diff --git a/src/loader.js b/src/loader.js index ae8da6e..d3d9f28 100644 --- a/src/loader.js +++ b/src/loader.js @@ -18,6 +18,9 @@ import loaderUtils from 'loader-utils'; import SingleEntryPlugin from 'webpack/lib/SingleEntryPlugin'; import WebWorkerTemplatePlugin from 'webpack/lib/webworker/WebWorkerTemplatePlugin'; import FetchCompileWasmTemplatePlugin from 'webpack/lib/web/FetchCompileWasmTemplatePlugin'; +import JsonpTemplatePlugin from 'webpack/lib/web/JsonpTemplatePlugin' +import SplitChunksPlugin from 'webpack/lib/optimize/SplitChunksPlugin' +import { ConcatSource } from 'webpack-sources' import WORKER_PLUGIN_SYMBOL from './symbol'; const NAME = 'WorkerPluginLoader'; @@ -41,7 +44,7 @@ export function pitch (request) { const chunkFilename = compilerOptions.output.chunkFilename.replace(/\.([a-z]+)$/i, '.worker.$1'); const workerOptions = { filename: chunkFilename.replace(/\[(?:chunkhash|contenthash)(:\d+(?::\d+)?)?\]/g, '[hash$1]'), - chunkFilename, + chunkFilename: compilerOptions.output.chunkFilename, globalObject: pluginOptions.globalObject || 'self' }; @@ -58,6 +61,13 @@ export function pitch (request) { const workerCompiler = this._compilation.createChildCompiler(NAME, workerOptions, plugins); workerCompiler.context = this._compiler.context; + + const splitChunks = compilerOptions.optimization && compilerOptions.optimization.splitChunks + if (splitChunks) { + (new SplitChunksPlugin(splitChunks)).apply(workerCompiler); + } + + (new JsonpTemplatePlugin()).apply(workerCompiler); (new WebWorkerTemplatePlugin(workerOptions)).apply(workerCompiler); (new FetchCompileWasmTemplatePlugin({ mangleImports: compilerOptions.optimization.mangleWasmImports @@ -70,13 +80,29 @@ export function pitch (request) { if (!compilation.cache[subCache]) compilation.cache[subCache] = {}; compilation.cache = compilation.cache[subCache]; } + + compilation.hooks.optimizeChunkAssets.tapAsync(NAME, (chunks, callback) => { + const allFiles = chunks.filter(chunk => chunk.name !== options.name).reduce((accumulated, chunk) => { + return accumulated.concat(chunk.files); + }, []); + const uniqueFiles = [...new Set(allFiles)]; + + if (uniqueFiles.length) { + // Sort to ensure the output is predictable. + uniqueFiles.sort(); + const file = chunks.find(c => c.name === options.name).files[0]; + compilation.assets[file] = new ConcatSource(`importScripts(${uniqueFiles.map(chunk => `${JSON.stringify(chunk)}`).join(', ')});\n\n`, compilation.assets[file]); + } + + callback(); + }) }); workerCompiler.runAsChild((err, entries, compilation) => { if (!err && compilation.errors && compilation.errors.length) { err = compilation.errors[0]; } - const entry = entries && entries[0] && entries[0].files[0]; + const entry = entries && entries[entries.length - 1] && entries[entries.length - 1].files[0]; if (!err && !entry) err = Error(`WorkerPlugin: no entry for ${request}`); if (err) return cb(err); return cb(null, `${options.esModule ? 'export default' : 'module.exports ='} __webpack_public_path__ + ${JSON.stringify(entry)}`);