Repository: cloudflare/workers-sdk
Pull request #8356: Support dynamic import paths in preview mode
Author: login: jamesopstad
Labels: name: vite-plugin
description: Relating to the `@cloudflare/vite-plugin` package
Created: 2025-03-05T08:40:34Z | Merged: 2025-03-05T20:18:51Z

Fixes #8317

This adds support for dynamic import paths in preview mode by using the `rules` to populate the `modules` array.

---

<!--
Please don't delete the checkboxes <3
The following selections do not need to be completed if this PR only contains changes to .md files
-->

- Tests
  - [ ] TODO (before merge)
  - [x] Tests included
  - [ ] Tests not necessary because:
- Wrangler E2E Tests CI Job required? (Use "e2e" label or ask maintainer to run separately)
  - [ ] I don't know
  - [ ] Required
  - [x] Not required because: N/A
- Public documentation
  - [ ] TODO (before merge)
  - [ ] Cloudflare docs PR(s): <!--e.g. <https://github.com/cloudflare/cloudflare-docs/pull/>...-->
  - [x] Documentation not necessary because: N/A

<!--
Have you read our [Contributing guide](https://github.com/cloudflare/workers-sdk/blob/main/CONTRIBUTING.md)?
In particular, for non-trivial changes, please always engage on the issue or create a discussion or feature request issue first before writing your code.
-->


Linked issue #8317: 🐛 BUG: vite preview fails if Worker uses dynamic imports
### Which Cloudflare product(s) does this pertain to?

Vite Plugin

### What versions are you using?

0.1.7 [@cloudflare/vite-plugin]

### What operating system and version are you using?

MacOS

### Please provide a link to a minimal reproduction

https://github.com/zebp/vite-dynamic-modules

### Describe the Bug

If you attempt to start Vite's preview server with `vite preview` and your Worker uses the `import` function with a dynamic path Miniflare will throw an error causing the preview to crash since Miniflare requires all paths to be explicitly defined in preview rules. A potential fix could be explicitly defining module rules by walking the build output?

### Please provide any relevant error logs

```
/Users/zeb/experiments/vite-dynamic-modules/node_modules/.pnpm/miniflare@3.20250214.1/node_modules/miniflare/dist/src/index.js:10028
      throw new MiniflareCoreError("ERR_MODULE_DYNAMIC_SPEC", message);
            ^

MiniflareCoreError [ERR_MODULE_DYNAMIC_SPEC]: Unable to resolve "dist/vite_dynamic_modules/index.js" dependency: dynamic module specifiers are unsupported.
You must manually define your modules when constructing Miniflare:
  new Miniflare({
    ...,
    modules: [
      { type: "ESModule", path: "dist/vite_dynamic_modules/index.js" },
      ...
    ]
  })
    at /Users/zeb/experiments/vite-dynamic-modules/dist/vite_dynamic_modules/index.js:4:29
    at #visitModule (/Users/zeb/experiments/vite-dynamic-modules/node_modules/.pnpm/miniflare@3.20250214.1/node_modules/miniflare/dist/src/index.js:10028:13)
    at Object.ImportExpression (/Users/zeb/experiments/vite-dynamic-modules/node_modules/.pnpm/miniflare@3.20250214.1/node_modules/miniflare/dist/src/index.js:9995:26)
    at c (/Users/zeb/experiments/vite-dynamic-modules/node_modules/.pnpm/acorn-walk@8.3.2/node_modules/acorn-walk/dist/walk.js:30:43)
    at Object.skipThrough (/Users/zeb/experiments/vite-dynamic-modules/node_modules/.pnpm/acorn-walk@8.3.2/node_modules/acorn-walk/dist/walk.js:186:39)
    at c (/Users/zeb/experiments/vite-dynamic-modules/node_modules/.pnpm/acorn-walk@8.3.2/node_modules/acorn-walk/dist/walk.js:29:24)
    at base.ReturnStatement.base.YieldExpression.base.AwaitExpression (/Users/zeb/experiments/vite-dynamic-modules/node_modules/.pnpm/acorn-walk@8.3.2/node_modules/acorn-walk/dist/walk.js:240:26)
    at c (/Users/zeb/experiments/vite-dynamic-modules/node_modules/.pnpm/acorn-walk@8.3.2/node_modules/acorn-walk/dist/walk.js:29:24)
    at Object.skipThrough (/Users/zeb/experiments/vite-dynamic-modules/node_modules/.pnpm/acorn-walk@8.3.2/node_modules/acorn-walk/dist/walk.js:186:39)
    at c (/Users/zeb/experiments/vite-dynamic-modules/node_modules/.pnpm/acorn-walk@8.3.2/node_modules/acorn-walk/dist/walk.js:29:24)
    at base.VariableDeclarator (/Users/zeb/experiments/vite-dynamic-modules/node_modules/.pnpm/acorn-walk@8.3.2/node_modules/acorn-walk/dist/walk.js:285:22) {
  code: 'ERR_MODULE_DYNAMIC_SPEC',
  cause: undefined
}
```
Linked issue comments: user: login: petebacondarwin
created_at: 2025-03-03T10:08:45Z
body: Thanks for the report @zebp - this is a known issue that @jamesopstad is working on fixing.
author_association: CONTRIBUTOR

Diff:
diff --git a/.changeset/giant-breads-taste.md b/.changeset/giant-breads-taste.md
new file mode 100644
index 0000000000..aa313bd8e6
--- /dev/null
+++ b/.changeset/giant-breads-taste.md
@@ -0,0 +1,5 @@
+---
+"@cloudflare/vite-plugin": patch
+---
+
+Support dynamic import paths in preview mode.
diff --git a/packages/vite-plugin-cloudflare/package.json b/packages/vite-plugin-cloudflare/package.json
index 804fbf0cc7..a2d5e399a7 100644
--- a/packages/vite-plugin-cloudflare/package.json
+++ b/packages/vite-plugin-cloudflare/package.json
@@ -45,6 +45,7 @@
 		"@cloudflare/unenv-preset": "1.1.1",
 		"@hattip/adapter-node": "^0.0.49",
 		"miniflare": "workspace:*",
+		"tinyglobby": "^0.2.12",
 		"unenv": "2.0.0-rc.1",
 		"ws": "catalog:default"
 	},
