Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support WebAssembly modules #8031

Merged
merged 30 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
118ac28
Scaffold playground
jamesopstad Jan 29, 2025
84a3e55
Prisma process issue
jamesopstad Jan 30, 2025
ba7c010
Externalized wasm imports
jamesopstad Feb 4, 2025
c49d5fb
Emitted modules as assets and replaced import paths
jamesopstad Feb 4, 2025
e4ba332
Added test to wasm playground
jamesopstad Feb 4, 2025
936c578
Resolved relative import paths and added Prisma test
jamesopstad Feb 4, 2025
97e86af
Added setup scripts to Prisma tests
jamesopstad Feb 4, 2025
ee176d5
Used pluginConfig to apply module plugin only to Worker environments
jamesopstad Feb 4, 2025
105b6b6
Added dev support
jamesopstad Feb 4, 2025
c9b9630
Fix lock file
jamesopstad Feb 4, 2025
4adbd0e
Removed replacements for chunk.imports and chunk.importedBindings
jamesopstad Feb 4, 2025
1a5336d
Added build target
jamesopstad Feb 4, 2025
1154cbd
Replace database_id
jamesopstad Feb 4, 2025
24ac98b
Tidy up playground files
jamesopstad Feb 4, 2025
064a4a9
Used RegExp.test rather than RegExp.exec where appropriate
jamesopstad Feb 4, 2025
2f941ae
Added error messages for assertions
jamesopstad Feb 4, 2025
3ac142a
Made error messages mroe consistent
jamesopstad Feb 4, 2025
ebc0920
Added changeset
jamesopstad Feb 4, 2025
6a307c1
Added extra comments
jamesopstad Feb 5, 2025
9f8a4f3
Added prisma generate to postinstall script
jamesopstad Feb 5, 2025
41f55a3
Try using normalizePath to fix import paths on Windows
jamesopstad Feb 5, 2025
d5188e0
Move vite.normalizePath
jamesopstad Feb 5, 2025
a306aae
PR feedback
jamesopstad Feb 7, 2025
72791e7
Moved modules plugin into index.ts
jamesopstad Feb 7, 2025
541410c
Additional comments
jamesopstad Feb 7, 2025
23a126c
Use rawSpecifier instead of specifier in module fallback service
jamesopstad Feb 7, 2025
09df9d1
Fix lock file
jamesopstad Feb 7, 2025
2c2bf54
Use predev and prebuild hooks for Prisma generate
jamesopstad Feb 10, 2025
57ed257
Use nullish coalescing assignment
jamesopstad Feb 10, 2025
d4c4077
Remove Uint8Array check
jamesopstad Feb 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/wild-schools-kiss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudflare/vite-plugin": minor
---

Add support for Wasm (WebAssembly) modules.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
# Keep environment variables out of version control
.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { expect, test } from "vitest";
import { getJsonResponse } from "../../__test-utils__";

// Need to remove the `.wrangler` directory and run the following commands before the tests.
// I'm not sure how to do this with our testing setup so have skipped the test for now.
// const commands = [
// `pnpm wrangler d1 migrations apply prisma-demo-db --local`,
// `pnpm wrangler d1 execute prisma-demo-db --command "INSERT INTO \"User\" (\"email\", \"name\") VALUES ('[email protected]', 'Jane Doe (Local)');" --local`,
// ];

test.skip("runs D1 query using Prisma", async () => {
const result = await getJsonResponse();
expect(result).toEqual([
{ id: 1, email: "[email protected]", name: "Jane Doe (Local)" },
]);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- CreateTable
CREATE TABLE "User" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"email" TEXT NOT NULL,
"name" TEXT
);

-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
27 changes: 27 additions & 0 deletions packages/vite-plugin-cloudflare/playground/prisma/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@playground/prisma",
"private": true,
"type": "module",
"scripts": {
"prebuild": "pnpm generate",
"build": "vite build --app",
"check:types": "tsc --build",
"predev": "pnpm generate",
"dev": "vite dev",
"generate": "pnpm prisma generate",
"migrate-db": "pnpm wrangler d1 migrations apply prisma-demo-db --local",
"preview": "vite preview",
"seed-db": "pnpm wrangler d1 execute prisma-demo-db --command \"INSERT INTO \"User\" (\"email\", \"name\") VALUES ('[email protected]', 'Jane Doe (Local)');\" --local"
},
"devDependencies": {
"@cloudflare/vite-plugin": "workspace:*",
"@cloudflare/workers-tsconfig": "workspace:*",
"@cloudflare/workers-types": "^4.20250121.0",
"@prisma/adapter-d1": "^6.3.0",
"@prisma/client": "^6.3.0",
"prisma": "^6.3.0",
"typescript": "catalog:default",
"vite": "catalog:vite-plugin",
"wrangler": "catalog:vite-plugin"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"]
// Default output directory does not work with Vite. See https://github.com/vitejs/vite/issues/19036#issuecomment-2558791944
output = "../node_modules/@prisma/client-generated"
}

datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}
16 changes: 16 additions & 0 deletions packages/vite-plugin-cloudflare/playground/prisma/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { PrismaD1 } from "@prisma/adapter-d1";
import { PrismaClient } from "@prisma/client-generated";

interface Env {
DB: D1Database;
}

