mirror of
https://github.com/morluto/rea.git
synced 2026-10-31 11:56:12 +00:00
* fix(javascript): resolve Vite build-output preload dependencies With an absolute base, Vite writes __vite__mapDeps entries relative to the build output directory (for example assets/chunk.js), and its preload helper prefixes the configured base at runtime. REA emitted these entries as dynamic-import module specifiers, so a scheme-less path without a leading dot resolved as a bare package and every entry was reported as an unresolved "external" module, even when the build output directory was selected. The static analyzer now marks such entries with a vite-output: specifier, as Webpack chunk loads are marked with chunk:. Entries starting with ./, ../ or /, and scheme-qualified entries, keep their previous handling. The graph resolves a marked entry as a URL path under each ancestor directory of the importing file; exactly one ancestor holding the file establishes the build output directory. Otherwise the entry is not-found (or unavailable when several ancestors match) with a limitation that names the build output directory. On a synthetic 7-file Vite build, the 12 preload entries that were "external" now resolve when the build output directory is selected, and are not-found with that guidance when only assets/ is selected. * fix(javascript): keep unanalyzed Vite output candidates resolveViteOutputDependency considered only resolved ancestors. A file that exists under an ancestor but was not analyzed (for example dist/assets/lazy.css for the entry assets/lazy.css) resolves there as unavailable, and that result was replaced by the root's not-found with a limitation saying that no ancestor holds the file. Keep resolved and unavailable ancestor candidates together. One candidate is returned with its own path and limitations; several are reported as unavailable with every candidate path and limitation. Only when no ancestor can hold the file does the root's not-found result stand.
100 lines
3.7 KiB
TypeScript
100 lines
3.7 KiB
TypeScript
import { join } from "node:path";
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
import { createTestTempDirectory } from "../../../fixtures/temporaryDirectory.js";
|
|
import {
|
|
reconstructJavaScriptFixture,
|
|
writeFixtureFiles,
|
|
} from "../../../support/javascriptApplicationFixture.js";
|
|
|
|
// Vite's absolute-base build output: the helper table names files under the
|
|
// output directory, and the real import is relative to the importing chunk.
|
|
const viteBuild = async (): Promise<string> => {
|
|
const root = await createTestTempDirectory("rea-vite-output-");
|
|
await writeFixtureFiles(root, {
|
|
"index.html":
|
|
'<!doctype html><script type="module" src="/assets/index.js"></script>',
|
|
"assets/index.js": `
|
|
const __vite__mapDeps = (i, m = __vite__mapDeps, d =
|
|
(m.f || (m.f = ["assets/lazy.js", "assets/missing.js"]))) => i.map((i) => d[i]);
|
|
const preload = (load, deps) => load();
|
|
export const route = () =>
|
|
preload(() => import("./lazy.js"), __vite__mapDeps([0, 1]));
|
|
`,
|
|
"assets/lazy.js": "export const lazy = true;",
|
|
});
|
|
return root;
|
|
};
|
|
|
|
const preloadEdges = (
|
|
graph: Awaited<ReturnType<typeof reconstructJavaScriptFixture>>["graph"],
|
|
) =>
|
|
graph.edges
|
|
.filter(
|
|
({ relation, properties }) =>
|
|
relation === "imports" &&
|
|
typeof properties.specifier === "string" &&
|
|
properties.specifier.startsWith("vite-output:"),
|
|
)
|
|
.map(({ properties }) => ({
|
|
specifier: properties.specifier,
|
|
resolution_status: properties.resolution_status,
|
|
resolved_path: properties.resolved_path,
|
|
}));
|
|
|
|
describe("Vite build-output preload dependencies", () => {
|
|
it("resolves a dependency under the selected build output directory", async () => {
|
|
const result = await reconstructJavaScriptFixture(await viteBuild());
|
|
|
|
expect(preloadEdges(result.graph)).toContainEqual({
|
|
specifier: "vite-output:assets/lazy.js",
|
|
resolution_status: "resolved",
|
|
resolved_path: "assets/lazy.js",
|
|
});
|
|
expect(JSON.stringify(result.graph)).toContain(
|
|
"no ancestor of the importing file holds it",
|
|
);
|
|
});
|
|
|
|
it("does not report a dependency as an external package when only the assets directory is selected", async () => {
|
|
const root = await viteBuild();
|
|
const result = await reconstructJavaScriptFixture(join(root, "assets"));
|
|
const serialized = JSON.stringify(result.graph);
|
|
|
|
expect(serialized).not.toContain('"resolution_status":"external"');
|
|
expect(serialized).toContain(
|
|
"A Vite preload dependency is relative to the build output directory",
|
|
);
|
|
});
|
|
|
|
it("keeps an inventoried but unanalyzed dependency under a nested build output directory", async () => {
|
|
const root = await createTestTempDirectory("rea-vite-output-css-");
|
|
await writeFixtureFiles(root, {
|
|
"dist/index.html":
|
|
'<!doctype html><script type="module" src="/assets/index.js"></script>',
|
|
"dist/assets/index.js": `
|
|
const __vite__mapDeps = (i, m = __vite__mapDeps, d =
|
|
(m.f || (m.f = ["assets/lazy.css"]))) => i.map((i) => d[i]);
|
|
export const route = () => __vite__mapDeps([0]);
|
|
`,
|
|
"dist/assets/lazy.css": ".lazy { color: green; }",
|
|
});
|
|
const result = await reconstructJavaScriptFixture(root);
|
|
const edge = result.graph.edges.find(
|
|
({ properties }) =>
|
|
properties.specifier === "vite-output:assets/lazy.css",
|
|
);
|
|
|
|
expect(edge?.properties).toMatchObject({
|
|
resolution_status: "unavailable",
|
|
candidate_path: "dist/assets/lazy.css",
|
|
});
|
|
const serialized = JSON.stringify(edge);
|
|
expect(serialized).toContain("dist/assets/lazy.css");
|
|
expect(serialized).not.toContain(
|
|
"no ancestor of the importing file holds it",
|
|
);
|
|
});
|
|
});
|