diff --git a/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/__tests__/dynamic-import-paths.spec.ts b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/__tests__/dynamic-import-paths.spec.ts
new file mode 100644
index 0000000000..42a47f0fdd
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/__tests__/dynamic-import-paths.spec.ts
@@ -0,0 +1,13 @@
+import { expect, test } from "vitest";
+import { getJsonResponse, isBuild } from "../../__test-utils__";
+
+test.runIf(isBuild)(
+	"supports imports with both static and dynamic paths in preview",
+	async () => {
+		const result = await getJsonResponse();
+		expect(result).toEqual({
+			staticPathImportResult: "Cloudflare",
+			dynamicPathImportResult: "Cloudflare",
+		});
+	}
+);
diff --git a/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/package.json b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/package.json
new file mode 100644
index 0000000000..6ab29aaa4c
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/package.json
@@ -0,0 +1,19 @@
+{
+	"name": "@playground/dynamic-import-paths",
+	"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.20250214.0",
+		"typescript": "catalog:default",
+		"vite": "catalog:vite-plugin",
+		"wrangler": "catalog:vite-plugin"
+	}
+}
diff --git a/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/src/another.js b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/src/another.js
new file mode 100644
index 0000000000..a2983d31ed
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/src/another.js
@@ -0,0 +1 @@
+export const name = "Cloudflare";
diff --git a/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/src/index.ts b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/src/index.ts
new file mode 100644
index 0000000000..33ee6fc9de
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/src/index.ts
@@ -0,0 +1,12 @@
+export default {
+	async fetch() {
+		const staticPathImport = await import("./another.js");
+		const dynamicPath = "./another.js";
+		const dynamicPathImport = await import(/* @vite-ignore */ dynamicPath);
+
+		return Response.json({
+			staticPathImportResult: staticPathImport.name,
+			dynamicPathImportResult: dynamicPathImport.name,
+		});
+	},
+} satisfies ExportedHandler;
diff --git a/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/tsconfig.json b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/tsconfig.json
new file mode 100644
index 0000000000..b52af703bd
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/tsconfig.json
@@ -0,0 +1,7 @@
+{
+	"files": [],
+	"references": [
+		{ "path": "./tsconfig.node.json" },
+		{ "path": "./tsconfig.worker.json" }
+	]
+}
diff --git a/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/tsconfig.node.json b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/tsconfig.node.json
new file mode 100644
index 0000000000..773be9834a
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/tsconfig.node.json
@@ -0,0 +1,4 @@
+{
+	"extends": ["@cloudflare/workers-tsconfig/base.json"],
+	"include": ["vite.config.ts", "__tests__"]
+}
diff --git a/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/tsconfig.worker.json b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/tsconfig.worker.json
new file mode 100644
index 0000000000..8ce2d78a93
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/tsconfig.worker.json
@@ -0,0 +1,7 @@
+{
+	"extends": ["@cloudflare/workers-tsconfig/worker.json"],
+	"include": ["src"],
+	"compilerOptions": {
+		"allowJs": true
+	}
+}
diff --git a/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/turbo.json b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/turbo.json
new file mode 100644
index 0000000000..6556dcf3e5
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/turbo.json
@@ -0,0 +1,9 @@
+{
+	"$schema": "http://turbo.build/schema.json",
+	"extends": ["//"],
+	"tasks": {
+		"build": {
+			"outputs": ["dist/**"]
+		}
+	}
+}
diff --git a/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/vite.config.ts b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/vite.config.ts
new file mode 100644
index 0000000000..b4a39c2d34
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/vite.config.ts
@@ -0,0 +1,17 @@
+import { cloudflare } from "@cloudflare/vite-plugin";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+	environments: {
+		worker: {
+			build: {
+				rollupOptions: {
+					output: {
+						preserveModules: true,
+					},
+				},
+			},
+		},
+	},
+	plugins: [cloudflare({ persistState: false })],
+});
diff --git a/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/wrangler.toml b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/wrangler.toml
new file mode 100644
index 0000000000..9a44ca3733
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/dynamic-import-paths/wrangler.toml
@@ -0,0 +1,3 @@
+name = "worker"
+main = "./src/index.ts"
+compatibility_date = "2024-12-30"
diff --git a/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts b/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts
index c1e9e0cd02..7b0a597dd5 100644
--- a/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts
+++ b/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts
@@ -17,6 +17,7 @@ export default defineConfig({
 		globalSetup: ["./vitest-global-setup.ts"],
 		reporters: "dot",
 		onConsoleLog: () => false,
+		testTimeout: 10000,
 	},
 	publicDir: false,
 });
