Skip to content

Commit dc3e644

Browse files
authored
fix: should parse webpackExports with empty array (#12066)
1 parent d862a45 commit dc3e644

File tree

24 files changed

+141
-174
lines changed

24 files changed

+141
-174
lines changed

crates/rspack_plugin_javascript/src/webpack_comment.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ fn add_magic_comment_warning(
153153
// _8 for identifier
154154
// _9 for item value as a whole
155155
static WEBPACK_MAGIC_COMMENT_REGEXP: LazyLock<regex::Regex> = LazyLock::new(|| {
156-
regex::Regex::new(r#"(?P<_0>webpack[a-zA-Z\d_-]+)\s*:\s*(?P<_9>"(?P<_1>[^"]+)"|'(?P<_2>[^']+)'|`(?P<_3>[^`]+)`|(?P<_4>[\d.-]+)|(?P<_5>true|false)|(?P<_6>/((?:(?:[^\\/\]\[]+)|(?:\[[^\]]+\])|(?:\\/)|(?:\\.))*)/([dgimsuvy]*))|\[(?P<_7>[^\]]+)|(?P<_8>([^,]+)))"#)
156+
regex::Regex::new(r#"(?P<_0>webpack[a-zA-Z\d_-]+)\s*:\s*(?P<_9>"(?P<_1>[^"]+)"|'(?P<_2>[^']+)'|`(?P<_3>[^`]+)`|(?P<_4>[\d.-]+)|(?P<_5>true|false)|(?P<_6>/((?:(?:[^\\/\]\[]+)|(?:\[[^\]]+\])|(?:\\/)|(?:\\.))*)/([dgimsuvy]*))|\[(?P<_7>[^\]]*)|(?P<_8>([^,]+)))"#)
157157
.expect("invalid regex")
158158
});
159159

@@ -468,8 +468,8 @@ fn analyze_comments(
468468
item_value_match.as_str().trim().to_string(),
469469
);
470470
continue;
471-
} else if let Some(item_value_match) = captures.name("_7")
472-
&& let Some(exports) =
471+
} else if let Some(item_value_match) = captures.name("_7") {
472+
if let Some(exports) =
473473
item_value_match
474474
.as_str()
475475
.split(',')
@@ -479,8 +479,9 @@ fn analyze_comments(
479479
.and_then(|matched| matched.get(1).map(|x| x.as_str()))
480480
.map(|name| format!("{acc},{name}"))
481481
})
482-
{
483-
result.insert(WebpackComment::Exports, exports);
482+
{
483+
result.insert(WebpackComment::Exports, exports);
484+
}
484485
continue;
485486
}
486487
add_magic_comment_warning(

packages/rspack-test-tools/etc/test-tools.api.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,6 @@ export function createHotNormalCase(name: string, src: string, dist: string): vo
104104
// @public (undocumented)
105105
export function createHotStepCase(name: string, src: string, dist: string, temp: string, target: RspackOptions["target"]): void;
106106

107-
// @public (undocumented)
108-
export const createLocatedError: (collectedErrors: Error[], offset: number) => (e: Error, file: TRunnerFile) => Error;
109-
110107
// @public (undocumented)
111108
export function createMultiCompilerCase(name: string, src: string, dist: string, testConfig: string): void;
112109

@@ -826,7 +823,8 @@ export class WebRunner extends NodeRunner {
826823
{
827824
exports: Record<string, unknown>;
828825
},
829-
string
826+
string,
827+
number
830828
];
831829
// (undocumented)
832830
protected log(message: string): void;

packages/rspack-test-tools/src/runner/node/index.ts

Lines changed: 23 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ declare global {
2222
var printLogger: boolean;
2323
}
2424

25-
const EVAL_LOCATION_REGEX = /<anonymous>:(\d+)/;
26-
2725
const isRelativePath = (p: string) => /^\.\.?\//.test(p);
2826
const getSubPath = (p: string) => {
2927
const lastSlash = p.lastIndexOf("/");
@@ -397,49 +395,38 @@ export class NodeRunner implements ITestRunner {
397395
currentModuleScope.__STATS_I__ = statsIndex;
398396
}
399397
}
400-
const createNodeLocatedError = createLocatedError(
401-
this._options.errors || ([] as Error[]),
402-
2
403-
);
404-
const originIt = currentModuleScope.it;
405-
currentModuleScope.it = (
406-
description: string,
407-
fn: () => Promise<void> | void
408-
) => {
409-
originIt(description, async () => {
410-
try {
411-
await fn();
412-
} catch (err) {
413-
throw createNodeLocatedError(err as Error, file);
414-
}
415-
});
416-
};
417-
currentModuleScope.__CREATE_LOCATED_ERROR__ = createNodeLocatedError;
418-
currentModuleScope.__FILE__ = file;
419398
const args = Object.keys(currentModuleScope);
420399
const argValues = args.map(arg => currentModuleScope[arg]);
421400
const code = `(function(${args.join(", ")}) {
422-
try {
423-
${file.content}
424-
} catch(err) {
425-
throw __CREATE_LOCATED_ERROR__(err, __FILE__);
426-
}
401+
${file.content}
427402
})`;
428403

429404
this.preExecute(code, file);
430405
this.log(
431406
`run mode: ${this._options.runInNewContext ? "new context" : "this context"}`
432407
);
433-
const fn = this._options.runInNewContext
434-
? vm.runInNewContext(code, this.globalContext!)
435-
: vm.runInThisContext(code);
436-
437-
fn.call(
438-
this._options.testConfig.nonEsmThis
439-
? this._options.testConfig.nonEsmThis(modulePath)
440-
: m.exports,
441-
...argValues
442-
);
408+
409+
try {
410+
const fn = this._options.runInNewContext
411+
? vm.runInNewContext(code, this.globalContext!, {
412+
filename: file.path,
413+
lineOffset: -1
414+
})
415+
: vm.runInThisContext(code, {
416+
filename: file.path,
417+
lineOffset: -1
418+
});
419+
420+
fn.call(
421+
this._options.testConfig.nonEsmThis
422+
? this._options.testConfig.nonEsmThis(modulePath)
423+
: m.exports,
424+
...argValues
425+
);
426+
} catch (e) {
427+
this._options.errors?.push(e as Error);
428+
throw e;
429+
}
443430

444431
this.postExecute(m, file);
445432
this.log(`end cjs: ${modulePath}`);
@@ -543,31 +530,3 @@ export class NodeRunner implements ITestRunner {
543530
};
544531
}
545532
}
546-
547-
export const createLocatedError = (
548-
collectedErrors: Error[],
549-
offset: number
550-
) => {
551-
return (e: Error, file: TRunnerFile) => {
552-
const match = (e.stack || e.message).match(EVAL_LOCATION_REGEX);
553-
if (match) {
554-
const [, line] = match;
555-
const realLine = Number(line) - offset;
556-
const codeLines = file.content.split("\n");
557-
const lineContents = [
558-
...codeLines
559-
.slice(Math.max(0, realLine - 3), Math.max(0, realLine - 1))
560-
.map(line => `│ ${line}`),
561-
`│> ${codeLines[realLine - 1]}`,
562-
...codeLines.slice(realLine, realLine + 2).map(line => `│ ${line}`)
563-
];
564-
const message = `Error in JSDOM when running file '${file.path}' at line ${realLine}: ${e.message}\n${lineContents.join("\n")}`;
565-
const finalError = new Error(message);
566-
finalError.stack = undefined;
567-
collectedErrors.push(finalError);
568-
return finalError;
569-
} else {
570-
return e;
571-
}
572-
};
573-
};

packages/rspack-test-tools/src/runner/web/index.ts

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ import { escapeSep } from "../../helper";
77
import EventSource from "../../helper/legacy/EventSourceForNode";
88
import urlToRelativePath from "../../helper/legacy/urlToRelativePath";
99
import type { TRunnerFile, TRunnerRequirer } from "../../type";
10-
import {
11-
createLocatedError,
12-
type INodeRunnerOptions,
13-
NodeRunner
14-
} from "../node";
10+
import { type INodeRunnerOptions, NodeRunner } from "../node";
1511

1612
export interface IWebRunnerOptions extends INodeRunnerOptions {
1713
location: string;
@@ -215,7 +211,8 @@ export class WebRunner extends NodeRunner {
215211
{
216212
exports: Record<string, unknown>;
217213
},
218-
string
214+
string,
215+
number
219216
] {
220217
const m = {
221218
exports: {}
@@ -276,23 +273,6 @@ export class WebRunner extends NodeRunner {
276273
return Reflect.set(target, prop, value, receiver);
277274
}
278275
});`;
279-
const createJSDOMLocatedError = createLocatedError(
280-
this._options.errors || ([] as Error[]),
281-
proxyCode.split("\n").length + 2
282-
);
283-
const originIt = currentModuleScope.it;
284-
currentModuleScope.it = (
285-
description: string,
286-
fn: () => Promise<void> | void
287-
) => {
288-
originIt(description, async () => {
289-
try {
290-
await fn();
291-
} catch (err) {
292-
throw createJSDOMLocatedError(err as Error, file);
293-
}
294-
});
295-
};
296276

297277
const scopeKey = escapeSep(file!.path);
298278
const args = Object.keys(currentModuleScope).filter(
@@ -303,19 +283,14 @@ export class WebRunner extends NodeRunner {
303283
.join(", ");
304284
this.dom.window[scopeKey] = currentModuleScope;
305285
this.dom.window["__GLOBAL_SHARED__"] = this.globalContext;
306-
this.dom.window["__FILE__"] = file;
307-
this.dom.window["__CREATE_LOCATED_ERROR__"] = createJSDOMLocatedError;
308286

309287
return [
310288
m,
311289
`${proxyCode}
312290
(function(window, self, globalThis, console, ${args.join(", ")}) {
313-
try {
314-
${file.content}
315-
} catch (err) {
316-
throw __CREATE_LOCATED_ERROR__(err, __FILE__);
317-
}
318-
})($$g$$, $$self$$, $$g$$, window["console"], ${argValues});`
291+
${file.content}
292+
})($$g$$, $$self$$, $$g$$, window["console"], ${argValues});`,
293+
proxyCode.split("\n").length + 1
319294
];
320295
}
321296

