UNPKG

webpack

Version:

Packs ECMAScript/CommonJs/AMD modules for the browser. Allows you to split your codebase into multiple bundles, which can be loaded on demand. Supports loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.

323 lines (300 loc) 9.55 kB
/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ "use strict"; const { getExternalModuleNodeCommonjsInitFragment } = require("./ExternalModule"); const { JAVASCRIPT_MODULE_TYPE_AUTO, JAVASCRIPT_MODULE_TYPE_DYNAMIC, JAVASCRIPT_MODULE_TYPE_ESM } = require("./ModuleTypeConstants"); const RuntimeGlobals = require("./RuntimeGlobals"); const WebpackError = require("./WebpackError"); const ConstDependency = require("./dependencies/ConstDependency"); const BasicEvaluatedExpression = require("./javascript/BasicEvaluatedExpression"); const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin"); const { evaluateToString, toConstantDependency } = require("./javascript/JavascriptParserHelpers"); const ChunkNameRuntimeModule = require("./runtime/ChunkNameRuntimeModule"); const GetFullHashRuntimeModule = require("./runtime/GetFullHashRuntimeModule"); /** @typedef {import("./Compiler")} Compiler */ /** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */ /** @typedef {import("./Module").BuildInfo} BuildInfo */ /** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */ /** @typedef {import("./javascript/JavascriptParser").Range} Range */ /** * @returns {Record<string, {expr: string, req: string[] | null, type?: string, assign: boolean}>} replacements */ function getReplacements() { return { __webpack_require__: { expr: RuntimeGlobals.require, req: [RuntimeGlobals.require], type: "function", assign: false }, __webpack_global__: { expr: RuntimeGlobals.require, req: [RuntimeGlobals.require], type: "function", assign: false }, __webpack_public_path__: { expr: RuntimeGlobals.publicPath, req: [RuntimeGlobals.publicPath], type: "string", assign: true }, __webpack_base_uri__: { expr: RuntimeGlobals.baseURI, req: [RuntimeGlobals.baseURI], type: "string", assign: true }, __webpack_modules__: { expr: RuntimeGlobals.moduleFactories, req: [RuntimeGlobals.moduleFactories], type: "object", assign: false }, __webpack_chunk_load__: { expr: RuntimeGlobals.ensureChunk, req: [RuntimeGlobals.ensureChunk], type: "function", assign: true }, __non_webpack_require__: { expr: "require", req: null, type: undefined, // type is not known, depends on environment assign: true }, __webpack_nonce__: { expr: RuntimeGlobals.scriptNonce, req: [RuntimeGlobals.scriptNonce], type: "string", assign: true }, __webpack_hash__: { expr: `${RuntimeGlobals.getFullHash}()`, req: [RuntimeGlobals.getFullHash], type: "string", assign: false }, __webpack_chunkname__: { expr: RuntimeGlobals.chunkName, req: [RuntimeGlobals.chunkName], type: "string", assign: false }, __webpack_get_script_filename__: { expr: RuntimeGlobals.getChunkScriptFilename, req: [RuntimeGlobals.getChunkScriptFilename], type: "function", assign: true }, __webpack_runtime_id__: { expr: RuntimeGlobals.runtimeId, req: [RuntimeGlobals.runtimeId], assign: false }, "require.onError": { expr: RuntimeGlobals.uncaughtErrorHandler, req: [RuntimeGlobals.uncaughtErrorHandler], type: undefined, // type is not known, could be function or undefined assign: true // is never a pattern }, __system_context__: { expr: RuntimeGlobals.systemContext, req: [RuntimeGlobals.systemContext], type: "object", assign: false }, __webpack_share_scopes__: { expr: RuntimeGlobals.shareScopeMap, req: [RuntimeGlobals.shareScopeMap], type: "object", assign: false }, __webpack_init_sharing__: { expr: RuntimeGlobals.initializeSharing, req: [RuntimeGlobals.initializeSharing], type: "function", assign: true } }; } const PLUGIN_NAME = "APIPlugin"; class APIPlugin { /** * Apply the plugin * @param {Compiler} compiler the compiler instance * @returns {void} */ apply(compiler) { compiler.hooks.compilation.tap( PLUGIN_NAME, (compilation, { normalModuleFactory }) => { const moduleOutput = compilation.options.output.module; const nodeTarget = compiler.platform.node; const nodeEsm = moduleOutput && nodeTarget; const REPLACEMENTS = getReplacements(); if (nodeEsm) { REPLACEMENTS.__non_webpack_require__.expr = "__WEBPACK_EXTERNAL_createRequire_require"; } compilation.dependencyTemplates.set( ConstDependency, new ConstDependency.Template() ); compilation.hooks.runtimeRequirementInTree .for(RuntimeGlobals.chunkName) .tap(PLUGIN_NAME, (chunk) => { compilation.addRuntimeModule( chunk, new ChunkNameRuntimeModule(/** @type {string} */ (chunk.name)) ); return true; }); compilation.hooks.runtimeRequirementInTree .for(RuntimeGlobals.getFullHash) .tap(PLUGIN_NAME, (chunk, _set) => { compilation.addRuntimeModule(chunk, new GetFullHashRuntimeModule()); return true; }); const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation); hooks.renderModuleContent.tap( PLUGIN_NAME, (source, module, renderContext) => { if (/** @type {BuildInfo} */ (module.buildInfo).needCreateRequire) { const chunkInitFragments = [ getExternalModuleNodeCommonjsInitFragment( renderContext.runtimeTemplate ) ]; renderContext.chunkInitFragments.push(...chunkInitFragments); } return source; } ); /** * @param {JavascriptParser} parser the parser */ const handler = (parser) => { for (const key of Object.keys(REPLACEMENTS)) { const info = REPLACEMENTS[key]; parser.hooks.expression.for(key).tap(PLUGIN_NAME, (expression) => { const dep = toConstantDependency(parser, info.expr, info.req); if (key === "__non_webpack_require__" && moduleOutput) { if (nodeTarget) { /** @type {BuildInfo} */ (parser.state.module.buildInfo).needCreateRequire = true; } else { const warning = new WebpackError( `${PLUGIN_NAME}\n__non_webpack_require__ is only allowed in target node` ); warning.loc = /** @type {DependencyLocation} */ ( expression.loc ); warning.module = parser.state.module; compilation.warnings.push(warning); } } return dep(expression); }); if (info.assign === false) { parser.hooks.assign.for(key).tap(PLUGIN_NAME, (expr) => { const err = new WebpackError(`${key} must not be assigned`); err.loc = /** @type {DependencyLocation} */ (expr.loc); throw err; }); } if (info.type) { parser.hooks.evaluateTypeof .for(key) .tap(PLUGIN_NAME, evaluateToString(info.type)); } } parser.hooks.expression .for("__webpack_layer__") .tap(PLUGIN_NAME, (expr) => { const dep = new ConstDependency( JSON.stringify(parser.state.module.layer), /** @type {Range} */ (expr.range) ); dep.loc = /** @type {DependencyLocation} */ (expr.loc); parser.state.module.addPresentationalDependency(dep); return true; }); parser.hooks.evaluateIdentifier .for("__webpack_layer__") .tap(PLUGIN_NAME, (expr) => (parser.state.module.layer === null ? new BasicEvaluatedExpression().setNull() : new BasicEvaluatedExpression().setString( parser.state.module.layer ) ).setRange(/** @type {Range} */ (expr.range)) ); parser.hooks.evaluateTypeof .for("__webpack_layer__") .tap(PLUGIN_NAME, (expr) => new BasicEvaluatedExpression() .setString( parser.state.module.layer === null ? "object" : "string" ) .setRange(/** @type {Range} */ (expr.range)) ); parser.hooks.expression .for("__webpack_module__.id") .tap(PLUGIN_NAME, (expr) => { /** @type {BuildInfo} */ (parser.state.module.buildInfo).moduleConcatenationBailout = "__webpack_module__.id"; const dep = new ConstDependency( `${parser.state.module.moduleArgument}.id`, /** @type {Range} */ (expr.range), [RuntimeGlobals.moduleId] ); dep.loc = /** @type {DependencyLocation} */ (expr.loc); parser.state.module.addPresentationalDependency(dep); return true; }); parser.hooks.expression .for("__webpack_module__") .tap(PLUGIN_NAME, (expr) => { /** @type {BuildInfo} */ (parser.state.module.buildInfo).moduleConcatenationBailout = "__webpack_module__"; const dep = new ConstDependency( parser.state.module.moduleArgument, /** @type {Range} */ (expr.range), [RuntimeGlobals.module] ); dep.loc = /** @type {DependencyLocation} */ (expr.loc); parser.state.module.addPresentationalDependency(dep); return true; }); parser.hooks.evaluateTypeof .for("__webpack_module__") .tap(PLUGIN_NAME, evaluateToString("object")); }; normalModuleFactory.hooks.parser .for(JAVASCRIPT_MODULE_TYPE_AUTO) .tap(PLUGIN_NAME, handler); normalModuleFactory.hooks.parser .for(JAVASCRIPT_MODULE_TYPE_DYNAMIC) .tap(PLUGIN_NAME, handler); normalModuleFactory.hooks.parser .for(JAVASCRIPT_MODULE_TYPE_ESM) .tap(PLUGIN_NAME, handler); } ); } } module.exports = APIPlugin;