diff --git a/packages/vite-plugin-cloudflare/src/index.ts b/packages/vite-plugin-cloudflare/src/index.ts
index af496d74bc..f160fc66eb 100644
--- a/packages/vite-plugin-cloudflare/src/index.ts
+++ b/packages/vite-plugin-cloudflare/src/index.ts
@@ -217,7 +217,7 @@ export function cloudflare(pluginConfig: PluginConfig = {}): vite.Plugin[] {
 				}
 
 				config.no_bundle = true;
-				config.rules = [{ type: "ESModule", globs: ["**/*.js"] }];
+				config.rules = [{ type: "ESModule", globs: ["**/*.js", "**/*.mjs"] }];
 				// Set to `undefined` if it's an empty object so that the user doesn't see a warning about using `unsafe` fields when deploying their Worker.
 				if (config.unsafe && Object.keys(config.unsafe).length === 0) {
 					config.unsafe = undefined;
diff --git a/packages/vite-plugin-cloudflare/src/miniflare-options.ts b/packages/vite-plugin-cloudflare/src/miniflare-options.ts
index 19c7036ee1..efb5dc7eb2 100644
--- a/packages/vite-plugin-cloudflare/src/miniflare-options.ts
+++ b/packages/vite-plugin-cloudflare/src/miniflare-options.ts
@@ -9,6 +9,7 @@ import {
 	LogLevel,
 	Response as MiniflareResponse,
 } from "miniflare";
+import { globSync } from "tinyglobby";
 import * as vite from "vite";
 import {
 	unstable_getMiniflareWorkerOptions,
@@ -29,6 +30,7 @@ import type {
 } from "./plugin-config";
 import type { MiniflareOptions, SharedOptions, WorkerOptions } from "miniflare";
 import type { FetchFunctionOptions } from "vite/module-runner";
+import type { SourcelessWorkerOptions } from "wrangler";
 
 type PersistOptions = Pick<
 	SharedOptions,
@@ -486,6 +488,31 @@ export function getDevMiniflareOptions(
 	};
 }
 
+function getPreviewModules(
+	main: string,
+	modulesRules: SourcelessWorkerOptions["modulesRules"]
+) {
+	assert(modulesRules, `Unexpected error: 'modulesRules' is undefined`);
+	const rootPath = path.dirname(main);
+	const entryPath = path.basename(main);
+
+	return {
+		rootPath,
+		modules: [
+			{
+				type: "ESModule",
+				path: entryPath,
+			} as const,
+			...modulesRules.flatMap(({ type, include }) =>
+				globSync(include, { cwd: rootPath, ignore: entryPath }).map((path) => ({
+					type,
+					path,
+				}))
+			),
+		],
+	} satisfies Pick<WorkerOptions, "rootPath" | "modules">;
+}
+
 export function getPreviewMiniflareOptions(
 	vitePreviewServer: vite.PreviewServer,
 	persistState: PersistState
@@ -499,17 +526,16 @@ export function getPreviewMiniflareOptions(
 	const workers: Array<WorkerOptions> = workerConfigs.map((config) => {
 		const miniflareWorkerOptions = unstable_getMiniflareWorkerOptions(config);
 
-		const { ratelimits, ...workerOptions } =
+		const { ratelimits, modulesRules, ...workerOptions } =
 			miniflareWorkerOptions.workerOptions;
 
 		return {
 			...workerOptions,
 			// We have to add the name again because `unstable_getMiniflareWorkerOptions` sets it to `undefined`
 			name: config.name,
-			modules: true,
 			...(miniflareWorkerOptions.main
-				? { scriptPath: miniflareWorkerOptions.main }
-				: { script: "" }),
+				? getPreviewModules(miniflareWorkerOptions.main, modulesRules)
+				: { modules: true, script: "" }),
 		};
 	});
 
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index bafe115ea9..6487d39537 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1760,6 +1760,9 @@ importers:
       miniflare:
         specifier: workspace:*
         version: link:../miniflare
+      tinyglobby:
+        specifier: ^0.2.12
+        version: 0.2.12
       unenv:
         specifier: 2.0.0-rc.1
         version: 2.0.0-rc.1
@@ -1909,6 +1912,27 @@ importers:
         specifier: catalog:vite-plugin
         version: 3.109.2(@cloudflare/workers-types@4.20250224.0)
 
+  packages/vite-plugin-cloudflare/playground/dynamic-import-paths:
+    devDependencies:
+      '@cloudflare/vite-plugin':
+        specifier: workspace:*
+        version: link:../..
+      '@cloudflare/workers-tsconfig':
+        specifier: workspace:*
+        version: link:../../../workers-tsconfig
+      '@cloudflare/workers-types':
+        specifier: ^4.20250214.0
+        version: 4.20250224.0
+      typescript:
+        specifier: catalog:default
+        version: 5.7.3
+      vite:
+        specifier: catalog:vite-plugin
+        version: 6.1.0(@types/node@18.19.76)(jiti@2.4.2)
+      wrangler:
+        specifier: catalog:vite-plugin
+        version: 3.109.2(@cloudflare/workers-types@4.20250224.0)
+
   packages/vite-plugin-cloudflare/playground/external-durable-objects:
     devDependencies:
       '@cloudflare/vite-plugin':
@@ -7806,14 +7830,6 @@ packages:
   fd-slicer@1.1.0:
     resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
 
-  fdir@6.4.2:
-    resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==}
-    peerDependencies:
-      picomatch: ^3 || ^4
-    peerDependenciesMeta:
-      picomatch:
-        optional: true
-
   fdir@6.4.3:
     resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==}
     peerDependencies:
