Skip to content

Commit f135ec8

Browse files
committed
fix(build): namespace virtual module ids in sourcemap sources
1 parent 69c36aa commit f135ec8

4 files changed

Lines changed: 114 additions & 42 deletions

File tree

src/build/plugins.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { unwasm } from "unwasm/plugin";
88
import { routeMeta } from "./plugins/route-meta.ts";
99
import { serverMain } from "./plugins/server-main.ts";
1010
import { virtual, virtualDeps } from "./plugins/virtual.ts";
11-
import { sourcemapMinify } from "./plugins/sourcemap-min.ts";
11+
import { sourcemap } from "./plugins/sourcemap.ts";
1212
import { raw, RESOLVED_RE as rawModulesRE } from "./plugins/raw.ts";
1313
import { importAttributes } from "./plugins/import-attributes.ts";
1414
import { externals } from "./plugins/externals.ts";
@@ -75,13 +75,14 @@ export async function baseBuildPlugins(nitro: Nitro, base: BaseBuildConfig) {
7575
);
7676
}
7777

78-
// Sourcemap minify
79-
if (
80-
nitro.options.sourcemap &&
81-
!nitro.options.dev &&
82-
nitro.options.experimental.sourcemapMinify !== false
83-
) {
84-
plugins.push(sourcemapMinify());
78+
// Sourcemap
79+
if (nitro.options.sourcemap && !nitro.options.dev) {
80+
plugins.push(
81+
sourcemap({
82+
virtualIds: virtualPlugin.api.modules.keys(),
83+
minify: nitro.options.experimental.sourcemapMinify !== false,
84+
})
85+
);
8586
}
8687

8788
return plugins;

src/build/plugins/sourcemap-min.ts

Lines changed: 0 additions & 30 deletions
This file was deleted.

src/build/plugins/sourcemap.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import type { ExistingRawSourceMap, Plugin } from "rollup";
2+
3+
// Ids of virtual modules already namespaced by their own plugins
4+
const VIRTUAL_PREFIX_RE = /(?:^|\/)(virtual:.+)$/;
5+
6+
export function sourcemap(opts: { virtualIds: Iterable<string>; minify: boolean }): Plugin {
7+
const virtualIds = [...opts.virtualIds];
8+
9+
return {
10+
name: "nitro:sourcemap",
11+
generateBundle(_options, bundle) {
12+
for (const [key, asset] of Object.entries(bundle)) {
13+
// Only process sourcemaps
14+
if (!key.endsWith(".map") || !("source" in asset) || typeof asset.source !== "string") {
15+
continue;
16+
}
17+
18+
// Parse sourcemap
19+
const sourcemap: ExistingRawSourceMap = JSON.parse(asset.source);
20+
21+
// Virtual modules have no file on disk. Bundlers emit their ids as (relative)
22+
// paths, making consumers warn about missing sources. Namespace them instead.
23+
if (sourcemap.sources) {
24+
sourcemap.sources = sourcemap.sources.map((source) =>
25+
source ? virtualSource(source, virtualIds) : source
26+
);
27+
}
28+
29+
if (opts.minify) {
30+
// Remove sourcesContent
31+
delete sourcemap.sourcesContent;
32+
33+
// Remove x_google_ignoreList
34+
delete sourcemap.x_google_ignoreList;
35+
36+
if ((sourcemap.sources || []).every((s) => s?.includes("node_modules"))) {
37+
sourcemap.mappings = ""; // required key
38+
}
39+
}
40+
41+
asset.source = JSON.stringify(sourcemap);
42+
}
43+
},
44+
};
45+
}
46+
47+
function virtualSource(source: string, virtualIds: string[]): string {
48+
const namespaced = VIRTUAL_PREFIX_RE.exec(source)?.[1];
49+
if (namespaced) {
50+
return namespaced;
51+
}
52+
for (const id of virtualIds) {
53+
if (source === id || source.endsWith(`/${id}`)) {
54+
return `virtual:${id}`;
55+
}
56+
}
57+
return source;
58+
}
Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, it } from "vitest";
2-
import { sourcemapMinify } from "../../src/build/plugins/sourcemap-min.ts";
2+
import { sourcemap } from "../../src/build/plugins/sourcemap.ts";
33

44
type BundleAsset = { type: "asset"; source: string };
55

@@ -20,8 +20,14 @@ function createSourcemapAsset(sourcemap: {
2020
};
2121
}
2222

23-
function runPlugin(bundle: Record<string, BundleAsset>) {
24-
const plugin = sourcemapMinify();
23+
function runPlugin(
24+
bundle: Record<string, BundleAsset>,
25+
opts: { virtualIds?: string[]; minify?: boolean } = {}
26+
) {
27+
const plugin = sourcemap({
28+
virtualIds: opts.virtualIds || [],
29+
minify: opts.minify ?? true,
30+
});
2531
(plugin.generateBundle as Function).call(null, {}, bundle);
2632
const results: Record<string, ReturnType<typeof JSON.parse>> = {};
2733
for (const [key, asset] of Object.entries(bundle)) {
@@ -32,7 +38,7 @@ function runPlugin(bundle: Record<string, BundleAsset>) {
3238
return results;
3339
}
3440

35-
describe("sourcemapMinify", () => {
41+
describe("sourcemap", () => {
3642
it("removes sourcesContent from all sourcemaps", () => {
3743
const bundle = {
3844
"index.mjs.map": createSourcemapAsset({
@@ -109,4 +115,41 @@ describe("sourcemapMinify", () => {
109115
const results = runPlugin(bundle);
110116
expect(results["chunk.mjs.map"].mappings).toBe("");
111117
});
118+
119+
it("namespaces virtual module sources", () => {
120+
const bundle = {
121+
"_chunks/app.mjs.map": createSourcemapAsset({
122+
sources: [
123+
"../../../../workspace/app/#nitro/virtual/app",
124+
"../../../../workspace/app/#virtual-route",
125+
"../../../../workspace/app/virtual:nitro:raw:/workspace/app/server/files/test.txt.js",
126+
"../../src/routes/index.ts",
127+
],
128+
}),
129+
};
130+
const results = runPlugin(bundle, {
131+
virtualIds: ["#nitro/virtual/app", "#virtual-route"],
132+
});
133+
expect(results["_chunks/app.mjs.map"].sources).toEqual([
134+
"virtual:#nitro/virtual/app",
135+
"virtual:#virtual-route",
136+
"virtual:nitro:raw:/workspace/app/server/files/test.txt.js",
137+
"../../src/routes/index.ts",
138+
]);
139+
});
140+
141+
it("keeps sourcesContent when minify is disabled", () => {
142+
const bundle = {
143+
"index.mjs.map": createSourcemapAsset({
144+
sources: ["../../workspace/app/#nitro/virtual/app"],
145+
sourcesContent: ["export default 42;"],
146+
}),
147+
};
148+
const results = runPlugin(bundle, {
149+
virtualIds: ["#nitro/virtual/app"],
150+
minify: false,
151+
});
152+
expect(results["index.mjs.map"].sourcesContent).toEqual(["export default 42;"]);
153+
expect(results["index.mjs.map"].sources).toEqual(["virtual:#nitro/virtual/app"]);
154+
});
112155
});

0 commit comments

Comments
 (0)