@@ -331,18 +306,23 @@ export class WebRunner extends NodeRunner {
331306
return this.requireCache[file.path].exports;
332307
}
333308

334-
const [m, code] = this.getModuleContent(file);
309+
const [m, code, lineOffset] = this.getModuleContent(file);
335310

336311
this.preExecute(code, file);
337312

338313
try {
339314
const script = new Script(code);
340315
const vmContext = this.dom.getInternalVMContext();
341-
script.runInContext(vmContext);
316+
script.runInContext(vmContext, {
317+
filename: file.path,
318+
lineOffset: -lineOffset
319+
});
342320
} catch (e) {
343-
throw new Error(
321+
const error = new Error(
344322
`Parse script '${file.path}' failed: ${(e as Error).message}`
345323
);
324+
this._options.errors?.push(error);
325+
throw error;
346326
}
347327

348328
this.postExecute(m, file);

tests/rspack-test/configCases/parsing/harmony-global/test.filter.js

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11

2-
module.exports = () => "FIXME: expect number"
2+
module.exports = () => "TODO: support compile time evaluation of optional chaining"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11

2-
module.exports = () => "FIXME: Module not found"
2+
module.exports = () => "FIXME: should not bail for optional modules, can be fixed by https://github.com/web-infra-dev/rspack/pull/10351, but it is too dirty"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
// Expecting createRequire import to stay and import.meta.url to not be evaluated
2-
module.exports = () => "FIXME: createRequire is replaced with otherRequire";
2+
module.exports = () => "TODO: support webpackIgnore in createRequire(import.meta.url).resolve()"

tests/rspack-test/configCases/plugins/banner-plugin-hashing/index.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ var source = require("fs")
1515
.slice(0, 1)[0];
1616

1717
const banner = parseBanner(source);
18-
const REGEXP_HASH = /^[A-Za-z0-9]{20}$/;
18+
// DIFF:
19+
// const REGEXP_HASH = /^[A-Za-z0-9]{20}$/;
20+
const REGEXP_HASH = /^[A-Za-z0-9]{16}$/;
1921

2022
it("should interpolate file hash in chunk banner", () => {
2123
expect(REGEXP_HASH.test(banner["fullhash"])).toBe(true);
@@ -30,7 +32,9 @@ it("should interpolate file into chunk banner", () => {
3032
});
3133

3234
it("should interpolate name in chunk banner", () => {
33-
expect(banner["name"]).toBe("dist/banner");
35+
// DIFF:
36+
// expect(banner["name"]).toBe("dist/banner");
37+
expect(banner["name"]).toBe("banner");
3438
});
3539

3640
it("should interpolate basename in chunk banner", () => {

tests/rspack-test/configCases/plugins/banner-plugin-hashing/test.filter.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)