@@ -10766,10 +10782,6 @@ packages:
   tinyexec@0.3.2:
     resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
 
-  tinyglobby@0.2.10:
-    resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==}
-    engines: {node: '>=12.0.0'}
-
   tinyglobby@0.2.12:
     resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==}
     engines: {node: '>=12.0.0'}
@@ -14162,7 +14174,7 @@ snapshots:
       '@rollup/pluginutils': 5.1.4(rollup@4.30.1)
       commondir: 1.0.1
       estree-walker: 2.0.2
-      fdir: 6.4.2(picomatch@4.0.2)
+      fdir: 6.4.3(picomatch@4.0.2)
       is-reference: 1.2.1
       magic-string: 0.30.17
       picomatch: 4.0.2
@@ -17441,10 +17453,6 @@ snapshots:
     dependencies:
       pend: 1.2.0
 
-  fdir@6.4.2(picomatch@4.0.2):
-    optionalDependencies:
-      picomatch: 4.0.2
-
   fdir@6.4.3(picomatch@4.0.2):
     optionalDependencies:
       picomatch: 4.0.2
@@ -18655,7 +18663,7 @@ snapshots:
       postcss: 8.4.49
       postcss-nested: 7.0.2(postcss@8.4.49)
       semver: 7.7.1
-      tinyglobby: 0.2.10
+      tinyglobby: 0.2.12
     optionalDependencies:
       typescript: 5.7.3
       vue-tsc: 2.0.29(typescript@5.7.3)
