fix(javascript): retain distinct chunk registration callback metadata (#2737)

Co-authored-by: LouisChen <3361008+chqcjq@users.noreply.github.com>
This commit is contained in:
LouisChenandLouisChen authored and GitHub committed 2026-10-13 17:42:41 +08:00
1 parent 52d4ce6ced
commit 0cf224e762
3 files changed
+147

No files matched your search

@@ -0,0 +1,78 @@
import { expect, it } from "vitest";
import { analyzeJavaScriptStaticSource } from "./javascriptStaticAnalysis.js";
const registration = (runtime: string, callback: string, chunk = 1) =>
"(globalThis." +
runtime +
" = globalThis." +
runtime +
" || []).push([[" +
chunk +
"], {a: function() {}}, " +
callback +
"]);";
it.each(["webpackChunkFixture", "rspackChunkFixture"])(
"keeps differing callback facts for %s independent of source order",
(runtime) => {
const first = registration(
runtime,
'function(r) { r(7); r.e("chunk-a"); }',
);
const second = registration(
runtime,
'function(r) { r(8); r.e("chunk-b"); }',
);
for (const source of [first + "\n" + second, second + "\n" + first]) {
const result = analyzeJavaScriptStaticSource(source);
expect(result.parse_status).toBe("complete");
expect(result.bundler_registrations).toHaveLength(2);
expect(
result.bundler_registrations.flatMap((r) => r.entry_module_keys).sort(),
).toEqual(["7", "8"]);
expect(
result.bundler_registrations.flatMap((r) => r.async_chunk_keys).sort(),
).toEqual(["chunk-a", "chunk-b"]);
}
expect(
analyzeJavaScriptStaticSource(first + "\n" + first).bundler_registrations,
).toHaveLength(1);
expect(
analyzeJavaScriptStaticSource(first).bundler_registrations[0],
).toMatchObject({
entry_module_keys: ["7"],
async_chunk_keys: ["chunk-a"],
});
expect(
analyzeJavaScriptStaticSource(second).bundler_registrations[0],
).toMatchObject({
entry_module_keys: ["8"],
async_chunk_keys: ["chunk-b"],
});
},
);
it.each([
["function(r) { r(7); }", "function(r) { r(8); }"],
['function(r) { r.e("a"); }', 'function(r) { r.e("b"); }'],
["function(r) {}", "function(s) {}"],
["function(r) {}", "function(r) { r(dynamic); }"],
["function(r) {}", "function(r) { r.e(dynamic); }"],
])("retains callback metadata differences: %s / %s", (left, right) => {
const result = analyzeJavaScriptStaticSource(
registration("webpackChunkFixture", left) +
"\n" +
registration("webpackChunkFixture", right),
);
expect(result.bundler_registrations).toHaveLength(2);
});
it("retains distinct chunk identities with identical callbacks", () => {
const callback = "function(r) { r(7); }";
const result = analyzeJavaScriptStaticSource(
registration("webpackChunkFixture", callback, 1) +
"\n" +
registration("webpackChunkFixture", callback, 2),
);
expect(result.bundler_registrations).toHaveLength(2);
});
@@ -691,6 +691,14 @@ export const registrationKey = (
registration.runtime,
registration.chunk_keys,
String(registration.unknown_chunk_keys),
// Equal factory tables can be registered with different runtime callbacks.
// Both early collection and finalization must retain those recovered facts.
registration.runtime_require_name,
registration.runtime_module_cache_status,
registration.entry_module_keys,
String(registration.unknown_entry_module_keys),
registration.async_chunk_keys,
String(registration.unknown_async_chunk_keys),
registration.modules.map(({ module_key: key, source_sha256: digest }) => [
key,
digest,
@@ -0,0 +1,61 @@
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect } from "vitest";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
import { analyzeJavaScriptDirectory } from "../../support/cli/javascriptApplication.js";
cliTest.for(["CLI", "stdio MCP"] as const)(
"retains both repeated chunk callback observations through %s",
async (surface, { cli }) => {
const root = await createTestTempDirectory("rea-bundler-callbacks-");
const source = [
'(globalThis.webpackChunkFixture = globalThis.webpackChunkFixture || []).push([[1], {a: function() {}}, function(r) { r(7); r.e("chunk-a"); }]);',
'(globalThis.webpackChunkFixture = globalThis.webpackChunkFixture || []).push([[1], {a: function() {}}, function(r) { r(8); r.e("chunk-b"); }]);',
].join("\n");
await writeFile(join(root, "bundle.js"), source);
const { graph } = await analyzeJavaScriptDirectory(surface, cli, root);
const chunk = graph.nodes.find(({ kind }) => kind === "javascript-chunk");
for (const [index, entry, asyncChunk] of [
[0, "7", "chunk-a"],
[1, "8", "chunk-b"],
] as const) {
expect(chunk?.observations).toContainEqual(
expect.objectContaining({
properties: expect.objectContaining({
entry_module_keys: [entry],
async_chunk_keys: [asyncChunk],
}),
evidence: expect.objectContaining({
location: expect.objectContaining({
value: expect.objectContaining({
source: "bundle.js",
start: { line: index + 1, column: 0 },
}),
}),
}),
}),
);
expect(graph.edges).toContainEqual(
expect.objectContaining({
source_node_id: chunk?.node_id,
properties: expect.objectContaining({
kind: "bundler-entry-module",
module_key: entry,
resolution_status: "not-found",
}),
}),
);
expect(graph.edges).toContainEqual(
expect.objectContaining({
source_node_id: chunk?.node_id,
properties: expect.objectContaining({
kind: "bundler-async-chunk",
chunk_key: asyncChunk,
resolution_status: "not-found",
}),
}),
);
}
},
);