UNPKG

workerize-loader-wp5

Version:

Automatically move a module into a Web Worker (Webpack loader)

174 lines (136 loc) 7.57 kB
var path = require('path'); var loaderUtils = require('loader-utils'); var NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin'); var SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin'); var WebWorkerTemplatePlugin = require('webpack/lib/webworker/WebWorkerTemplatePlugin'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var path__default = /*#__PURE__*/_interopDefaultLegacy(path); var loaderUtils__default = /*#__PURE__*/_interopDefaultLegacy(loaderUtils); var NodeTargetPlugin__default = /*#__PURE__*/_interopDefaultLegacy(NodeTargetPlugin); var SingleEntryPlugin__default = /*#__PURE__*/_interopDefaultLegacy(SingleEntryPlugin); var WebWorkerTemplatePlugin__default = /*#__PURE__*/_interopDefaultLegacy(WebWorkerTemplatePlugin); function loader() {} var CACHE = {}; var tapName = "workerize-loader-wp5"; var compilationHook = function compilationHook(compiler, handler) { if (compiler.hooks) { return compiler.hooks.compilation.tap(tapName, handler); } return compiler.plugin("compilation", handler); }; var parseHook = function parseHook(data, handler) { if (data.normalModuleFactory.hooks) { return data.normalModuleFactory.hooks.parser.for("javascript/auto").tap(tapName, handler); } return data.normalModuleFactory.plugin("parser", handler); }; var exportDeclarationHook = function exportDeclarationHook(parser, handler) { if (parser.hooks) { return parser.hooks.exportDeclaration.tap(tapName, handler); } return parser.plugin("export declaration", handler); }; loader.pitch = function (request) { var _this = this; this.cacheable(false); var options = loaderUtils__default['default'].getOptions(this) || {}; var cb = this.async(); var compilerOptions = this._compiler.options || {}; var filename = (options.name || "[fullhash]") + ".worker.js"; var worker = {}; worker.options = { filename: filename, chunkFilename: filename, publicPath: options.publicPath || compilerOptions.output.publicPath, globalObject: "self" }; if (compilerOptions.output && compilerOptions.output.globalObject === "window") { console.warn('Warning (workerize-loader-wp5): output.globalObject is set to "window". It should be set to "self" or "this" to support HMR in Workers.'); } worker.compiler = this._compilation.createChildCompiler("worker " + request, worker.options); new WebWorkerTemplatePlugin__default['default'](worker.options).apply(worker.compiler); if (this.target !== "webworker" && this.target !== "web") { new NodeTargetPlugin__default['default']().apply(worker.compiler); } // webpack >= v4 supports webassembly var wasmPluginPath = null; try { wasmPluginPath = require.resolve("webpack/lib/web/FetchCompileWasmTemplatePlugin"); } catch (_err) {// webpack <= v3, skipping } if (wasmPluginPath) { var FetchCompileWasmTemplatePlugin = require(wasmPluginPath); new FetchCompileWasmTemplatePlugin({ mangleImports: this._compiler.options.optimization.mangleWasmImports }).apply(worker.compiler); } var bundleName = path__default['default'].parse(this.resourcePath).name; new SingleEntryPlugin__default['default'](this.context, "!!" + path__default['default'].resolve(__dirname, "rpc-worker-loader.js") + "!" + request, bundleName).apply(worker.compiler); compilationHook(worker.compiler, function (_, data) { parseHook(data, function (parser) { exportDeclarationHook(parser, function (expr) { var decl = expr.declaration || expr; var _parser$state = parser.state, compilation = _parser$state.compilation, current = _parser$state.current; var entryModule = compilation.entries instanceof Map ? compilation.moduleGraph.getModule(compilation.entries.get(bundleName).dependencies[0]) : compilation.entries[0]; // only process entry exports if (current.resource !== entryModule.resource) return; var key = current.nameForCondition(); var exports = CACHE[key] || (CACHE[key] = {}); if (decl.id) { exports[decl.id.name] = true; } else if (decl.declarations) { for (var i = 0; i < decl.declarations.length; i++) { exports[decl.declarations[i].id.name] = true; } } else { console.warn("[workerize] unknown export declaration: ", expr); } // This is for Webpack 5: mark the exports as used so it does not get tree-shaken away on production build if (compilation.moduleGraph) { var _require = require("webpack/lib/util/runtime"), getEntryRuntime = _require.getEntryRuntime; var _require2 = require("webpack"), UsageState = _require2.UsageState; var runtime = getEntryRuntime(compilation, bundleName); for (var _i = 0, _Object$keys = Object.keys(exports); _i < _Object$keys.length; _i++) { var exportName = _Object$keys[_i]; var exportInfo = compilation.moduleGraph.getExportInfo(entryModule, exportName); exportInfo.setUsed(UsageState.Used, runtime); exportInfo.canMangleUse = false; exportInfo.canMangleProvide = false; } compilation.moduleGraph.addExtraReason(entryModule, "used by workerize-loader-wp5"); } }); }); }); worker.compiler.runAsChild(function (err, entries, compilation) { if (err) return cb(err); if (entries[0]) { worker.file = Array.from(entries[0].files)[0]; var entryModules = compilation.chunkGraph && compilation.chunkGraph.getChunkEntryModulesIterable ? Array.from(compilation.chunkGraph.getChunkEntryModulesIterable(entries[0])) : null; var entryModule = entryModules && entryModules.length > 0 ? entryModules[0] : entries[0].entryModule; var key = entryModule.nameForCondition(); var contents = compilation.assets[worker.file].source(); var exports = Object.keys(CACHE[key] || {}); // console.log('Workerized exports: ', exports.join(', ')); if (options.inline) { worker.url = "URL.createObjectURL(new Blob([" + JSON.stringify(contents) + "]))"; } else if (options.publicPath) { worker.url = "" + JSON.stringify(options.publicPath + worker.file); } else { worker.url = "__webpack_public_path__ + " + JSON.stringify(worker.file); } if (options.fallback === false) { delete _this._compilation.assets[worker.file]; } var workerUrl = worker.url; if (options.import) { workerUrl = "\"data:,importScripts('\"+location.origin+" + workerUrl + "+\"')\""; } // workerUrl will be URL.revokeObjectURL() to avoid memory leaks on browsers // https://github.com/webpack-contrib/worker-loader/issues/208 return cb(null, "\n\t\t\t\tvar addMethods = require(" + loaderUtils__default['default'].stringifyRequest(_this, path__default['default'].resolve(__dirname, "rpc-wrapper.js")) + ")\n\t\t\t\tvar methods = " + JSON.stringify(exports) + "\n\t\t\t\tmodule.exports = function() {\n\t\t\t\t\tvar w = new Worker(" + workerUrl + ", { name: " + JSON.stringify(filename) + " })\n\t\t\t\t\tURL.revokeObjectURL(" + workerUrl + ");\n\t\t\t\t\taddMethods(w, methods)\n\t\t\t\t\t" + (options.ready ? 'w.ready = new Promise(function(r) { w.addEventListener("ready", function(){ r(w) }) })' : "") + "\n\t\t\t\t\treturn w\n\t\t\t\t}\n\t\t\t"); } return cb(null, null); }); }; module.exports = loader; //# sourceMappingURL=index.js.map