Skip to content

Commit 0664476

Browse files
fix: workaround vite treating npm: as built-ins (#3205)
Upstream fix: vitejs/vite#20558
1 parent a084a2c commit 0664476

6 files changed

Lines changed: 143 additions & 39 deletions

File tree

deno.lock

Lines changed: 13 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/plugin-vite/src/mod.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { devServer } from "./plugins/dev_server.ts";
1212
import { buildIdPlugin } from "./plugins/build_id.ts";
1313
import { clientSnapshot } from "./plugins/client_snapshot.ts";
1414
import { serverSnapshot } from "./plugins/server_snapshot.ts";
15-
import { commonjs } from "./plugins/commonjs.ts";
15+
import { patches } from "./plugins/patches.ts";
1616

1717
export function fresh(config?: FreshViteConfig): Plugin[] {
1818
const fConfig: ResolvedFreshViteConfig = {
@@ -109,7 +109,7 @@ export function fresh(config?: FreshViteConfig): Plugin[] {
109109
fConfig.routeDir = pathWithRoot(fConfig.routeDir, config.root);
110110
},
111111
},
112-
commonjs(),
112+
patches(),
113113
serverEntryPlugin(fConfig),
114114
...serverSnapshot(fConfig),
115115
clientEntryPlugin(),

packages/plugin-vite/src/plugins/commonjs.ts

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,7 @@
1-
import type { Plugin } from "vite";
2-
import * as babel from "@babel/core";
3-
4-
export function commonjs(): Plugin {
5-
return {
6-
name: "cjs",
7-
applyToEnvironment() {
8-
return true;
9-
},
10-
transform(code, id) {
11-
const res = babel.transformSync(code, {
12-
filename: id,
13-
babelrc: false,
14-
plugins: [cjsPlugin],
15-
});
16-
17-
if (res?.code) {
18-
return {
19-
code: res.code,
20-
map: res.map,
21-
};
22-
}
23-
},
24-
};
25-
}
1+
import type { types } from "@babel/core";
262

273
export function cjsPlugin(
28-
{ types: t }: { types: typeof babel.types },
4+
{ types: t }: { types: typeof types },
295
): babel.PluginObj {
306
const HAS_ES_MODULE = "esModule";
317
const REQUIRE_CALLS = "requireCalls";
@@ -143,16 +119,16 @@ export function cjsPlugin(
143119
}
144120

145121
function isModuleExports(
146-
t: typeof babel.types,
147-
node: babel.types.MemberExpression,
122+
t: typeof types,
123+
node: types.MemberExpression,
148124
): boolean {
149125
return t.isIdentifier(node.object) && node.object.name === "module" &&
150126
t.isIdentifier(node.property) && node.property.name === "exports";
151127
}
152128

153129
function getExportsAssignName(
154-
t: typeof babel.types,
155-
node: babel.types.MemberExpression,
130+
t: typeof types,
131+
node: types.MemberExpression,
156132
): string | null {
157133
if (
158134
(t.isMemberExpression(node.object) &&
@@ -170,8 +146,8 @@ function getExportsAssignName(
170146
* Detect `exports.__esModule = true;`
171147
*/
172148
function isEsModuleFlag(
173-
t: typeof babel.types,
174-
node: babel.types.AssignmentExpression,
149+
t: typeof types,
150+
node: types.AssignmentExpression,
175151
): boolean {
176152
if (!t.isMemberExpression(node.left)) return false;
177153

@@ -187,8 +163,8 @@ function isEsModuleFlag(
187163
* Check for `Object.defineProperty(exports, '__esModule', { value: true })`
188164
*/
189165
function isObjEsModuleFlag(
190-
t: typeof babel.types,
191-
node: babel.types.CallExpression,
166+
t: typeof types,
167+
node: types.CallExpression,
192168
): boolean {
193169
return t.isMemberExpression(node.callee) &&
194170
t.isIdentifier(node.callee.object) &&
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import type { types } from "@babel/core";
2+
3+
// Workaround until upstream PR is merged and released,
4+
// see: https://github.com/vitejs/vite/pull/20558
5+
export function npmWorkaround(
6+
{ types: t }: { types: typeof types },
7+
): babel.PluginObj {
8+
return {
9+
name: "fresh-npm-workaround",
10+
visitor: {
11+
ImportDeclaration(path) {
12+
const source = path.node.source;
13+
if (source.value.startsWith("npm:")) {
14+
source.value = `deno-${source.value}`;
15+
}
16+
},
17+
ExportNamedDeclaration(path) {
18+
const source = path.node.source;
19+
if (source === null || source === undefined) return;
20+
21+
if (source.value.startsWith("npm:")) {
22+
source.value = `deno-${source.value}`;
23+
}
24+
},
25+
CallExpression(path) {
26+
if (!t.isImport(path.node.callee)) return;
27+
if (path.node.arguments.length < 1) return;
28+
29+
const source = path.node.arguments[0];
30+
if (t.isStringLiteral(source)) {
31+
if (source.value.startsWith("npm:")) {
32+
source.value = `deno-${source.value}`;
33+
return;
34+
}
35+
}
36+
},
37+
},
38+
};
39+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { expect } from "@std/expect/expect";
2+
import * as babel from "@babel/core";
3+
import { npmWorkaround } from "./npm_workaround.ts";
4+
5+
function runTest(options: { input: string; expected: string }) {
6+
const res = babel.transformSync(options.input, {
7+
filename: "foo.js",
8+
babelrc: false,
9+
plugins: [npmWorkaround],
10+
});
11+
12+
const output = res?.code ?? "";
13+
expect(output).toEqual(options.expected);
14+
}
15+
16+
Deno.test("npm workaround - import declaration", () => {
17+
runTest({
18+
input: `import * as foo from "npm:foo";
19+
import foo2 from "npm:foo";
20+
import { bar } from "npm:foo";
21+
import baz, { bar2 } from "npm:foo";`,
22+
expected: `import * as foo from "deno-npm:foo";
23+
import foo2 from "deno-npm:foo";
24+
import { bar } from "deno-npm:foo";
25+
import baz, { bar2 } from "deno-npm:foo";`,
26+
});
27+
});
28+
29+
Deno.test("npm workaround - export declaration", () => {
30+
runTest({
31+
input: `export * as foo from "npm:foo";
32+
export { bar } from "npm:foo";`,
33+
expected: `export * as foo from "deno-npm:foo";
34+
export { bar } from "deno-npm:foo";`,
35+
});
36+
});
37+
38+
Deno.test("npm workaround - import()", () => {
39+
runTest({
40+
input: `import("npm:foo");
41+
import("npm:foo", { type: "json" })`,
42+
expected: `import("deno-npm:foo");
43+
import("deno-npm:foo", {
44+
type: "json"
45+
});`,
46+
});
47+
});
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import type { Plugin } from "vite";
2+
import * as babel from "@babel/core";
3+
import { cjsPlugin } from "./commonjs.ts";
4+
import { npmWorkaround } from "./npm_workaround.ts";
5+
6+
export function patches(): Plugin {
7+
return {
8+
name: "fresh:patches",
9+
applyToEnvironment() {
10+
return true;
11+
},
12+
resolveId(id) {
13+
if (id.startsWith("deno-npm:")) {
14+
return id.slice("deno-".length);
15+
}
16+
},
17+
transform(code, id) {
18+
const res = babel.transformSync(code, {
19+
filename: id,
20+
babelrc: false,
21+
plugins: [npmWorkaround, cjsPlugin],
22+
});
23+
24+
if (res?.code) {
25+
return {
26+
code: res.code,
27+
map: res.map,
28+
};
29+
}
30+
},
31+
};
32+
}

0 commit comments

Comments
 (0)