diff --git a/lib/DefinePlugin.js b/lib/DefinePlugin.js index b9e728082e4..c7fb1d85c47 100644 --- a/lib/DefinePlugin.js +++ b/lib/DefinePlugin.js @@ -5,10 +5,16 @@ "use strict"; +const { + JAVASCRIPT_MODULE_TYPE_AUTO, + JAVASCRIPT_MODULE_TYPE_ESM, + JAVASCRIPT_MODULE_TYPE_DYNAMIC +} = require("./ModuleTypeConstants"); const RuntimeGlobals = require("./RuntimeGlobals"); const WebpackError = require("./WebpackError"); const ConstDependency = require("./dependencies/ConstDependency"); const BasicEvaluatedExpression = require("./javascript/BasicEvaluatedExpression"); + const { evaluateToString, toConstantDependency @@ -249,8 +255,12 @@ const toCacheVersion = code => { return code + ""; }; -const VALUE_DEP_PREFIX = "webpack/DefinePlugin "; -const VALUE_DEP_MAIN = "webpack/DefinePlugin_hash"; +const PLUGIN_NAME = "DefinePlugin"; +const VALUE_DEP_PREFIX = `webpack/${PLUGIN_NAME} `; +const VALUE_DEP_MAIN = `webpack/${PLUGIN_NAME}_hash`; +const TYPEOF_OPERATOR_REGEXP = /^typeof\s+/; +const WEBPACK_REQUIRE_FUNCTION_REGEXP = /__webpack_require__\s*(!?\.)/; +const WEBPACK_REQUIRE_IDENTIFIER_REGEXP = /__webpack_require__/; class DefinePlugin { /** @@ -278,7 +288,7 @@ class DefinePlugin { apply(compiler) { const definitions = this.definitions; compiler.hooks.compilation.tap( - "DefinePlugin", + PLUGIN_NAME, (compilation, { normalModuleFactory }) => { compilation.dependencyTemplates.set( ConstDependency, @@ -300,7 +310,7 @@ class DefinePlugin { */ const handler = parser => { const mainValue = compilation.valueCacheVersions.get(VALUE_DEP_MAIN); - parser.hooks.program.tap("DefinePlugin", () => { + parser.hooks.program.tap(PLUGIN_NAME, () => { const { buildInfo } = parser.state.module; if (!buildInfo.valueDependencies) buildInfo.valueDependencies = new Map(); @@ -356,7 +366,7 @@ class DefinePlugin { const splittedKey = key.split("."); splittedKey.slice(1).forEach((_, i) => { const fullKey = prefix + splittedKey.slice(0, i + 1).join("."); - parser.hooks.canRename.for(fullKey).tap("DefinePlugin", () => { + parser.hooks.canRename.for(fullKey).tap(PLUGIN_NAME, () => { addValueDependency(key); return true; }); @@ -371,18 +381,18 @@ class DefinePlugin { */ const applyDefine = (key, code) => { const originalKey = key; - const isTypeof = /^typeof\s+/.test(key); - if (isTypeof) key = key.replace(/^typeof\s+/, ""); + const isTypeof = TYPEOF_OPERATOR_REGEXP.test(key); + if (isTypeof) key = key.replace(TYPEOF_OPERATOR_REGEXP, ""); let recurse = false; let recurseTypeof = false; if (!isTypeof) { - parser.hooks.canRename.for(key).tap("DefinePlugin", () => { + parser.hooks.canRename.for(key).tap(PLUGIN_NAME, () => { addValueDependency(originalKey); return true; }); parser.hooks.evaluateIdentifier .for(key) - .tap("DefinePlugin", expr => { + .tap(PLUGIN_NAME, expr => { /** * this is needed in case there is a recursion in the DefinePlugin * to prevent an endless recursion @@ -408,7 +418,7 @@ class DefinePlugin { res.setRange(expr.range); return res; }); - parser.hooks.expression.for(key).tap("DefinePlugin", expr => { + parser.hooks.expression.for(key).tap(PLUGIN_NAME, expr => { addValueDependency(originalKey); const strCode = toCode( code, @@ -418,11 +428,11 @@ class DefinePlugin { runtimeTemplate, !parser.isAsiPosition(expr.range[0]) ); - if (/__webpack_require__\s*(!?\.)/.test(strCode)) { + if (WEBPACK_REQUIRE_FUNCTION_REGEXP.test(strCode)) { return toConstantDependency(parser, strCode, [ RuntimeGlobals.require ])(expr); - } else if (/__webpack_require__/.test(strCode)) { + } else if (WEBPACK_REQUIRE_IDENTIFIER_REGEXP.test(strCode)) { return toConstantDependency(parser, strCode, [ RuntimeGlobals.requireScope ])(expr); @@ -431,7 +441,7 @@ class DefinePlugin { } }); } - parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", expr => { + parser.hooks.evaluateTypeof.for(key).tap(PLUGIN_NAME, expr => { /** * this is needed in case there is a recursion in the DefinePlugin * to prevent an endless recursion @@ -459,7 +469,7 @@ class DefinePlugin { res.setRange(expr.range); return res; }); - parser.hooks.typeof.for(key).tap("DefinePlugin", expr => { + parser.hooks.typeof.for(key).tap(PLUGIN_NAME, expr => { addValueDependency(originalKey); const codeCode = toCode( code, @@ -488,26 +498,24 @@ class DefinePlugin { * @returns {void} */ const applyObjectDefine = (key, obj) => { - parser.hooks.canRename.for(key).tap("DefinePlugin", () => { + parser.hooks.canRename.for(key).tap(PLUGIN_NAME, () => { addValueDependency(key); return true; }); - parser.hooks.evaluateIdentifier - .for(key) - .tap("DefinePlugin", expr => { - addValueDependency(key); - return new BasicEvaluatedExpression() - .setTruthy() - .setSideEffects(false) - .setRange(expr.range); - }); + parser.hooks.evaluateIdentifier.for(key).tap(PLUGIN_NAME, expr => { + addValueDependency(key); + return new BasicEvaluatedExpression() + .setTruthy() + .setSideEffects(false) + .setRange(expr.range); + }); parser.hooks.evaluateTypeof .for(key) .tap( - "DefinePlugin", + PLUGIN_NAME, withValueDependency(key, evaluateToString("object")) ); - parser.hooks.expression.for(key).tap("DefinePlugin", expr => { + parser.hooks.expression.for(key).tap(PLUGIN_NAME, expr => { addValueDependency(key); const strCode = stringifyObj( obj, @@ -518,11 +526,11 @@ class DefinePlugin { !parser.isAsiPosition(expr.range[0]) ); - if (/__webpack_require__\s*(!?\.)/.test(strCode)) { + if (WEBPACK_REQUIRE_FUNCTION_REGEXP.test(strCode)) { return toConstantDependency(parser, strCode, [ RuntimeGlobals.require ])(expr); - } else if (/__webpack_require__/.test(strCode)) { + } else if (WEBPACK_REQUIRE_IDENTIFIER_REGEXP.test(strCode)) { return toConstantDependency(parser, strCode, [ RuntimeGlobals.requireScope ])(expr); @@ -533,7 +541,7 @@ class DefinePlugin { parser.hooks.typeof .for(key) .tap( - "DefinePlugin", + PLUGIN_NAME, withValueDependency( key, toConstantDependency(parser, JSON.stringify("object")) @@ -545,14 +553,14 @@ class DefinePlugin { }; normalModuleFactory.hooks.parser - .for("javascript/auto") - .tap("DefinePlugin", handler); + .for(JAVASCRIPT_MODULE_TYPE_AUTO) + .tap(PLUGIN_NAME, handler); normalModuleFactory.hooks.parser - .for("javascript/dynamic") - .tap("DefinePlugin", handler); + .for(JAVASCRIPT_MODULE_TYPE_DYNAMIC) + .tap(PLUGIN_NAME, handler); normalModuleFactory.hooks.parser - .for("javascript/esm") - .tap("DefinePlugin", handler); + .for(JAVASCRIPT_MODULE_TYPE_ESM) + .tap(PLUGIN_NAME, handler); /** * Walk definitions @@ -571,7 +579,7 @@ class DefinePlugin { compilation.valueCacheVersions.set(name, version); } else if (oldVersion !== version) { const warning = new WebpackError( - `DefinePlugin\nConflicting values for '${prefix + key}'` + `${PLUGIN_NAME}\nConflicting values for '${prefix + key}'` ); warning.details = `'${oldVersion}' !== '${version}'`; warning.hideStack = true; diff --git a/lib/ModuleTypeConstants.js b/lib/ModuleTypeConstants.js new file mode 100644 index 00000000000..9c77c9c0b48 --- /dev/null +++ b/lib/ModuleTypeConstants.js @@ -0,0 +1,32 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Sean Larkin @TheLarkInn +*/ + +"use strict"; + +/** + * @type {Readonly<"javascript/auto">} + */ +const JAVASCRIPT_MODULE_TYPE_AUTO = "javascript/auto"; +/** + * @type {Readonly<"javascript/dynamic">} + */ +const JAVASCRIPT_MODULE_TYPE_DYNAMIC = "javascript/dynamic"; +/** + * @type {Readonly<"javascript/esm">} + * This is the module type used for _strict_ ES Module syntax. This means that all legacy formats + * that webpack supports (CommonJS, AMD, SystemJS) are not supported. + */ +const JAVASCRIPT_MODULE_TYPE_ESM = "javascript/esm"; + +/** + * @type {Readonly<"json">} + * This is the module type used for JSON files. JSON files are always parsed as ES Module. + */ +const JSON_MODULE_TYPE = "json"; + +exports.JAVASCRIPT_MODULE_TYPE_AUTO = JAVASCRIPT_MODULE_TYPE_AUTO; +exports.JAVASCRIPT_MODULE_TYPE_DYNAMIC = JAVASCRIPT_MODULE_TYPE_DYNAMIC; +exports.JAVASCRIPT_MODULE_TYPE_ESM = JAVASCRIPT_MODULE_TYPE_ESM; +exports.JSON_MODULE_TYPE = JSON_MODULE_TYPE; diff --git a/lib/json/JsonModulesPlugin.js b/lib/json/JsonModulesPlugin.js index 3743eec8d61..fc82bb540cf 100644 --- a/lib/json/JsonModulesPlugin.js +++ b/lib/json/JsonModulesPlugin.js @@ -5,6 +5,7 @@ "use strict"; +const { JSON_MODULE_TYPE } = require("../ModuleTypeConstants"); const createSchemaValidation = require("../util/create-schema-validation"); const JsonGenerator = require("./JsonGenerator"); const JsonParser = require("./JsonParser"); @@ -20,26 +21,33 @@ const validate = createSchemaValidation( } ); +const PLUGIN_NAME = "JsonModulesPlugin"; + +/** + * The JsonModulesPlugin is the entrypoint plugin for the json modules feature. + * It adds the json module type to the compiler and registers the json parser and generator. + */ class JsonModulesPlugin { /** * Apply the plugin * @param {Compiler} compiler the compiler instance * @returns {void} + * */ apply(compiler) { compiler.hooks.compilation.tap( - "JsonModulesPlugin", + PLUGIN_NAME, (compilation, { normalModuleFactory }) => { normalModuleFactory.hooks.createParser - .for("json") - .tap("JsonModulesPlugin", parserOptions => { + .for(JSON_MODULE_TYPE) + .tap(PLUGIN_NAME, parserOptions => { validate(parserOptions); return new JsonParser(parserOptions); }); normalModuleFactory.hooks.createGenerator - .for("json") - .tap("JsonModulesPlugin", () => { + .for(JSON_MODULE_TYPE) + .tap(PLUGIN_NAME, () => { return new JsonGenerator(); }); }