diff --git a/lib/dependencies/CommonJsImportsParserPlugin.js b/lib/dependencies/CommonJsImportsParserPlugin.js index 67d495cea..2c62d3f99 100644 --- a/lib/dependencies/CommonJsImportsParserPlugin.js +++ b/lib/dependencies/CommonJsImportsParserPlugin.js @@ -126,15 +126,6 @@ class CommonJsImportsParserPlugin { }); // #region Unsupported - parser.hooks.expression - .for("require.main") - .tap( - PLUGIN_NAME, - expressionIsUnsupported( - parser, - "require.main is not supported by webpack." - ) - ); parser.hooks.call .for("require.main.require") .tap( diff --git a/lib/dependencies/ImportMetaPlugin.js b/lib/dependencies/ImportMetaPlugin.js index 863ed2ec7..da8fe3e01 100644 --- a/lib/dependencies/ImportMetaPlugin.js +++ b/lib/dependencies/ImportMetaPlugin.js @@ -13,6 +13,7 @@ const { JAVASCRIPT_MODULE_TYPE_AUTO, JAVASCRIPT_MODULE_TYPE_ESM } = require("../ModuleTypeConstants"); +const RuntimeGlobals = require("../RuntimeGlobals"); const Template = require("../Template"); const BasicEvaluatedExpression = require("../javascript/BasicEvaluatedExpression"); const { @@ -34,6 +35,7 @@ const ConstDependency = require("./ConstDependency"); /** @typedef {import("../javascript/JavascriptParser").Range} Range */ /** @typedef {import("../javascript/JavascriptParser").Members} Members */ /** @typedef {import("../javascript/JavascriptParser").DestructuringAssignmentProperty} DestructuringAssignmentProperty */ +/** @typedef {import("./ConstDependency").RawRuntimeRequirements} RawRuntimeRequirements */ const getCriticalDependencyWarning = memoize(() => require("./CriticalDependencyWarning") @@ -168,6 +170,9 @@ class ImportMetaPlugin { return true; } + /** @type {RawRuntimeRequirements} */ + const runtimeRequirements = []; + let str = ""; for (const prop of referencedPropertiesInDestructuring) { const value = hooks.propertyInDestructuring.call(prop); @@ -184,6 +189,14 @@ class ImportMetaPlugin { case "webpack": str += `webpack: ${importMetaWebpackVersion()},`; break; + case "main": + str += `main: ${RuntimeGlobals.moduleCache}[${RuntimeGlobals.entryModuleId}] === ${RuntimeGlobals.module},`; + runtimeRequirements.push( + RuntimeGlobals.moduleCache, + RuntimeGlobals.entryModuleId, + RuntimeGlobals.module + ); + break; default: str += `[${JSON.stringify( prop.id @@ -193,7 +206,8 @@ class ImportMetaPlugin { } const dep = new ConstDependency( `({${str}})`, - /** @type {Range} */ (metaProperty.range) + /** @type {Range} */ (metaProperty.range), + runtimeRequirements ); dep.loc = /** @type {DependencyLocation} */ (metaProperty.loc); parser.state.module.addPresentationalDependency(dep); @@ -237,18 +251,18 @@ class ImportMetaPlugin { ); // import.meta.webpack - parser.hooks.typeof - .for("import.meta.webpack") - .tap( - PLUGIN_NAME, - toConstantDependency(parser, JSON.stringify("number")) - ); parser.hooks.expression .for("import.meta.webpack") .tap( PLUGIN_NAME, toConstantDependency(parser, importMetaWebpackVersion()) ); + parser.hooks.typeof + .for("import.meta.webpack") + .tap( + PLUGIN_NAME, + toConstantDependency(parser, JSON.stringify("number")) + ); parser.hooks.evaluateTypeof .for("import.meta.webpack") .tap(PLUGIN_NAME, evaluateToString("number")); @@ -256,6 +270,30 @@ class ImportMetaPlugin { .for("import.meta.webpack") .tap(PLUGIN_NAME, evaluateToNumber(webpackVersion)); + parser.hooks.expression + .for("import.meta.main") + .tap( + PLUGIN_NAME, + toConstantDependency( + parser, + `${RuntimeGlobals.moduleCache}[${RuntimeGlobals.entryModuleId}] === ${RuntimeGlobals.module}`, + [ + RuntimeGlobals.moduleCache, + RuntimeGlobals.entryModuleId, + RuntimeGlobals.module + ] + ) + ); + parser.hooks.typeof + .for("import.meta.main") + .tap( + PLUGIN_NAME, + toConstantDependency(parser, JSON.stringify("boolean")) + ); + parser.hooks.evaluateTypeof + .for("import.meta.main") + .tap(PLUGIN_NAME, evaluateToString("boolean")); + // Unknown properties parser.hooks.unhandledExpressionMemberChain .for("import.meta") diff --git a/test/configCases/parsing/import-meta-main/boolean.js b/test/configCases/parsing/import-meta-main/boolean.js new file mode 100644 index 000000000..508074e2a --- /dev/null +++ b/test/configCases/parsing/import-meta-main/boolean.js @@ -0,0 +1 @@ +export default "1"; diff --git a/test/configCases/parsing/import-meta-main/index.js b/test/configCases/parsing/import-meta-main/index.js new file mode 100644 index 000000000..f1751198e --- /dev/null +++ b/test/configCases/parsing/import-meta-main/index.js @@ -0,0 +1,14 @@ +import { main } from "./module.js"; + +it("should handle import.meta.main", async () => { + expect(import.meta.main).toBe(true); + expect(typeof import.meta.main).toBe("boolean"); + + // Just for test, nobody uses this in real code + await import(`./${typeof import.meta.main}.js`); + + const { main: myMain } = import.meta; + expect(myMain).toBe(true); + + expect(main).toBe(false); +}); diff --git a/test/configCases/parsing/import-meta-main/module.js b/test/configCases/parsing/import-meta-main/module.js new file mode 100644 index 000000000..0c71e2120 --- /dev/null +++ b/test/configCases/parsing/import-meta-main/module.js @@ -0,0 +1,3 @@ +const main = import.meta.main; + +export { main }; diff --git a/test/configCases/parsing/import-meta-main/webpack.config.js b/test/configCases/parsing/import-meta-main/webpack.config.js new file mode 100644 index 000000000..270b2df2b --- /dev/null +++ b/test/configCases/parsing/import-meta-main/webpack.config.js @@ -0,0 +1,9 @@ +"use strict"; + +/** @type {import("../../../../").Configuration} */ +module.exports = { + target: "node", + optimization: { + concatenateModules: false + } +}; diff --git a/test/configCases/parsing/require-main/index.js b/test/configCases/parsing/require-main/index.js new file mode 100644 index 000000000..317c0b96e --- /dev/null +++ b/test/configCases/parsing/require-main/index.js @@ -0,0 +1,7 @@ +const { main } = require("./module"); + +it("should handle require.main", async () => { + expect(require.main === module).toBe(true); + + expect(main).toBe(false); +}); diff --git a/test/configCases/parsing/require-main/module.js b/test/configCases/parsing/require-main/module.js new file mode 100644 index 000000000..1bd071b12 --- /dev/null +++ b/test/configCases/parsing/require-main/module.js @@ -0,0 +1,3 @@ +const main = require.main === module; + +module.exports = { main }; diff --git a/test/configCases/parsing/require-main/webpack.config.js b/test/configCases/parsing/require-main/webpack.config.js new file mode 100644 index 000000000..270b2df2b --- /dev/null +++ b/test/configCases/parsing/require-main/webpack.config.js @@ -0,0 +1,9 @@ +"use strict"; + +/** @type {import("../../../../").Configuration} */ +module.exports = { + target: "node", + optimization: { + concatenateModules: false + } +};