Skip to content

Commit

Permalink
Merge pull request #16896 from webpack/thelarkinn/module-type-constants
Browse files Browse the repository at this point in the history
refactor(moduletypes): introduce module type constants for plugins
  • Loading branch information
TheLarkInn committed Mar 31, 2023
2 parents 46a3e3d + 4bcc0f0 commit 6364822
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 41 deletions.
80 changes: 44 additions & 36 deletions lib/DefinePlugin.js
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
/**
Expand Down Expand Up @@ -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,
Expand All @@ -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();
Expand Down Expand Up @@ -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;
});
Expand All @@ -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
Expand All @@ -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,
Expand All @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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);
Expand All @@ -533,7 +541,7 @@ class DefinePlugin {
parser.hooks.typeof
.for(key)
.tap(
"DefinePlugin",
PLUGIN_NAME,
withValueDependency(
key,
toConstantDependency(parser, JSON.stringify("object"))
Expand All @@ -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
Expand All @@ -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;
Expand Down
32 changes: 32 additions & 0 deletions 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;
18 changes: 13 additions & 5 deletions lib/json/JsonModulesPlugin.js
Expand Up @@ -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");
Expand All @@ -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();
});
}
Expand Down

0 comments on commit 6364822

Please sign in to comment.