Skip to content

Commit 2259e2c

Browse files
fix: compatibility import.meta.filename and import.meta.dirname with eval devtools (#20135)
1 parent af7d241 commit 2259e2c

File tree

11 files changed

+175
-63
lines changed

11 files changed

+175
-63
lines changed

lib/NodeStuffPlugin.js

Lines changed: 52 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -245,45 +245,46 @@ class NodeStuffPlugin {
245245
parser.hooks.expression
246246
.for(expressionName)
247247
.tap(PLUGIN_NAME, (expr) => {
248+
// We use `CachedConstDependency` because of `eval` devtool, there is no `import.meta` inside `eval()`
248249
const { importMetaName, environment, module } =
249250
compilation.outputOptions;
250251

251-
if (
252-
module &&
253-
importMetaName === "import.meta" &&
254-
(expressionName === "import.meta.filename" ||
255-
expressionName === "import.meta.dirname") &&
256-
environment.importMetaDirnameAndFilename
257-
) {
258-
return true;
259-
}
260-
261252
// Generate `import.meta.dirname` and `import.meta.filename` when:
262253
// - they are supported by the environment
263254
// - it is a universal target, because we can't use `import mod from "node:url"; ` at the top file
264-
const dep =
255+
if (
265256
environment.importMetaDirnameAndFilename ||
266257
(compiler.platform.web === null &&
267258
compiler.platform.node === null &&
268259
module)
269-
? new ConstDependency(
270-
`${importMetaName}.${property}`,
271-
/** @type {Range} */
272-
(expr.range)
273-
)
274-
: new ExternalModuleDependency(
275-
"url",
276-
[
277-
{
278-
name: "fileURLToPath",
279-
value: URL_MODULE_CONSTANT_FUNCTION_NAME
280-
}
281-
],
282-
undefined,
283-
`${URL_MODULE_CONSTANT_FUNCTION_NAME}(${value()})`,
284-
/** @type {Range} */ (expr.range),
285-
`__webpack_${property}__`
286-
);
260+
) {
261+
const dep = new CachedConstDependency(
262+
`${importMetaName}.${property}`,
263+
/** @type {Range} */
264+
(expr.range),
265+
`__webpack_${property}__`,
266+
CachedConstDependency.PLACE_CHUNK
267+
);
268+
269+
dep.loc = /** @type {DependencyLocation} */ (expr.loc);
270+
parser.state.module.addPresentationalDependency(dep);
271+
return;
272+
}
273+
274+
const dep = new ExternalModuleDependency(
275+
"url",
276+
[
277+
{
278+
name: "fileURLToPath",
279+
value: URL_MODULE_CONSTANT_FUNCTION_NAME
280+
}
281+
],
282+
undefined,
283+
`${URL_MODULE_CONSTANT_FUNCTION_NAME}(${value()})`,
284+
/** @type {Range} */ (expr.range),
285+
`__webpack_${property}__`,
286+
ExternalModuleDependency.PLACE_CHUNK
287+
);
287288
dep.loc = /** @type {DependencyLocation} */ (expr.loc);
288289
parser.state.module.addPresentationalDependency(dep);
289290

@@ -300,34 +301,43 @@ class NodeStuffPlugin {
300301
compilation.outputOptions;
301302

302303
if (
303-
module &&
304-
importMetaName === "import.meta" &&
305-
(expressionName === "import.meta.filename" ||
306-
expressionName === "import.meta.dirname") &&
307-
environment.importMetaDirnameAndFilename
304+
environment.importMetaDirnameAndFilename ||
305+
(compiler.platform.web === null &&
306+
compiler.platform.node === null &&
307+
module)
308308
) {
309-
return `${property}: ${importMetaName}.${property},`;
310-
}
311-
312-
if (environment.importMetaDirnameAndFilename) {
313-
return `${property}: ${importMetaName}.${property},`;
309+
const dep = new CachedConstDependency(
310+
`${importMetaName}.${property}`,
311+
null,
312+
`__webpack_${property}__`,
313+
CachedConstDependency.PLACE_CHUNK
314+
);
315+
dep.loc = /** @type {DependencyLocation} */ (
316+
usingProperty.loc
317+
);
318+
parser.state.module.addPresentationalDependency(dep);
319+
return `${property}: __webpack_${property}__,`;
314320
}
315321

316-
const dep = new ExternalModuleInitFragmentDependency(
322+
const dep = new ExternalModuleDependency(
317323
"url",
318324
[
319325
{
320326
name: "fileURLToPath",
321327
value: URL_MODULE_CONSTANT_FUNCTION_NAME
322328
}
323329
],
324-
undefined
330+
undefined,
331+
`${URL_MODULE_CONSTANT_FUNCTION_NAME}(${value()})`,
332+
null,
333+
`__webpack_${property}__`,
334+
ExternalModuleDependency.PLACE_CHUNK
325335
);
326336

327337
dep.loc = /** @type {DependencyLocation} */ (usingProperty.loc);
328338
parser.state.module.addPresentationalDependency(dep);
329339

330-
return `${property}: ${URL_MODULE_CONSTANT_FUNCTION_NAME}(${value()}),`;
340+
return `${property}: __webpack_${property}__,`;
331341
}
332342
});
333343
}

lib/dependencies/CachedConstDependency.js

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,30 @@ const NullDependency = require("./NullDependency");
2222
class CachedConstDependency extends NullDependency {
2323
/**
2424
* @param {string} expression expression
25-
* @param {Range} range range
25+
* @param {Range | null} range range
2626
* @param {string} identifier identifier
27+
* @param {number=} place place where we inject the expression
2728
*/
28-
constructor(expression, range, identifier) {
29+
constructor(
30+
expression,
31+
range,
32+
identifier,
33+
place = CachedConstDependency.PLACE_MODULE
34+
) {
2935
super();
3036

3137
this.expression = expression;
3238
this.range = range;
3339
this.identifier = identifier;
40+
this.place = place;
3441
this._hashUpdate = undefined;
3542
}
3643

3744
/**
3845
* @returns {string} hash update
3946
*/
4047
_createHashUpdate() {
41-
return `${this.identifier}${this.range}${this.expression}`;
48+
return `${this.place}${this.identifier}${this.range}${this.expression}`;
4249
}
4350

4451
/**
@@ -63,6 +70,7 @@ class CachedConstDependency extends NullDependency {
6370
write(this.expression);
6471
write(this.range);
6572
write(this.identifier);
73+
write(this.place);
6674

6775
super.serialize(context);
6876
}
@@ -76,11 +84,15 @@ class CachedConstDependency extends NullDependency {
7684
this.expression = read();
7785
this.range = read();
7886
this.identifier = read();
87+
this.place = read();
7988

8089
super.deserialize(context);
8190
}
8291
}
8392

93+
CachedConstDependency.PLACE_MODULE = 10;
94+
CachedConstDependency.PLACE_CHUNK = 20;
95+
8496
makeSerializable(
8597
CachedConstDependency,
8698
"webpack/lib/dependencies/CachedConstDependency"
@@ -95,25 +107,27 @@ CachedConstDependency.Template = class CachedConstDependencyTemplate extends (
95107
* @param {DependencyTemplateContext} templateContext the context object
96108
* @returns {void}
97109
*/
98-
apply(dependency, source, { initFragments }) {
110+
apply(dependency, source, { initFragments, chunkInitFragments }) {
99111
const dep = /** @type {CachedConstDependency} */ (dependency);
100112

101-
initFragments.push(
113+
(dep.place === CachedConstDependency.PLACE_MODULE
114+
? initFragments
115+
: chunkInitFragments
116+
).push(
102117
new InitFragment(
103118
`var ${dep.identifier} = ${dep.expression};\n`,
104119
InitFragment.STAGE_CONSTANTS,
105-
0,
120+
// For a chunk we inject expression after imports
121+
dep.place === CachedConstDependency.PLACE_MODULE ? 0 : 10,
106122
`const ${dep.identifier}`
107123
)
108124
);
109125

110126
if (typeof dep.range === "number") {
111127
source.insert(dep.range, dep.identifier);
112-
113-
return;
128+
} else if (dep.range !== null) {
129+
source.replace(dep.range[0], dep.range[1] - 1, dep.identifier);
114130
}
115-
116-
source.replace(dep.range[0], dep.range[1] - 1, dep.identifier);
117131
}
118132
};
119133

lib/dependencies/ExternalModuleDependency.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,30 @@ const ExternalModuleInitFragment = require("./ExternalModuleInitFragment");
1313
/** @typedef {import("../Dependency")} Dependency */
1414
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
1515
/** @typedef {import("../javascript/JavascriptParser").Range} Range */
16+
/** @typedef {import("../dependencies/ExternalModuleInitFragment").ArrayImportSpecifiers} ArrayImportSpecifiers */
1617
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
1718
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
1819

1920
class ExternalModuleDependency extends CachedConstDependency {
2021
/**
2122
* @param {string} module module
22-
* @param {{ name: string, value: string }[]} importSpecifiers import specifiers
23+
* @param {ArrayImportSpecifiers} importSpecifiers import specifiers
2324
* @param {string | undefined} defaultImport default import
2425
* @param {string} expression expression
25-
* @param {Range} range range
26+
* @param {Range | null} range range
2627
* @param {string} identifier identifier
28+
* @param {number=} place place where we inject the expression
2729
*/
2830
constructor(
2931
module,
3032
importSpecifiers,
3133
defaultImport,
3234
expression,
3335
range,
34-
identifier
36+
identifier,
37+
place = CachedConstDependency.PLACE_MODULE
3538
) {
36-
super(expression, range, identifier);
39+
super(expression, range, identifier, place);
3740

3841
this.importedModule = module;
3942
this.specifiers = importSpecifiers;

lib/dependencies/ExternalModuleInitFragment.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const makeSerializable = require("../util/makeSerializable");
1212
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
1313
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
1414
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
15+
/** @typedef {{ name: string, value?: string }[]} ArrayImportSpecifiers */
1516
/** @typedef {Map<string, Set<string>>} ImportSpecifiers */
1617

1718
/**
@@ -20,7 +21,7 @@ const makeSerializable = require("../util/makeSerializable");
2021
class ExternalModuleInitFragment extends InitFragment {
2122
/**
2223
* @param {string} importedModule imported module
23-
* @param {{ name: string, value?: string }[] | ImportSpecifiers} specifiers import specifiers
24+
* @param {ArrayImportSpecifiers | ImportSpecifiers} specifiers import specifiers
2425
* @param {string=} defaultImport default import
2526
*/
2627
constructor(importedModule, specifiers, defaultImport) {

lib/dependencies/ExternalModuleInitFragmentDependency.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ const NullDependency = require("./NullDependency");
1414
/** @typedef {import("../Dependency")} Dependency */
1515
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
1616
/** @typedef {import("../javascript/JavascriptParser").Range} Range */
17+
/** @typedef {import("../dependencies/ExternalModuleInitFragment").ArrayImportSpecifiers} ArrayImportSpecifiers */
1718
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
1819
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
1920

2021
class ExternalModuleInitFragmentDependency extends NullDependency {
2122
/**
2223
* @param {string} module module
23-
* @param {{ name: string, value: string }[]} importSpecifiers import specifiers
24+
* @param {ArrayImportSpecifiers} importSpecifiers import specifiers
2425
* @param {string | undefined} defaultImport default import
2526
*/
2627
constructor(module, importSpecifiers, defaultImport) {

test/__snapshots__/ConfigCacheTestCases.longtest.js.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target
5353

5454
exports[`ConfigCacheTestCases chunks-order module exported tests The dependOn chunk must be loaded before the common chunk. 1`] = `
5555
"import {fileURLToPath as __webpack_fileURLToPath__} from \\"node:url\\";
56+
var __webpack_filename__ = __webpack_fileURLToPath__(import.meta.url);
5657
export const __webpack_esm_id__ = \\"foo\\";
5758
export const __webpack_esm_ids__ = [\\"foo\\"];
5859
export const __webpack_esm_modules__ = {
@@ -73,7 +74,6 @@ export const __webpack_esm_modules__ = {
7374
\\\\****************/
7475
/***/ ((__unused_webpack_module, __unused_webpack___webpack_exports__, __webpack_require__) => {
7576
76-
var __webpack_filename__ = __webpack_fileURLToPath__(import.meta.url);
7777
/* harmony import */ var _style_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./style.css */ 125);
7878
/* harmony import */ var _dependency_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./dependency.js */ 784);
7979
/* harmony import */ var _dependency_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_dependency_js__WEBPACK_IMPORTED_MODULE_1__);
@@ -14998,10 +14998,10 @@ __WEBPACK_EXTERNAL_MODULE_externals1_v__;
1499814998
1499914999
exports[`ConfigCacheTestCases module import-meta-env exported tests import.meta.env behaves like process.env 1`] = `
1500015000
"import {fileURLToPath as __webpack_fileURLToPath__} from \\"url\\";
15001+
var __webpack_filename__ = __webpack_fileURLToPath__(import.meta.url);
1500115002
/*!******************!*\\\\
1500215003
!*** ./index.js ***!
1500315004
\\\\******************/
15004-
var __webpack_filename__ = __webpack_fileURLToPath__(import.meta.url);
1500515005
it(\\"should work import.meta.env with EnvironmentPlugin\\", () => {
1500615006
expect(\\"aaa\\").toBe(\\"aaa\\");
1500715007
});

test/__snapshots__/ConfigTestCases.basictest.js.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target
5353

5454
exports[`ConfigTestCases chunks-order module exported tests The dependOn chunk must be loaded before the common chunk. 1`] = `
5555
"import {fileURLToPath as __webpack_fileURLToPath__} from \\"node:url\\";
56+
var __webpack_filename__ = __webpack_fileURLToPath__(import.meta.url);
5657
export const __webpack_esm_id__ = \\"foo\\";
5758
export const __webpack_esm_ids__ = [\\"foo\\"];
5859
export const __webpack_esm_modules__ = {
@@ -73,7 +74,6 @@ export const __webpack_esm_modules__ = {
7374
\\\\****************/
7475
/***/ ((__unused_webpack_module, __unused_webpack___webpack_exports__, __webpack_require__) => {
7576
76-
var __webpack_filename__ = __webpack_fileURLToPath__(import.meta.url);
7777
/* harmony import */ var _style_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./style.css */ 125);
7878
/* harmony import */ var _dependency_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./dependency.js */ 784);
7979
/* harmony import */ var _dependency_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_dependency_js__WEBPACK_IMPORTED_MODULE_1__);
@@ -13789,10 +13789,10 @@ __WEBPACK_EXTERNAL_MODULE_externals1_v__;
1378913789
1379013790
exports[`ConfigTestCases module import-meta-env exported tests import.meta.env behaves like process.env 1`] = `
1379113791
"import {fileURLToPath as __webpack_fileURLToPath__} from \\"url\\";
13792+
var __webpack_filename__ = __webpack_fileURLToPath__(import.meta.url);
1379213793
/*!******************!*\\\\
1379313794
!*** ./index.js ***!
1379413795
\\\\******************/
13795-
var __webpack_filename__ = __webpack_fileURLToPath__(import.meta.url);
1379613796
it(\\"should work import.meta.env with EnvironmentPlugin\\", () => {
1379713797
expect(\\"aaa\\").toBe(\\"aaa\\");
1379813798
});

test/configCases/node/filename-and-dirname-universal/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ it("should work", () => {
88
// because they may not exist when code is running
99
expect(import.meta.dirname).toBe(__STATS__.children[__STATS_I__].outputPath);
1010
expect(typeof import.meta.dirname).toBe("string");
11-
expect(import.meta.filename.endsWith("bundle1.mjs")).toBe(true);
11+
expect(/bundle[13].mjs/.test(import.meta.filename)).toBe(true);
1212
expect(typeof import.meta.filename).toBe("string");
1313
}
1414
});

test/configCases/node/filename-and-dirname-universal/webpack.config.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,27 @@ module.exports = [
2121
experiments: {
2222
outputModule: true
2323
}
24+
},
25+
{
26+
name: "web",
27+
devtool: "eval",
28+
target: ["node", "web"],
29+
output: {
30+
module: true
31+
},
32+
experiments: {
33+
outputModule: true
34+
}
35+
},
36+
{
37+
name: "node",
38+
devtool: "eval",
39+
target: ["node", "web"],
40+
output: {
41+
module: true
42+
},
43+
experiments: {
44+
outputModule: true
45+
}
2446
}
2547
];

0 commit comments

Comments
 (0)