web-dev-qa-db-ja.com

共有Webワーカーにユーザースクリプトをロードするにはどうすればよいですか?

共有ワーカーにユーザースクリプトをロードしたい。問題は、ユーザースクリプトが無料であり、ファイルをホストするためのビジネスモデルがないことです。また、1つの小さなファイルをホストするために、無料のサーバーであってもサーバーを使用したくありません。とにかく、 私はそれを試しました そして私は(もちろん)同じOriginポリシーエラーを受け取ります:

Uncaught SecurityError: Failed to construct 'SharedWorker': Script at
'https://cdn.rawgit.com/viziionary/Nacho-Bot/master/webworker.js'
cannot be accessed from Origin 'http://stackoverflow.com'.

別の方法があります ワーカー関数を文字列に変換してからBlobに変換し、それをワーカーとしてロードすることでWebワーカーをロードしますが、私もそれを試しました:

var sharedWorkers = {};
var startSharedWorker = function(workerFunc){
    var funcString = workerFunc.toString();
    var index = funcString.indexOf('{');
    var funcStringClean = funcString.substring(index + 1, funcString.length - 1);
    var blob = new Blob([funcStringClean], { type: "text/javascript" });
    sharedWorkers.google = new SharedWorker(window.URL.createObjectURL(blob));
    sharedWorkers.google.port.start();
};

そして、それも機能しません。どうして?共有ワーカーは、ワーカーファイルのロード元の場所に基づいて共有されるためです。 createObjectURLは使用ごとに一意のファイル名を生成する であるため、ワーカーが同じURLを持つことはなく、したがって共有されることもありません。

どうすればこの問題を解決できますか?


注:特定の解決策について質問しようとしましたが、現時点で私ができる最善のことは、より広い方法で問題の任意のソリューション。同一生成元ポリシーまたは方法のために、試行したすべてのソリューションは基本的に不可能に見えるためですURL.createObjectURL動作します( 仕様から 、結果のファイルURLを変更することは不可能のようです)。

そうは言っても、私の質問が何らかの形で改善または明確化できる場合は、コメントを残してください。

32
user5536767

fetch()response.blob()を使用して、返されたBlobからタイプ_Blob URL_の_application/javascript_を作成できます。 SharedWorker()パラメータをURL.createObjectURL()によって作成された_Blob URL_に設定します。新しく開いたloadwindow.open()windowイベントを利用して、元のSharedWorkerで以前に定義した同じwindowを定義し、新しく開いたmessagesで元のSharedWorkerwindowイベントを添付します。

javascriptconsoleat iFrameの内容を別のiFrameからクリアする方法 で試行されました。ここで、現在の質問URLは新しいtabmessagewindowを開いてからworker.port.postMessage()イベントハンドラーまでロードする必要があります。 consoleに記録されています。

windowを開くと、同様にmessageを開くときに、worker.postMessage(/* message */)を使用して新しく開いたwindowから投稿されたときに、windowイベントもログに記録する必要があります

_window.worker = void 0, window.so = void 0;

fetch("https://cdn.rawgit.com/viziionary/Nacho-Bot/master/webworker.js")
  .then(response => response.blob())
  .then(script => {
    console.log(script);
    var url = URL.createObjectURL(script);
    window.worker = new SharedWorker(url);
    console.log(worker);
    worker.port.addEventListener("message", (e) => console.log(e.data));
    worker.port.start();

    window.so = window.open("https://stackoverflow.com/questions/" 
                            + "38810002/" 
                            + "how-can-i-load-a-shared-web-worker-" 
                            + "with-a-user-script", "_blank");

    so.addEventListener("load", () => {
      so.worker = worker;
      so.console.log(so.worker);
      so.worker.port.addEventListener("message", (e) => so.console.log(e.data));
      so.worker.port.start();
      so.worker.port.postMessage("hi from " + so.location.href);
    });

    so.addEventListener("load", () => {
      worker.port.postMessage("hello from " + location.href)
    })

  });
_