@@ -20474,11 +20482,6 @@ snapshots:
 
   tinyexec@0.3.2: {}
 
-  tinyglobby@0.2.10:
-    dependencies:
-      fdir: 6.4.2(picomatch@4.0.2)
-      picomatch: 4.0.2
-
   tinyglobby@0.2.12:
     dependencies:
       fdir: 6.4.3(picomatch@4.0.2)
@@ -20620,7 +20623,7 @@ snapshots:
       rollup: 4.30.1
       source-map: 0.8.0-beta.0
       sucrase: 3.35.0
-      tinyglobby: 0.2.10
+      tinyglobby: 0.2.12
       tree-kill: 1.2.2
     optionalDependencies:
       '@microsoft/api-extractor': 7.49.1(@types/node@18.19.76)
@@ -20799,7 +20802,7 @@ snapshots:
       rollup: 4.30.1
       rollup-plugin-dts: 6.1.1(rollup@4.30.1)(typescript@5.7.3)
       scule: 1.3.0
-      tinyglobby: 0.2.10
+      tinyglobby: 0.2.12
       untyped: 1.5.2
     optionalDependencies:
       typescript: 5.7.3


Reviews:
user: login: jamesopstad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T13:58:54Z
user: login: penalosa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T14:54:49Z
user: login: jamesopstad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T15:16:12Z
user: login: petebacondarwin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T19:55:56Z
user: login: petebacondarwin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T19:57:25Z
user: login: petebacondarwin
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T20:02:46Z
user: login: jamesopstad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T20:15:57Z

