Skip to content

Commit 6d773f6

Browse files
authored
fix: Fix WASM support + Prisma >6.7 support (#463)
## Context Takes several changes from #457 for us to use to fix general WASM support. * We had configuration for supporting Prisma WASM, most of which predated our move to `@cloudflare/vite-plugin`, or were around in the early stages while the CF team were still working on WASM support in the plugin. `@cloudflare/vite-plugin` is now able to support WASM without these hacks and workarounds * Those workarounds we had also accidentally prevented us from using any other packages that had WASM in them * With these changes, we now should be able to support **both Prisma <6.7 and >6.7**, as well as unblock supporting other packages that have WASM * **note:** While Prisma >6.7 is supported, if you're is using the new `prisma-client` generator and `pnpm`, there is an edge case with a fix (cloudflare/workers-sdk#9322) that first needs to be released * We'll also be updating the standard starter to use >6.7 Prisma once this same fix has been released and we have upgraded `@cloudflare/vite-plugin` ## Other changes * Also upgrades * @cloudflare/vite-plugin:1.1.0 -> 0.0.0.0-1bae8618b (so we can use cloudflare/workers-sdk#9322 already) * wrangler:4.14.1 -> 4.16.0
1 parent a038c32 commit 6d773f6

13 files changed

+592
-243
lines changed

pnpm-lock.yaml

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

sdk/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "rwsdk",
3-
"version": "0.0.84",
3+
"version": "0.0.84-test.20250522015638",
44
"description": "Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime",
55
"type": "module",
66
"bin": {
@@ -99,7 +99,7 @@
9999
"author": "RedwoodSDK <peter@redwoodjs.com>",
100100
"license": "MIT",
101101
"dependencies": {
102-
"@cloudflare/vite-plugin": "^1.1.0",
102+
"@cloudflare/vite-plugin": "0.0.0-1bae8618b",
103103
"@cloudflare/workers-types": "^4.20250407.0",
104104
"@puppeteer/browsers": "^2.8.0",
105105
"@types/fs-extra": "^11.0.4",
@@ -130,7 +130,7 @@
130130
"unique-names-generator": "^4.7.1",
131131
"vibe-rules": "^0.2.31",
132132
"vite-tsconfig-paths": "^5.1.4",
133-
"wrangler": "^4.14.1"
133+
"wrangler": "^4.16.0"
134134
},
135135
"peerDependencies": {
136136
"vite": "^6.2.6"

sdk/src/vite/checkIsUsingPrisma.mts

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
11
import enhancedResolve from "enhanced-resolve";
22

3-
export const checkIsUsingPrisma = ({
4-
projectRootDir,
5-
}: {
6-
projectRootDir: string;
7-
}) => {
3+
export type PrismaCheckResult = {
4+
isUsingPrisma: boolean;
5+
};
6+
7+
const isUsingPrisma = ({ projectRootDir }: { projectRootDir: string }) => {
88
try {
9-
return Boolean(enhancedResolve.sync(projectRootDir, "@prisma/client"));
9+
const prismaClientPath = enhancedResolve.sync(
10+
projectRootDir,
11+
"@prisma/client",
12+
);
13+
if (!prismaClientPath) {
14+
return false;
15+
}
16+
return true;
1017
} catch {
1118
return false;
1219
}
1320
};
21+
22+
export const checkPrismaStatus = ({
23+
projectRootDir,
24+
}: {
25+
projectRootDir: string;
26+
}): PrismaCheckResult => {
27+
return {
28+
isUsingPrisma: isUsingPrisma({ projectRootDir }),
29+
};
30+
};

sdk/src/vite/configPlugin.mts

Lines changed: 4 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Plugin } from "vite";
22
import { resolve } from "node:path";
33
import { mergeConfig, InlineConfig } from "vite";
4+
import { PrismaCheckResult } from "./checkIsUsingPrisma.mjs";
45

56
const ignoreVirtualModules = {
67
name: "rwsdk:ignore-virtual-modules",
@@ -17,14 +18,12 @@ export const configPlugin = ({
1718
projectRootDir,
1819
clientEntryPathname,
1920
workerEntryPathname,
20-
isUsingPrisma,
2121
}: {
2222
mode: "development" | "production";
2323
silent: boolean;
2424
projectRootDir: string;
2525
clientEntryPathname: string;
2626
workerEntryPathname: string;
27-
isUsingPrisma: boolean;
2827
}): Plugin => ({
2928
name: "rwsdk:config",
3029
config: (_, { command }) => {
@@ -67,29 +66,7 @@ export const configPlugin = ({
6766
noDiscovery: false,
6867
esbuildOptions: {
6968
conditions: ["workerd", "react-server"],
70-
plugins: [
71-
...(isUsingPrisma
72-
? [
73-
{
74-
name: "rwsdk:prisma-client-wasm",
75-
setup(build: any) {
76-
build.onResolve(
77-
{ filter: /.prisma\/client\/default/ },
78-
async (args: any) => {
79-
return {
80-
path: resolve(
81-
projectRootDir,
82-
"node_modules/.prisma/client/wasm.js",
83-
),
84-
};
85-
},
86-
);
87-
},
88-
},
89-
]
90-
: []),
91-
ignoreVirtualModules,
92-
],
69+
plugins: [ignoreVirtualModules],
9370
},
9471
include: [
9572
"react/jsx-runtime",
@@ -118,16 +95,7 @@ export const configPlugin = ({
11895
},
11996
resolve: {
12097
conditions: ["workerd"],
121-
alias: {
122-
...(isUsingPrisma
123-
? {
124-
".prisma/client/default": resolve(
125-
projectRootDir,
126-
"node_modules/.prisma/client/wasm.js",
127-
),
128-
}
129-
: {}),
130-
},
98+
alias: [],
13199
},
132100
};
133101

@@ -137,7 +105,7 @@ export const configPlugin = ({
137105
worker: {
138106
build: {
139107
rollupOptions: {
140-
external: ["cloudflare:workers", "node:stream", /\.wasm$/],
108+
external: ["cloudflare:workers", "node:stream"],
141109
},
142110
},
143111
},

sdk/src/vite/copyPrismaWasmPlugin.mts

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

sdk/src/vite/ensureAliasArray.mts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { Alias, UserConfig } from "vite";
2+
3+
export const ensureAliasArray = (config: UserConfig): Alias[] => {
4+
config.resolve ??= {};
5+
6+
if (!config.resolve?.alias) {
7+
config.resolve.alias = [];
8+
} else if (!Array.isArray(config.resolve.alias)) {
9+
const existingAlias = config.resolve.alias;
10+
config.resolve.alias = Object.entries(existingAlias).map(
11+
([find, replacement]) => ({ find, replacement }),
12+
);
13+
}
14+
15+
return config.resolve.alias as Alias[];
16+
};

sdk/src/vite/moveStaticAssetsPlugin.mts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ export const moveStaticAssetsPlugin = ({
1414
if (this.environment.name === "worker") {
1515
await $sh({
1616
cwd: rootDir,
17-
})`mv dist/worker/assets/* dist/client/assets || true`;
18-
await $sh({ cwd: rootDir })`rmdir dist/worker/assets || true`;
17+
})`mv dist/worker/assets/*.css dist/client/assets/ || true`;
1918
}
2019
},
2120
});

sdk/src/vite/prismaPlugin.mts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Plugin } from "vite";
2+
import { resolve } from "node:path";
3+
import { invalidateCacheIfPrismaClientChanged } from "./invalidateCacheIfPrismaClientChanged.mjs";
4+
import { checkPrismaStatus } from "./checkIsUsingPrisma.mjs";
5+
import { ensureAliasArray } from "./ensureAliasArray.mjs";
6+
7+
export const prismaPlugin = async ({
8+
projectRootDir,
9+
}: {
10+
projectRootDir: string;
11+
}): Promise<Plugin | undefined> => {
12+
if (!checkPrismaStatus({ projectRootDir }).isUsingPrisma) {
13+
return;
14+
}
15+
16+
// context(justinvdm, 10 Mar 2025): We need to use vite optimizeDeps for all deps to work with @cloudflare/vite-plugin.
17+
// Thing is, @prisma/client has generated code. So users end up with a stale @prisma/client
18+
// when they change their prisma schema and regenerate the client, until clearing out node_modules/.vite
19+
// We can't exclude @prisma/client from optimizeDeps since we need it there for @cloudflare/vite-plugin to work.
20+
// But we can manually invalidate the cache if the prisma schema changes.
21+
await invalidateCacheIfPrismaClientChanged({
22+
projectRootDir,
23+
});
24+
25+
return {
26+
name: "rwsdk:prisma",
27+
configEnvironment(name, config) {
28+
if (name !== "worker") {
29+
return;
30+
}
31+
32+
const wasmPath = resolve(
33+
projectRootDir,
34+
"node_modules/.prisma/client/wasm.js",
35+
);
36+
37+
config.optimizeDeps ??= {};
38+
config.optimizeDeps.esbuildOptions ??= {};
39+
config.optimizeDeps.esbuildOptions.plugins ??= [];
40+
41+
config.optimizeDeps.esbuildOptions.plugins.push({
42+
name: "rwsdk:prisma",
43+
setup(build: any) {
44+
build.onResolve({ filter: /^.prisma\/client\/default/ }, async () => {
45+
return {
46+
path: wasmPath,
47+
};
48+
});
49+
},
50+
});
51+
52+
ensureAliasArray(config).push({
53+
find: /^\.prisma\/client\/default/,
54+
replacement: wasmPath,
55+
});
56+
},
57+
};
58+
};

sdk/src/vite/reactConditionsResolverPlugin.mts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { pathExists } from "fs-extra";
66
import enhancedResolve from "enhanced-resolve";
77
import { VENDOR_DIST_DIR } from "../lib/constants.mjs";
88
import { createRequire } from "node:module";
9+
import { ensureAliasArray } from "./ensureAliasArray.mjs";
10+
911
const log = debug("rwsdk:vite:react-conditions");
1012

1113
// Define package sets for each environment
@@ -168,14 +170,7 @@ export const reactConditionsResolverPlugin = async ({
168170

169171
config.resolve ??= {};
170172

171-
(config.resolve as any).alias ??= [];
172-
173-
if (!Array.isArray((config.resolve as any).alias)) {
174-
const existingAlias = (config.resolve as any).alias;
175-
(config.resolve as any).alias = Object.entries(existingAlias).map(
176-
([find, replacement]) => ({ find, replacement }),
177-
);
178-
}
173+
ensureAliasArray(config);
179174

180175
Object.entries(imports).forEach(([id, resolvedPath]) => {
181176
const exactMatchRegex = new RegExp(

sdk/src/vite/redwoodPlugin.mts

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,15 @@ import { useServerPlugin } from "./useServerPlugin.mjs";
99
import { useClientPlugin } from "./useClientPlugin.mjs";
1010
import { useClientLookupPlugin } from "./useClientLookupPlugin.mjs";
1111
import { miniflarePlugin } from "./miniflarePlugin.mjs";
12-
import { copyPrismaWasmPlugin } from "./copyPrismaWasmPlugin.mjs";
1312
import { moveStaticAssetsPlugin } from "./moveStaticAssetsPlugin.mjs";
1413
import { configPlugin } from "./configPlugin.mjs";
1514
import { $ } from "../lib/$.mjs";
1615
import { reactConditionsResolverPlugin } from "./reactConditionsResolverPlugin.mjs";
17-
import { invalidateCacheIfPrismaClientChanged } from "./invalidateCacheIfPrismaClientChanged.mjs";
1816
import { findWranglerConfig } from "../lib/findWranglerConfig.mjs";
1917
import { pathExists } from "fs-extra";
2018
import { injectVitePreamble } from "./injectVitePreamblePlugin.mjs";
2119
import { vitePreamblePlugin } from "./vitePreamblePlugin.mjs";
22-
import { checkIsUsingPrisma } from "./checkIsUsingPrisma.mjs";
20+
import { prismaPlugin } from "./prismaPlugin.mjs";
2321

2422
export type RedwoodPluginOptions = {
2523
silent?: boolean;
@@ -64,26 +62,13 @@ export const redwoodPlugin = async (
6462
stdio: ["ignore", "inherit", "inherit"],
6563
})`npm run dev:init`;
6664
}
67-
68-
const isUsingPrisma = checkIsUsingPrisma({ projectRootDir });
69-
70-
// context(justinvdm, 10 Mar 2025): We need to use vite optimizeDeps for all deps to work with @cloudflare/vite-plugin.
71-
// Thing is, @prisma/client has generated code. So users end up with a stale @prisma/client
72-
// when they change their prisma schema and regenerate the client, until clearing out node_modules/.vite
73-
// We can't exclude @prisma/client from optimizeDeps since we need it there for @cloudflare/vite-plugin to work.
74-
// But we can manually invalidate the cache if the prisma schema changes.
75-
await invalidateCacheIfPrismaClientChanged({
76-
projectRootDir,
77-
});
78-
7965
return [
8066
configPlugin({
8167
mode,
8268
silent: options.silent ?? false,
8369
projectRootDir,
8470
clientEntryPathname,
8571
workerEntryPathname,
86-
isUsingPrisma,
8772
}),
8873
reactConditionsResolverPlugin({ projectRootDir, mode }),
8974
tsconfigPaths({ root: projectRootDir }),
@@ -112,9 +97,7 @@ export const redwoodPlugin = async (
11297
"manifest.json",
11398
),
11499
}),
115-
...(isUsingPrisma
116-
? [copyPrismaWasmPlugin({ rootDir: projectRootDir })]
117-
: []),
118100
moveStaticAssetsPlugin({ rootDir: projectRootDir }),
101+
prismaPlugin({ projectRootDir }),
119102
];
120103
};

starters/minimal/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"types": "tsc"
2323
},
2424
"dependencies": {
25-
"rwsdk": "0.0.84"
25+
"rwsdk": "0.0.84-test.20250522015638"
2626
},
2727
"devDependencies": {
2828
"@types/node": "^22.14.0",

starters/standard/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"@prisma/client": "~6.5.0",
3232
"@simplewebauthn/browser": "^13.1.0",
3333
"@simplewebauthn/server": "^13.1.1",
34-
"rwsdk": "0.0.84"
34+
"rwsdk": "0.0.84-test.20250522015638"
3535
},
3636
"devDependencies": {
3737
"@types/node": "^22.14.0",

starters/standard/src/scripts/seed.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { defineScript } from "rwsdk/worker";
2-
import { db } from "@/db";
2+
import { db, setupDb } from "@/db";
33

44
export default defineScript(async () => {
5+
await setupDb();
6+
57
await db.$executeRawUnsafe(`\
68
DELETE FROM User;
79
DELETE FROM sqlite_sequence;

0 commit comments

Comments
 (0)