Skip to content

Commit f1ea815

Browse files
authored
Merge pull request #17308 from webpack/issue-17306
fix: compatibility `__non_webpack_require__` with ES modules
2 parents 9f837fc + ce9c21e commit f1ea815

15 files changed

Lines changed: 259 additions & 204 deletions

File tree

lib/APIPlugin.js

Lines changed: 150 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
"use strict";
77

8+
const InitFragment = require("./InitFragment");
89
const {
910
JAVASCRIPT_MODULE_TYPE_AUTO,
1011
JAVASCRIPT_MODULE_TYPE_DYNAMIC,
@@ -14,6 +15,7 @@ const RuntimeGlobals = require("./RuntimeGlobals");
1415
const WebpackError = require("./WebpackError");
1516
const ConstDependency = require("./dependencies/ConstDependency");
1617
const BasicEvaluatedExpression = require("./javascript/BasicEvaluatedExpression");
18+
const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin");
1719
const {
1820
toConstantDependency,
1921
evaluateToString
@@ -24,103 +26,121 @@ const GetFullHashRuntimeModule = require("./runtime/GetFullHashRuntimeModule");
2426
/** @typedef {import("./Compiler")} Compiler */
2527
/** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */
2628

27-
/* eslint-disable camelcase */
28-
const REPLACEMENTS = {
29-
__webpack_require__: {
30-
expr: RuntimeGlobals.require,
31-
req: [RuntimeGlobals.require],
32-
type: "function",
33-
assign: false
34-
},
35-
__webpack_public_path__: {
36-
expr: RuntimeGlobals.publicPath,
37-
req: [RuntimeGlobals.publicPath],
38-
type: "string",
39-
assign: true
40-
},
41-
__webpack_base_uri__: {
42-
expr: RuntimeGlobals.baseURI,
43-
req: [RuntimeGlobals.baseURI],
44-
type: "string",
45-
assign: true
46-
},
47-
__webpack_modules__: {
48-
expr: RuntimeGlobals.moduleFactories,
49-
req: [RuntimeGlobals.moduleFactories],
50-
type: "object",
51-
assign: false
52-
},
53-
__webpack_chunk_load__: {
54-
expr: RuntimeGlobals.ensureChunk,
55-
req: [RuntimeGlobals.ensureChunk],
56-
type: "function",
57-
assign: true
58-
},
59-
__non_webpack_require__: {
60-
expr: "require",
61-
req: null,
62-
type: undefined, // type is not known, depends on environment
63-
assign: true
64-
},
65-
__webpack_nonce__: {
66-
expr: RuntimeGlobals.scriptNonce,
67-
req: [RuntimeGlobals.scriptNonce],
68-
type: "string",
69-
assign: true
70-
},
71-
__webpack_hash__: {
72-
expr: `${RuntimeGlobals.getFullHash}()`,
73-
req: [RuntimeGlobals.getFullHash],
74-
type: "string",
75-
assign: false
76-
},
77-
__webpack_chunkname__: {
78-
expr: RuntimeGlobals.chunkName,
79-
req: [RuntimeGlobals.chunkName],
80-
type: "string",
81-
assign: false
82-
},
83-
__webpack_get_script_filename__: {
84-
expr: RuntimeGlobals.getChunkScriptFilename,
85-
req: [RuntimeGlobals.getChunkScriptFilename],
86-
type: "function",
87-
assign: true
88-
},
89-
__webpack_runtime_id__: {
90-
expr: RuntimeGlobals.runtimeId,
91-
req: [RuntimeGlobals.runtimeId],
92-
assign: false
93-
},
94-
"require.onError": {
95-
expr: RuntimeGlobals.uncaughtErrorHandler,
96-
req: [RuntimeGlobals.uncaughtErrorHandler],
97-
type: undefined, // type is not known, could be function or undefined
98-
assign: true // is never a pattern
99-
},
100-
__system_context__: {
101-
expr: RuntimeGlobals.systemContext,
102-
req: [RuntimeGlobals.systemContext],
103-
type: "object",
104-
assign: false
105-
},
106-
__webpack_share_scopes__: {
107-
expr: RuntimeGlobals.shareScopeMap,
108-
req: [RuntimeGlobals.shareScopeMap],
109-
type: "object",
110-
assign: false
111-
},
112-
__webpack_init_sharing__: {
113-
expr: RuntimeGlobals.initializeSharing,
114-
req: [RuntimeGlobals.initializeSharing],
115-
type: "function",
116-
assign: true
117-
}
118-
};
119-
/* eslint-enable camelcase */
29+
/**
30+
* @param {boolean} module true if ES module
31+
* @param {string} importMetaName `import.meta` name
32+
* @returns {Record<string, {expr: string, req: string[], type?: string, assign: boolean}>} replacements
33+
*/
34+
function getReplacements(module, importMetaName) {
35+
return {
36+
__webpack_require__: {
37+
expr: RuntimeGlobals.require,
38+
req: [RuntimeGlobals.require],
39+
type: "function",
40+
assign: false
41+
},
42+
__webpack_public_path__: {
43+
expr: RuntimeGlobals.publicPath,
44+
req: [RuntimeGlobals.publicPath],
45+
type: "string",
46+
assign: true
47+
},
48+
__webpack_base_uri__: {
49+
expr: RuntimeGlobals.baseURI,
50+
req: [RuntimeGlobals.baseURI],
51+
type: "string",
52+
assign: true
53+
},
54+
__webpack_modules__: {
55+
expr: RuntimeGlobals.moduleFactories,
56+
req: [RuntimeGlobals.moduleFactories],
57+
type: "object",
58+
assign: false
59+
},
60+
__webpack_chunk_load__: {
61+
expr: RuntimeGlobals.ensureChunk,
62+
req: [RuntimeGlobals.ensureChunk],
63+
type: "function",
64+
assign: true
65+
},
66+
__non_webpack_require__: {
67+
expr: module
68+
? `__WEBPACK_EXTERNAL_createRequire(${importMetaName}.url)`
69+
: "require",
70+
req: null,
71+
type: undefined, // type is not known, depends on environment
72+
assign: true
73+
},
74+
__webpack_nonce__: {
75+
expr: RuntimeGlobals.scriptNonce,
76+
req: [RuntimeGlobals.scriptNonce],
77+
type: "string",
78+
assign: true
79+
},
80+
__webpack_hash__: {
81+
expr: `${RuntimeGlobals.getFullHash}()`,
82+
req: [RuntimeGlobals.getFullHash],
83+
type: "string",
84+
assign: false
85+
},
86+
__webpack_chunkname__: {
87+
expr: RuntimeGlobals.chunkName,
88+
req: [RuntimeGlobals.chunkName],
89+
type: "string",
90+
assign: false
91+
},
92+
__webpack_get_script_filename__: {
93+
expr: RuntimeGlobals.getChunkScriptFilename,
94+
req: [RuntimeGlobals.getChunkScriptFilename],
95+
type: "function",
96+
assign: true
97+
},
98+
__webpack_runtime_id__: {
99+
expr: RuntimeGlobals.runtimeId,
100+
req: [RuntimeGlobals.runtimeId],
101+
assign: false
102+
},
103+
"require.onError": {
104+
expr: RuntimeGlobals.uncaughtErrorHandler,
105+
req: [RuntimeGlobals.uncaughtErrorHandler],
106+
type: undefined, // type is not known, could be function or undefined
107+
assign: true // is never a pattern
108+
},
109+
__system_context__: {
110+
expr: RuntimeGlobals.systemContext,
111+
req: [RuntimeGlobals.systemContext],
112+
type: "object",
113+
assign: false
114+
},
115+
__webpack_share_scopes__: {
116+
expr: RuntimeGlobals.shareScopeMap,
117+
req: [RuntimeGlobals.shareScopeMap],
118+
type: "object",
119+
assign: false
120+
},
121+
__webpack_init_sharing__: {
122+
expr: RuntimeGlobals.initializeSharing,
123+
req: [RuntimeGlobals.initializeSharing],
124+
type: "function",
125+
assign: true
126+
}
127+
};
128+
}
120129

121130
const PLUGIN_NAME = "APIPlugin";
122131

132+
/**
133+
* @typedef {Object} APIPluginOptions
134+
* @property {boolean} [module] the output filename
135+
*/
136+
123137
class APIPlugin {
138+
/**
139+
* @param {APIPluginOptions} [options] options
140+
*/
141+
constructor(options = {}) {
142+
this.options = options;
143+
}
124144
/**
125145
* Apply the plugin
126146
* @param {Compiler} compiler the compiler instance
@@ -130,6 +150,12 @@ class APIPlugin {
130150
compiler.hooks.compilation.tap(
131151
PLUGIN_NAME,
132152
(compilation, { normalModuleFactory }) => {
153+
const { importMetaName } = compilation.outputOptions;
154+
const REPLACEMENTS = getReplacements(
155+
this.options.module,
156+
importMetaName
157+
);
158+
133159
compilation.dependencyTemplates.set(
134160
ConstDependency,
135161
new ConstDependency.Template()
@@ -152,18 +178,43 @@ class APIPlugin {
152178
return true;
153179
});
154180

181+
const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation);
182+
183+
hooks.renderModuleContent.tap(
184+
PLUGIN_NAME,
185+
(source, module, renderContext) => {
186+
if (module.buildInfo.needCreateRequire) {
187+
const chunkInitFragments = [
188+
new InitFragment(
189+
'import { createRequire as __WEBPACK_EXTERNAL_createRequire } from "module";\n',
190+
InitFragment.STAGE_HARMONY_IMPORTS,
191+
0,
192+
"external module node-commonjs"
193+
)
194+
];
195+
196+
renderContext.chunkInitFragments.push(...chunkInitFragments);
197+
}
198+
199+
return source;
200+
}
201+
);
202+
155203
/**
156204
* @param {JavascriptParser} parser the parser
157205
*/
158206
const handler = parser => {
159207
Object.keys(REPLACEMENTS).forEach(key => {
160208
const info = REPLACEMENTS[key];
161-
parser.hooks.expression
162-
.for(key)
163-
.tap(
164-
PLUGIN_NAME,
165-
toConstantDependency(parser, info.expr, info.req)
166-
);
209+
parser.hooks.expression.for(key).tap(PLUGIN_NAME, expression => {
210+
const dep = toConstantDependency(parser, info.expr, info.req);
211+
212+
if (key === "__non_webpack_require__" && this.options.module) {
213+
parser.state.module.buildInfo.needCreateRequire = true;
214+
}
215+
216+
return dep(expression);
217+
});
167218
if (info.assign === false) {
168219
parser.hooks.assign.for(key).tap(PLUGIN_NAME, expr => {
169220
const err = new WebpackError(`${key} must not be assigned`);

lib/ExternalModule.js

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,13 @@ const getSourceForCommonJsExternal = moduleAndSpecifiers => {
104104

105105
/**
106106
* @param {string|string[]} moduleAndSpecifiers the module request
107+
* @param {string} importMetaName import.meta name
107108
* @returns {SourceData} the generated source
108109
*/
109-
const getSourceForCommonJsExternalInNodeModule = moduleAndSpecifiers => {
110+
const getSourceForCommonJsExternalInNodeModule = (
111+
moduleAndSpecifiers,
112+
importMetaName
113+
) => {
110114
const chunkInitFragments = [
111115
new InitFragment(
112116
'import { createRequire as __WEBPACK_EXTERNAL_createRequire } from "module";\n',
@@ -117,18 +121,18 @@ const getSourceForCommonJsExternalInNodeModule = moduleAndSpecifiers => {
117121
];
118122
if (!Array.isArray(moduleAndSpecifiers)) {
119123
return {
120-
expression: `__WEBPACK_EXTERNAL_createRequire(import.meta.url)(${JSON.stringify(
124+
chunkInitFragments,
125+
expression: `__WEBPACK_EXTERNAL_createRequire(${importMetaName}.url)(${JSON.stringify(
121126
moduleAndSpecifiers
122-
)})`,
123-
chunkInitFragments
127+
)})`
124128
};
125129
}
126130
const moduleName = moduleAndSpecifiers[0];
127131
return {
128-
expression: `__WEBPACK_EXTERNAL_createRequire(import.meta.url)(${JSON.stringify(
132+
chunkInitFragments,
133+
expression: `__WEBPACK_EXTERNAL_createRequire(${importMetaName}.url)(${JSON.stringify(
129134
moduleName
130-
)})${propertyAccess(moduleAndSpecifiers, 1)}`,
131-
chunkInitFragments
135+
)})${propertyAccess(moduleAndSpecifiers, 1)}`
132136
};
133137
};
134138

@@ -557,7 +561,10 @@ class ExternalModule extends Module {
557561
return getSourceForCommonJsExternal(request);
558562
case "node-commonjs":
559563
return this.buildInfo.module
560-
? getSourceForCommonJsExternalInNodeModule(request)
564+
? getSourceForCommonJsExternalInNodeModule(
565+
request,
566+
runtimeTemplate.outputOptions.importMetaName
567+
)
561568
: getSourceForCommonJsExternal(request);
562569
case "amd":
563570
case "amd-require":

lib/WebpackOptionsApply.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,9 @@ class WebpackOptionsApply extends OptionsApply {
368368
const NodeStuffPlugin = require("./NodeStuffPlugin");
369369
new NodeStuffPlugin(options.node).apply(compiler);
370370
}
371-
new APIPlugin().apply(compiler);
371+
new APIPlugin({
372+
module: options.output.module
373+
}).apply(compiler);
372374
new ExportsInfoApiPlugin().apply(compiler);
373375
new WebpackIsIncludedPlugin().apply(compiler);
374376
new ConstPlugin().apply(compiler);

lib/javascript/JavascriptModulesPlugin.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,7 @@ class JavascriptModulesPlugin {
937937
"JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().renderContent plugins should return something"
938938
);
939939
}
940+
940941
finalSource = InitFragment.addToSource(
941942
finalSource,
942943
chunkRenderContext.chunkInitFragments,

lib/node/ReadFileCompileAsyncWasmPlugin.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class ReadFileCompileAsyncWasmPlugin {
4040
: globalWasmLoading;
4141
return wasmLoading === this._type;
4242
};
43+
const { importMetaName } = compilation.outputOptions;
4344
/**
4445
* @type {(path: string) => string}
4546
*/
@@ -48,7 +49,7 @@ class ReadFileCompileAsyncWasmPlugin {
4849
Template.asString([
4950
"Promise.all([import('fs'), import('url')]).then(([{ readFile }, { URL }]) => new Promise((resolve, reject) => {",
5051
Template.indent([
51-
`readFile(new URL(${path}, import.meta.url), (err, buffer) => {`,
52+
`readFile(new URL(${path}, ${importMetaName}.url), (err, buffer) => {`,
5253
Template.indent([
5354
"if (err) return reject(err);",
5455
"",

test/ConfigTestCases.template.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,9 @@ const describeCases = config => {
441441
) {
442442
baseModuleScope.window = globalContext;
443443
baseModuleScope.self = globalContext;
444+
baseModuleScope.document = globalContext.document;
445+
baseModuleScope.setTimeout = globalContext.setTimeout;
446+
baseModuleScope.clearTimeout = globalContext.clearTimeout;
444447
baseModuleScope.URL = URL;
445448
baseModuleScope.Worker =
446449
require("./helpers/createFakeWorker")({

0 commit comments

Comments
 (0)