Review comments:
diff_hunk: @@ -0,0 +1,13 @@
+import { expect, test } from "vitest";
+import { getJsonResponse, isBuild } from "../../__test-utils__";
+
+test.runIf(isBuild)(
path: packages/vite-plugin-cloudflare/playground/dynamic-import-paths/__tests__/dynamic-import-paths.spec.ts
user: login: jamesopstad
body: I couldn't get this test to pass in dev on Windows and I'm not sure why. Seems like it could possibly be a bug in Vite - https://github.com/vitejs/vite/issues/15258.
created_at: 2025-03-05T13:58:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -45,6 +45,7 @@
 		"@cloudflare/unenv-preset": "1.1.1",
 		"@hattip/adapter-node": "^0.0.49",
 		"miniflare": "workspace:*",
+		"tinyglobby": "^0.2.12",
path: packages/vite-plugin-cloudflare/package.json
user: login: penalosa
body: Is this the same package we use for glob parsing in Wrangler? I feel like we should probably make sure they're the same
created_at: 2025-03-05T14:54:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -45,6 +45,7 @@
 		"@cloudflare/unenv-preset": "1.1.1",
 		"@hattip/adapter-node": "^0.0.49",
 		"miniflare": "workspace:*",
+		"tinyglobby": "^0.2.12",
path: packages/vite-plugin-cloudflare/package.json
user: login: jamesopstad
body: This is the same package used in Vite. Wrangler's glob handling is pretty convoluted. It uses `glob-to-regexp`, which was last published 6 years ago, and then does all the actual matching manually.
created_at: 2025-03-05T15:16:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -45,6 +45,7 @@
 		"@cloudflare/unenv-preset": "1.1.1",
 		"@hattip/adapter-node": "^0.0.49",
 		"miniflare": "workspace:*",
+		"tinyglobby": "^0.2.12",
path: packages/vite-plugin-cloudflare/package.json
user: login: petebacondarwin
body: And `glob-to-regex` is broken! It doesn't wrap the regexes in `^...$` so you get weird matches.
created_at: 2025-03-05T19:55:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,17 @@
+import { cloudflare } from "@cloudflare/vite-plugin";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+	environments: {
+		worker: {
+			build: {
+				rollupOptions: {
+					output: {
+						preserveModules: true,
path: packages/vite-plugin-cloudflare/playground/dynamic-import-paths/vite.config.ts
user: login: petebacondarwin
body: Will we require users to add such config?
created_at: 2025-03-05T19:57:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,17 @@
+import { cloudflare } from "@cloudflare/vite-plugin";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+	environments: {
+		worker: {
+			build: {
+				rollupOptions: {
+					output: {
+						preserveModules: true,
path: packages/vite-plugin-cloudflare/playground/dynamic-import-paths/vite.config.ts
user: login: jamesopstad
body: No, this is just for the test case to ensure we know the path of the output file. Frameworks generally use a build manifest to know which modules to reference.
created_at: 2025-03-05T20:15:57Z
author_association: CONTRIBUTOR

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-03-05T08:40:39Z
body: ###  🦋  Changeset detected

Latest commit: 79680385f6eedfd0095f80210c4d2081840c286d

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 1 package</summary>

  | Name                    | Type  |
| ----------------------- | ----- |
| @cloudflare/vite-plugin | Patch |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/cloudflare/workers-sdk/new/james/fix-dynamic-imports?filename=.changeset/rare-horses-peel.md&value=---%0A%22%40cloudflare%2Fvite-plugin%22%3A%20patch%0A%22%40playground%2Fdynamic-import-paths%22%3A%20patch%0A%22%40vite-plugin-cloudflare%2Fplayground%22%3A%20patch%0A---%0A%0ASupport%20dynamic%20import%20paths%20in%20preview%20mode%0A)


author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-05T08:43:56Z
body: A wrangler prerelease is available for testing. You can install this latest build in your project with:

```sh
npm install --save-dev https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13677384805/npm-package-wrangler-8356
```

You can reference the automatically updated head of this PR with:

```sh
npm install --save-dev https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/prs/8356/npm-package-wrangler-8356
```

Or you can use `npx` with this latest build directly:

```sh
npx https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13677384805/npm-package-wrangler-8356 dev path/to/script.js
```

<details><summary>Additional artifacts:</summary>


cloudflare-workers-bindings-extension:
```sh
wget https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13677384805/npm-package-cloudflare-workers-bindings-extension-8356 -O ./cloudflare-workers-bindings-extension.0.0.0-v3793af56d.vsix && code --install-extension ./cloudflare-workers-bindings-extension.0.0.0-v3793af56d.vsix
```



create-cloudflare:
```sh
npx https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13677384805/npm-package-create-cloudflare-8356 --no-auto-update
```



@cloudflare/kv-asset-handler:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13677384805/npm-package-cloudflare-kv-asset-handler-8356
```



miniflare:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13677384805/npm-package-miniflare-8356
```



@cloudflare/pages-shared:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13677384805/npm-package-cloudflare-pages-shared-8356
```



@cloudflare/unenv-preset:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13677384805/npm-package-cloudflare-unenv-preset-8356
```



@cloudflare/vite-plugin:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13677384805/npm-package-cloudflare-vite-plugin-8356
```



@cloudflare/vitest-pool-workers:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13677384805/npm-package-cloudflare-vitest-pool-workers-8356
```



@cloudflare/workers-editor-shared:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13677384805/npm-package-cloudflare-workers-editor-shared-8356
```



@cloudflare/workers-shared:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13677384805/npm-package-cloudflare-workers-shared-8356
```



@cloudflare/workflows-shared:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13677384805/npm-package-cloudflare-workflows-shared-8356
```


Note that these links will no longer work once [the GitHub Actions artifact expires](https://docs.github.com/en/organizations/managing-organization-settings/configuring-the-retention-period-for-github-actions-artifacts-and-logs-in-your-organization).

</details>

---

`wrangler@3.112.0` includes the following runtime dependencies:

|Package|Constraint|Resolved|
|-------|----------|--------|
|`miniflare`|workspace:*|3.20250214.2|
|`workerd`|1.20250224.0|1.20250224.0|
|`workerd --version`|1.20250224.0|2025-02-24|

Please ensure constraints are pinned, and `miniflare`/`workerd` minor versions match.
<!-- Sticky Pull Request Comment -->
author_association: CONTRIBUTOR