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);
+ })
+ );
});