export default {
async fetch(request, env) {
const adapter = new PrismaD1(env.DB);
const prisma = new PrismaClient({ adapter });
const users = await prisma.user.findMany();

return Response.json(users);
},
} satisfies ExportedHandler<Env>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.node.json" },
{ "path": "./tsconfig.worker.json" }
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": ["@cloudflare/workers-tsconfig/base.json"],
"include": ["vite.config.ts", "__tests__"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": ["@cloudflare/workers-tsconfig/worker.json"],
"include": ["src"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "http://turbo.build/schema.json",
"extends": ["//"],
"tasks": {
"build": {
"outputs": ["dist/**"]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { cloudflare } from "@cloudflare/vite-plugin";
import { defineConfig } from "vite";

export default defineConfig({
plugins: [cloudflare()],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name = "worker"
main = "./src/index.ts"
compatibility_date = "2024-12-30"
compatibility_flags = ["nodejs_compat"]

[[d1_databases]]
binding = "DB"
database_name = "prisma-demo-db"
database_id = "local"
11 changes: 11 additions & 0 deletions packages/vite-plugin-cloudflare/playground/wasm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# WebAssembly Playground

The `minimal.wasm` file in the `src` directory was generated from the following C code:

```c
#include <stdint.h>

int32_t add(int32_t a, int32_t b) {
return a + b;
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { expect, test } from "vitest";
import { getJsonResponse } from "../../__test-utils__";

test("imports and instantiates WebAssembly", async () => {
const result = await getJsonResponse();
expect(result).toEqual({ result: 7 });
});
19 changes: 19 additions & 0 deletions packages/vite-plugin-cloudflare/playground/wasm/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "@playground/wasm",
"private": true,
"type": "module",
"scripts": {
"build": "vite build --app",
"check:types": "tsc --build",
"dev": "vite dev",
"preview": "vite preview"
},
"devDependencies": {
"@cloudflare/vite-plugin": "workspace:*",
"@cloudflare/workers-tsconfig": "workspace:*",
"@cloudflare/workers-types": "^4.20250121.0",
"typescript": "catalog:default",
"vite": "catalog:vite-plugin",
"wrangler": "catalog:vite-plugin"
}
}
10 changes: 10 additions & 0 deletions packages/vite-plugin-cloudflare/playground/wasm/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import wasm from "./minimal.wasm";

export default {
async fetch() {
const instance = await WebAssembly.instantiate(wasm);
const result = instance.exports.add(3, 4);

return Response.json({ result });
},
} satisfies ExportedHandler;
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.node.json" },
{ "path": "./tsconfig.worker.json" }
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": ["@cloudflare/workers-tsconfig/base.json"],
"include": ["vite.config.ts", "__tests__"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": ["@cloudflare/workers-tsconfig/worker.json"],
"include": ["src"]
}
9 changes: 9 additions & 0 deletions packages/vite-plugin-cloudflare/playground/wasm/turbo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "http://turbo.build/schema.json",
"extends": ["//"],
"tasks": {
"build": {
"outputs": ["dist/**"]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { cloudflare } from "@cloudflare/vite-plugin";
import { defineConfig } from "vite";

export default defineConfig({
plugins: [cloudflare({ persistState: false })],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name = "worker"
main = "./src/index.ts"
compatibility_date = "2024-12-30"
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ const cloudflareBuiltInModules = [
"cloudflare:workflows",
];

const defaultConditions = ["workerd", "module", "browser"];

export function createCloudflareEnvironmentOptions(
workerConfig: WorkerConfig,
userConfig: vite.UserConfig,
Expand All @@ -131,7 +133,7 @@ export function createCloudflareEnvironmentOptions(
// dependencies as not external
noExternal: true,
// We want to use `workerd` package exports if available (e.g. for postgres).
conditions: ["workerd", "module", "browser", "development|production"],
conditions: [...defaultConditions, "development|production"],
},
dev: {
createEnvironment(name, config) {
Expand All @@ -142,6 +144,9 @@ export function createCloudflareEnvironmentOptions(
createEnvironment(name, config) {
return new vite.BuildEnvironment(name, config);
},
target: "es2022",
// We need to enable `emitAssets` in order to support additional modules defined by `rules`
emitAssets: true,
outDir: getOutputDirectory(userConfig, environmentName),
ssr: true,
rollupOptions: {
Expand All @@ -163,6 +168,7 @@ export function createCloudflareEnvironmentOptions(
],
esbuildOptions: {
platform: "neutral",
conditions: [...defaultConditions, "development"],
resolveExtensions: [
".mjs",
".js",
Expand Down
3 changes: 3 additions & 0 deletions packages/vite-plugin-cloudflare/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export const ROUTER_WORKER_NAME = "__router-worker__";
export const ASSET_WORKER_NAME = "__asset-worker__";
export const ASSET_WORKERS_COMPATIBILITY_DATE = "2024-10-04";
// TODO: add `Text` and `Data` types (resolves https://github.com/cloudflare/workers-sdk/issues/8022)
export const MODULE_TYPES = ["CompiledWasm"] as const;
jamesopstad marked this conversation as resolved.
Show resolved Hide resolved
export type ModuleType = (typeof MODULE_TYPES)[number];
Loading
Loading