consoleのいずれかのtabで、次のように使用できます。 at 別のiFrameからiFrameのコンテンツをクリアする方法worker.postMessage("hello, again") at new window of current URL 共有Webワーカーにユーザースクリプトをロードするにはどうすればよいですか?worker.port.postMessage("hi, again");ここで、各messagewindowイベントが付加され、2つのwindow間の通信は、初期URLで作成された元のSharedWorkerを使用して実現できます。

9
guest271314

前提条件

  • あなたが調査し、コメントで言及されているように、SharedWorkerのURLは同一生成元ポリシーの対象となります。
  • この質問 によると、WorkerのURLに対するCORSサポートはありません。
  • によると、この問題GM_workerのサポートはWONT_FIXになり、は不可能に近いようですFirefoxの変更により実装する。サンドボックス化されたWorkerunsafeWindow.Workerではなく)も機能しないという注意事項もあります。

設計

達成したいと思うのは、統計を収集したり、どこにでも表示されるグローバルUIを作成したりする@include *ユーザースクリプトです。したがって、実行時にいくつかの状態または統計の集計を維持するワーカーが必要です(ユーザースクリプトのすべてのインスタンスから簡単にアクセスできます)、および/または計算量の多いルーチンを実行する必要があります(そうでない場合はそうなるため)ターゲットサイトの速度が低下します)。

あらゆる解決策の方法で

私が提案したい解決策は、SharedWorkerデザインを別のものに置き換えることです。

  • 共有ワーカーの状態を維持したいだけの場合は、Greasemonkeyストレージ( GM_setValue とその仲間)を使用してください。すべてのuserscriptインスタンス間で共有されます(シーンの背後にあるSQLite)。
  • 計算量の多いタスクを実行したい場合は、unsafeWindow.Workerに入れて、結果をGreasemonkeyストレージに戻します。
  • バックグラウンド計算を実行する必要があり、単一インスタンスでのみ実行する必要がある場合は、「ウィンドウ間」同期ライブラリが多数あります(ほとんどの場合、localStorageを使用しますが、GreasemomkeyのAPIは同じであるため、使用しないでください。それにアダプタを書くのは難しいです)。したがって、1つのuserscriptインスタンスでロックを取得し、そのインスタンスでルーチンを実行できます。同様に、 [〜#〜] iwc [〜#〜] または ByTheWayここで使用される可能性が高い Stack Exchangeで; それについて投稿する )。

他の方法

よくわかりませんが、ServiceWorkerを希望どおりに機能させるためにSharedWorkerから作成された巧妙な応答のなりすましがある可能性があります。出発点は この回答の編集 にあります。

4
saaj

私はあなたが別の答えを望んでいると確信していますが、悲しいことにこれが要約されます。

ブラウザーはsame-Origin-policiesを実装してインターネットユーザーを保護します。意図は明確ですが、sharedWorkerのオリジンを変更できる正規のブラウザーはありません。

sharedWorker内のすべてのブラウジングコンテキストは、まったく同じオリジンを共有する必要があります

  • ホスト
  • プロトコル
  • ポート

この問題をハックすることはできません。メソッドに加えてiframeを使用しようとしましたが、機能しません。

たぶん、それをあなたのjavascriptファイルをgithubに置き、彼らのraw.サービスを使ってファイルを取得することができます。こうすれば、それほど労力をかけずに実行することができます。

更新

私はchromeアップデートを読んでいて、あなたがこれについて尋ねたことを思い出しました。クロスオリジンサービスワーカーがクロームに到着しました!

これを行うには、SWのインストールイベントに以下を追加します。

self.addEventListener('install', event => {
  event.registerForeignFetch({
    scopes: [self.registration.scope], // or some sub-scope
    origins: ['*'] // or ['https://example.com']
  });
});

他にもいくつかの考慮事項が必要です。チェックしてください。

フルリンク: https://developers.google.com/web/updates/2016/09/foreign-fetch?hl=en?utm_campaign=devshow_series_crossoriginserviceworkers_092316&utm_source=gdev&utm_medium=yt-desc

2
Bamieh