From 1e761edcbfc8b214ae3a19f44f401f20ab07b718 Mon Sep 17 00:00:00 2001 From: Evilebot Tnawi Date: Tue, 28 Jul 2020 19:01:15 +0300 Subject: [PATCH] fix: respect `externals` (#264) --- src/index.js | 20 +++++++++++++++-- src/utils.js | 30 ++++++++++++++++++++++++-- test/__snapshots__/loader.test.js.snap | 13 +++++++++++ test/fixtures/external/entry.js | 22 +++++++++++++++++++ test/fixtures/external/index.html | 13 +++++++++++ test/fixtures/external/worker.js | 9 ++++++++ test/loader.test.js | 21 ++++++++++++++++++ 7 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/external/entry.js create mode 100644 test/fixtures/external/index.html create mode 100644 test/fixtures/external/worker.js diff --git a/src/index.js b/src/index.js index b2564a3..91f343a 100644 --- a/src/index.js +++ b/src/index.js @@ -4,11 +4,16 @@ import validateOptions from 'schema-utils'; import NodeTargetPlugin from 'webpack/lib/node/NodeTargetPlugin'; import SingleEntryPlugin from 'webpack/lib/SingleEntryPlugin'; import WebWorkerTemplatePlugin from 'webpack/lib/webworker/WebWorkerTemplatePlugin'; +import ExternalsPlugin from 'webpack/lib/ExternalsPlugin'; import schema from './options.json'; import supportWebpack5 from './supportWebpack5'; import supportWebpack4 from './supportWebpack4'; -import { getDefaultFilename, getDefaultChunkFilename } from './utils'; +import { + getDefaultFilename, + getDefaultChunkFilename, + getExternalsType, +} from './utils'; let FetchCompileWasmPlugin; let FetchCompileAsyncWasmPlugin; @@ -56,7 +61,11 @@ export function pitch(request) { ? options.chunkFilename : getDefaultChunkFilename(compilerOptions.output.chunkFilename); - worker.options = { filename, chunkFilename, globalObject: 'self' }; + worker.options = { + filename, + chunkFilename, + globalObject: 'self', + }; worker.compiler = this._compilation.createChildCompiler( 'worker', @@ -79,6 +88,13 @@ export function pitch(request) { new FetchCompileAsyncWasmPlugin().apply(worker.compiler); } + if (compilerOptions.externals) { + new ExternalsPlugin( + getExternalsType(compilerOptions), + compilerOptions.externals + ).apply(worker.compiler); + } + new SingleEntryPlugin(this.context, `!!${request}`, 'main').apply( worker.compiler ); diff --git a/src/utils.js b/src/utils.js index 372ff7b..f127257 100644 --- a/src/utils.js +++ b/src/utils.js @@ -10,6 +10,28 @@ function getDefaultChunkFilename(chunkFilename) { return chunkFilename.replace(/\.([a-z]+)(\?.+)?$/i, '.worker.$1$2'); } +function getExternalsType(compilerOptions) { + // For webpack@4 + if (compilerOptions.output.libraryTarget) { + return compilerOptions.output.libraryTarget; + } + + // For webpack@5 + if (compilerOptions.externalsType) { + return compilerOptions.externalsType; + } + + if (compilerOptions.output.library) { + return compilerOptions.output.library.type; + } + + if (compilerOptions.output.module) { + return 'module'; + } + + return 'var'; +} + function getWorker(file, content, options) { const publicPath = typeof options.publicPath === 'undefined' @@ -48,5 +70,9 @@ function getWorker(file, content, options) { })`; } -// eslint-disable-next-line import/prefer-default-export -export { getDefaultFilename, getDefaultChunkFilename, getWorker }; +export { + getDefaultFilename, + getDefaultChunkFilename, + getExternalsType, + getWorker, +}; diff --git a/test/__snapshots__/loader.test.js.snap b/test/__snapshots__/loader.test.js.snap index e7924bb..333bbe0 100644 --- a/test/__snapshots__/loader.test.js.snap +++ b/test/__snapshots__/loader.test.js.snap @@ -1,5 +1,18 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`worker-loader should work with "externals": errors 1`] = `Array []`; + +exports[`worker-loader should work with "externals": module 1`] = ` +"export default function() { + return new Worker(__webpack_public_path__ + \\"test.worker.js\\"); +}; +" +`; + +exports[`worker-loader should work with "externals": result 1`] = `"{\\"postMessage\\":true,\\"onmessage\\":true}"`; + +exports[`worker-loader should work with "externals": warnings 1`] = `Array []`; + exports[`worker-loader should work with WASM: errors 1`] = `Array []`; exports[`worker-loader should work with WASM: module 1`] = ` diff --git a/test/fixtures/external/entry.js b/test/fixtures/external/entry.js new file mode 100644 index 0000000..8ac6a89 --- /dev/null +++ b/test/fixtures/external/entry.js @@ -0,0 +1,22 @@ +import Worker from './worker.js'; + +const worker = new Worker(); + +let result; + +worker.onmessage = function (event) { + if (!result) { + result = document.createElement("div"); + result.setAttribute('id', 'result'); + + document.body.append(result); + } + + result.innerText = JSON.stringify(event.data) +}; + +const button = document.getElementById('button'); + +button.addEventListener('click', () => { + worker.postMessage({ postMessage: true }) +}); diff --git a/test/fixtures/external/index.html b/test/fixtures/external/index.html new file mode 100644 index 0000000..786cafc --- /dev/null +++ b/test/fixtures/external/index.html @@ -0,0 +1,13 @@ + + + + + Webpack App + + + + + + + + diff --git a/test/fixtures/external/worker.js b/test/fixtures/external/worker.js new file mode 100644 index 0000000..d6b64ff --- /dev/null +++ b/test/fixtures/external/worker.js @@ -0,0 +1,9 @@ +import foo from 'my-custom-module'; + +onmessage = function(event) { + const workerResult = event.data; + + workerResult.onmessage = true; + + postMessage(workerResult); +}; diff --git a/test/loader.test.js b/test/loader.test.js index 76c055d..1db7417 100644 --- a/test/loader.test.js +++ b/test/loader.test.js @@ -59,4 +59,25 @@ describe('worker-loader', () => { expect(getWarnings(stats)).toMatchSnapshot('warnings'); expect(getErrors(stats)).toMatchSnapshot('errors'); }); + + it('should work with "externals"', async () => { + const compiler = getCompiler( + './external/entry.js', + {}, + { + externals: { + 'my-custom-module': 'navigator', + }, + } + ); + const stats = await compile(compiler); + const result = await getResultFromBrowser(stats); + + expect(getModuleSource('./external/worker.js', stats)).toMatchSnapshot( + 'module' + ); + expect(result).toMatchSnapshot('result'); + expect(getWarnings(stats)).toMatchSnapshot('warnings'); + expect(getErrors(stats)).toMatchSnapshot('errors'); + }); });