diff --git a/.gitignore b/.gitignore index da9157e..c92e42e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules test/expected +.idea diff --git a/README.md b/README.md index b7f5258..7446b8b 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ worker.addEventListener("message", function (event) {}) |**`name`**|`{String}`|`[hash].worker.js`|Set a custom name for the output script| |**`inline`**|`{Boolean}`|`false`|Inline the worker as a BLOB| |**`fallback`**|`{Boolean}`|`false`|Require a fallback for non-worker supporting environments| +|**`publicPath`**|`{String}`|`null`|Override the path from which worker scripts are downloaded| ### `name` @@ -130,6 +131,18 @@ self.postMessage({ foo: 'foo' }) self.addEventListener('message', (event) => console.log(event)) ``` +### `publicPath` + +Overrides the path from which worker scripts are downloaded. If not specified, the same public path used for other +webpack assets is used. + +```js +{ + loader: 'worker-loader' + options: { publicPath: '/scripts/workers/' } +} +``` + ### `Integrating with ES2015 Modules` > ℹ️ You can even use ES2015 Modules if you have the [`babel-loader`](https://github.com/babel/babel-loader) configured. @@ -187,6 +200,27 @@ worker.onmessage = (event) => {}; worker.addEventListener("message", (event) => {}); ``` +### Cross-origin policy workarounds + +Web Workers are restricted by a same-origin policy, so if your webpack assets are not being served from the same origin +as your application, their download may be blocked by your browser. This scenario can commonly occur if you are hosting +your assets under a CDN domain. Even downloads from the webpack dev server could be blocked. + +There are two workarounds. Firstly, you can inline the worker as a blob instead of downloading it as an external +script via the [`inline`](#inline) parameter: + +``` javascript +var MyWorker = require("worker?inline!./file.js"); +``` + +Secondly, you may override the base download URL for your worker script via the [`publicPath`](#publicpath) option. + +```javascript +// This will cause the worker to be downloaded from `/workers/file.js` +var MyWorker = require("worker?publicPath=%2Fworkers%2F!./file.js"); +``` + +

Maintainers

diff --git a/index.js b/index.js index 348a380..21be6fe 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,8 @@ const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin'); const schema = require('./options.json'); const getWorker = (file, content, options) => { - const workerPublicPath = `__webpack_public_path__ + ${JSON.stringify(file)}`; + const publicPath = options.publicPath ? JSON.stringify(options.publicPath) : '__webpack_public_path__'; + const workerPublicPath = `${publicPath} + ${JSON.stringify(file)}`; if (options.inline) { const createInlineWorkerPath = JSON.stringify(`!!${path.join(__dirname, 'createInlineWorker.js')}`); const fallbackWorkerPath = options.fallback === false ? 'null' : workerPublicPath; diff --git a/options.json b/options.json index 3cf5292..27e5ea4 100644 --- a/options.json +++ b/options.json @@ -9,6 +9,9 @@ }, "fallback": { "type": "boolean" + }, + "publicPath": { + "type": "string" } }, "additionalProperties": false diff --git a/test/fixtures/public-path-override/entry.js b/test/fixtures/public-path-override/entry.js new file mode 100644 index 0000000..1c070c7 --- /dev/null +++ b/test/fixtures/public-path-override/entry.js @@ -0,0 +1 @@ +const Worker = require('./worker.js'); diff --git a/test/fixtures/public-path-override/worker.js b/test/fixtures/public-path-override/worker.js new file mode 100644 index 0000000..e6de814 --- /dev/null +++ b/test/fixtures/public-path-override/worker.js @@ -0,0 +1 @@ +// named worker test mark diff --git a/test/index.js b/test/index.js index f6c494e..9b09b02 100644 --- a/test/index.js +++ b/test/index.js @@ -226,4 +226,26 @@ describe('worker-loader', () => { }) ); }); + + it('should use the publicPath option as the base URL if specified', () => + makeBundle('public-path-override', { + module: { + rules: [ + { + test: /worker\.js$/, + loader: '../index.js', + options: { + publicPath: '/some/proxy/', + }, + }, + ], + }, + }).then((stats) => { + const assets = stats.compilation.assets; + const bundle = assets['bundle.js']; + const workerFile = Object.keys(assets).find(name => /worker\.js$/.test(name)); + + assert.notEqual(bundle._cachedSource.indexOf(`new Worker("/some/proxy/" + "${workerFile}")`), -1); + }) + ); });