@cloudflare/vite-plugin 0.0.0-910007bce → 0.0.0-930ebb279

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,340 +1,8 @@
1
1
  # `@cloudflare/vite-plugin`
2
2
 
3
- [Intro](#intro) | [Quick start](#quick-start) | [Tutorial](#tutorial) | [API](#api) | [Cloudflare environments](#cloudflare-environments) | [Debugging](#debugging) | [Migrating from `wrangler dev`](#migrating-from-wrangler-dev)
4
-
5
- ## Intro
6
-
7
- The Cloudflare Vite plugin enables a full-featured integration between Vite and the Workers runtime.
3
+ The Cloudflare Vite plugin enables a full-featured integration between [Vite](https://vite.dev/) and the [Workers runtime](https://developers.cloudflare.com/workers/runtime-apis/).
8
4
  Your Worker code runs inside [workerd](https://github.com/cloudflare/workerd), matching the production behavior as closely as possible and providing confidence as you develop and deploy your applications.
9
5
 
10
- ### Features
11
-
12
- - Provides direct access to Workers runtime APIs and bindings
13
- - Supports Workers Assets, enabling you to build static sites, SPAs, and full-stack applications
14
- - Leverages Vite's hot module replacement for consistently fast updates
15
- - Supports `vite preview` for previewing your build output in the Workers runtime prior to deployment
16
-
17
- ## Quick start
18
-
19
- ### Start with a basic `package.json`
20
-
21
- ```json
22
- {
23
- "name": "cloudflare-vite-quick-start",
24
- "private": true,
25
- "version": "0.0.0",
26
- "type": "module",
27
- "scripts": {
28
- "dev": "vite",
29
- "build": "vite build",
30
- "preview": "vite preview"
31
- }
32
- }
33
- ```
34
-
35
- > [!NOTE]
36
- > Ensure that you include `"type": "module"` in order to use ES modules by default.
37
-
38
- ### Install the dependencies
39
-
40
- ```sh
41
- npm install vite @cloudflare/vite-plugin wrangler --save-dev
42
- ```
43
-
44
- ### Create your Vite config file and include the Cloudflare plugin
45
-
46
- ```ts
47
- // vite.config.ts
48
-
49
- import { defineConfig } from "vite";
50
- import { cloudflare } from "@cloudflare/vite-plugin";
51
-
52
- export default defineConfig({
53
- plugins: [cloudflare()],
54
- });
55
- ```
56
-
57
- ### Create your Worker config file
58
-
59
- ```toml
60
- # wrangler.toml
61
-
62
- name = "cloudflare-vite-quick-start"
63
- compatibility_date = "2024-12-30"
64
- main = "./src/index.ts"
65
- ```
66
-
67
- ### Create your Worker entry file
68
-
69
- ```ts
70
- // src/index.ts
71
-
72
- export default {
73
- fetch() {
74
- return new Response(`Running in ${navigator.userAgent}!`);
75
- },
76
- };
77
- ```
78
-
79
- You can now develop (`npm run dev`), build (`npm run build`), preview (`npm run preview`), and deploy (`npm exec wrangler deploy`) your application.
80
-
81
- ## Tutorial
82
-
83
- In this tutorial, you will create a React SPA that can be deployed as a Worker with Workers Assets.
84
- Then, you will add an API Worker that can be accessed from the front-end code.
85
- You will develop, build, and preview the application using Vite before finally deploying to Cloudflare.
86
-
87
- ### Set up and configure the React SPA
88
-
89
- #### Scaffold a Vite project
90
-
91
- Start by creating a React TypeScript project with Vite.
92
-
93
- ```sh
94
- npm create vite@latest cloudflare-vite-tutorial -- --template react-ts
95
- ```
96
-
97
- Open the `cloudflare-vite-tutorial` directory in your editor of choice.
98
-
99
- #### Add the Cloudflare dependencies
100
-
101
- ```sh
102
- npm install @cloudflare/vite-plugin wrangler --save-dev
103
- ```
104
-
105
- #### Add the plugin to your Vite config
106
-
107
- ```ts
108
- // vite.config.ts
109
-
110
- import { defineConfig } from "vite";
111
- import react from "@vitejs/plugin-react";
112
- import { cloudflare } from "@cloudflare/vite-plugin";
113
-
114
- export default defineConfig({
115
- plugins: [react(), cloudflare()],
116
- });
117
- ```
118
-
119
- #### Create your Worker config file
120
-
121
- ```toml
122
- # wrangler.toml
123
-
124
- name = "cloudflare-vite-tutorial"
125
- compatibility_date = "2024-12-30"
126
- assets = { not_found_handling = "single-page-application" }
127
- ```
128
-
129
- The [`not_found_handling`](https://developers.cloudflare.com/workers/static-assets/routing/#not_found_handling--404-page--single-page-application--none) value has been set to `single-page-application`.
130
- This means that all not found requests will serve the `index.html` file.
131
- With the Cloudflare plugin, the `assets` routing configuration is used in place of Vite's default behavior.
132
- This ensures that your application's routing works the same way while developing as it does when deployed to production.
133
-
134
- Note that the [`directory`](https://developers.cloudflare.com/workers/static-assets/binding/#directory) field is not used when configuring assets with Vite.
135
- The `directory` in the output configuration will automatically point to the client build output.
136
-
137
- > [!NOTE]
138
- > When using the Cloudflare Vite plugin, the Worker config (for example, `wrangler.toml`) that you provide is the input configuration file.
139
- > A separate output `wrangler.json` file is created when you run `vite build`.
140
- > This output file is a snapshot of your configuration at the time of the build and is modified to reference your build artifacts.
141
- > It is the configuration that is used for preview and deployment.
142
-
143
- #### Update the .gitignore file
144
-
145
- Wrangler will use and/or generate temporary files that should not be stored in git. Add the following lines to the `.gitignore` file:
146
-
147
- ```gitignore
148
- .wrangler
149
- .dev.vars
150
- ```
151
-
152
- #### Run the development server
153
-
154
- Run `npm run dev` to verify that your application is working as expected.
155
-
156
- For a purely front-end application, you could now build (`npm run build`), preview (`npm run preview`), and deploy (`npm exec wrangler deploy`) your application.
157
- However, this tutorial will show you how to go a step further and add an API Worker.
158
-
159
- ### Add an API Worker
160
-
161
- #### Configure TypeScript for your Worker code
162
-
163
- ```sh
164
- npm install @cloudflare/workers-types --save-dev
165
- ```
166
-
167
- ```jsonc
168
- // tsconfig.worker.json
169
-
170
- {
171
- "extends": "./tsconfig.node.json",
172
- "compilerOptions": {
173
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.worker.tsbuildinfo",
174
- "types": ["@cloudflare/workers-types/2023-07-01", "vite/client"],
175
- },
176
- "include": ["api"],
177
- }
178
- ```
179
-
180
- ```jsonc
181
- // tsconfig.json
182
-
183
- {
184
- "files": [],
185
- "references": [
186
- { "path": "./tsconfig.app.json" },
187
- { "path": "./tsconfig.node.json" },
188
- { "path": "./tsconfig.worker.json" },
189
- ],
190
- }
191
- ```
192
-
193
- #### Add to your Worker configuration
194
-
195
- ```toml
196
- # wrangler.toml
197
-
198
- name = "cloudflare-vite-tutorial"
199
- compatibility_date = "2024-12-30"
200
- assets = { not_found_handling = "single-page-application", binding = "ASSETS" }
201
- main = "./api/index.ts"
202
- ```
203
-
204
- The assets `binding` defined here will allow you to access the assets functionality from your Worker.
205
-
206
- #### Add your API Worker
207
-
208
- ```ts
209
- // api/index.ts
210
-
211
- interface Env {
212
- ASSETS: Fetcher;
213
- }
214
-
215
- export default {
216
- fetch(request, env) {
217
- const url = new URL(request.url);
218
-
219
- if (url.pathname.startsWith("/api/")) {
220
- return Response.json({
221
- name: "Cloudflare",
222
- });
223
- }
224
-
225
- return env.ASSETS.fetch(request);
226
- },
227
- } satisfies ExportedHandler<Env>;
228
- ```
229
-
230
- The Worker above will be invoked for any request not matching a static asset.
231
- It returns a JSON response if the `pathname` starts with `/api/` and otherwise passes the incoming request through to the assets binding.
232
- This means that for paths that do not start with `/api/`, the `not_found_handling` behavior defined in the Worker config will be evaluated and the `index.html` file will be returned, enabling SPA navigations.
233
-
234
- #### Call the API from the client
235
-
236
- Edit `src/App.tsx` so that it includes an additional button that calls the API and sets some state.
237
- Replace the file contents with the following code:
238
-
239
- ```tsx
240
- // src/App.tsx
241
-
242
- import { useState } from "react";
243
- import reactLogo from "./assets/react.svg";
244
- import viteLogo from "/vite.svg";
245
- import "./App.css";
246
-
247
- function App() {
248
- const [count, setCount] = useState(0);
249
- const [name, setName] = useState("unknown");
250
-
251
- return (
252
- <>
253
- <div>
254
- <a href="https://vite.dev" target="_blank">
255
- <img src={viteLogo} className="logo" alt="Vite logo" />
256
- </a>
257
- <a href="https://react.dev" target="_blank">
258
- <img src={reactLogo} className="logo react" alt="React logo" />
259
- </a>
260
- </div>
261
- <h1>Vite + React</h1>
262
- <div className="card">
263
- <button
264
- onClick={() => setCount((count) => count + 1)}
265
- aria-label="increment"
266
- >
267
- count is {count}
268
- </button>
269
- <p>
270
- Edit <code>src/App.tsx</code> and save to test HMR
271
- </p>
272
- </div>
273
- <div className="card">
274
- <button
275
- onClick={() => {
276
- fetch("/api/")
277
- .then((res) => res.json() as Promise<{ name: string }>)
278
- .then((data) => setName(data.name));
279
- }}
280
- aria-label="get name"
281
- >
282
- Name from API is: {name}
283
- </button>
284
- <p>
285
- Edit <code>api/index.ts</code> to change the name
286
- </p>
287
- </div>
288
- <p className="read-the-docs">
289
- Click on the Vite and React logos to learn more
290
- </p>
291
- </>
292
- );
293
- }
294
-
295
- export default App;
296
- ```
297
-
298
- Now, if you click the button, it will display 'Name from API is: Cloudflare'.
299
-
300
- Increment the counter to update the application state in the browser.
301
- Next, edit `api/index.ts` by changing the `name` it returns to `'Cloudflare Workers'`.
302
- If you click the button again, it will display the new `name` while preserving the previously set counter value.
303
- With Vite and the Cloudflare plugin, you can iterate on the client and server parts of your app quickly without losing UI state between edits.
304
-
305
- #### Build your application
306
-
307
- Run `npm run build` to build your application.
308
-
309
- If you inspect the `dist` directory, you will see that it contains two subdirectories: `client` and `cloudflare-vite-tutorial`.
310
- The `cloudflare-vite-tutorial` directory contains your Worker code and the output `wrangler.json` configuration.
311
-
312
- #### Preview your application
313
-
314
- Run `npm run preview` to validate that your application runs as expected.
315
- This command will run your build output locally in the Workers runtime, closely matching its behaviour in production.
316
-
317
- #### Deploy to Cloudflare
318
-
319
- Run `npm exec wrangler deploy` to deploy your application to Cloudflare.
320
- This command will automatically use the output `wrangler.json` that was included in the build output.
321
-
322
- ### Next steps
323
-
324
- In this tutorial, we created an SPA that could be deployed as a Worker with Workers Assets.
325
- We then added an API Worker that could be accessed from the front-end code and deployed to Cloudflare.
326
- Possible next steps include:
327
-
328
- - Adding a binding to another Cloudflare service such as a [KV namespace](https://developers.cloudflare.com/kv/) or [D1 database](https://developers.cloudflare.com/d1/)
329
- - Expanding the API to include additional routes
330
- - Using a library, such as [tRPC](https://trpc.io/) or [Hono](https://hono.dev/), in your API Worker
331
-
332
- ## API
333
-
334
- ### `cloudflare`
335
-
336
- The `cloudflare` plugin should be included in the Vite `plugins` array:
337
-
338
6
  ```ts
339
7
  // vite.config.ts
340
8
 
@@ -346,215 +14,22 @@ export default defineConfig({
346
14
  });
347
15
  ```
348
16
 
349
- It accepts an optional `PluginConfig` parameter.
350
-
351
- ### `interface PluginConfig`
352
-
353
- - `configPath?: string`
354
-
355
- An optional path to your Worker config file.
356
- By default, a `wrangler.toml`, `wrangler.json`, or `wrangler.jsonc` file in the root of your application will be used as the Worker config.
357
-
358
- - `viteEnvironment?: { name?: string }`
359
-
360
- Optional Vite environment options.
361
- By default, the environment name is the Worker name with `-` characters replaced with `_`.
362
- Setting the name here will override this.
363
-
364
- - `persistState?: boolean | { path: string }`
365
-
366
- An optional override for state persistence.
367
- By default, state is persisted to `.wrangler/state` in a `v3` subdirectory.
368
- A custom `path` can be provided or, alternatively, persistence can be disabled by setting the value to `false`.
369
-
370
- - `auxiliaryWorkers?: Array<AuxiliaryWorkerConfig>`
371
-
372
- An optional array of auxiliary workers.
373
- You can use [service bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/) to call auxiliary workers from your main (entry) Worker.
374
- All requests are routed through your entry Worker.
375
- During the build, each Worker is output to a separate subdirectory of `dist`.
376
-
377
- - `inspectorPort?: number | false`
378
-
379
- Optional inspector port to use for debugging your workers, for more details on debugging see the [devtools section](#devtools). Can be set to `false` to disable the debugging inspector altogether. Defaults to `9229`.
380
-
381
- > [!NOTE]
382
- > When running `wrangler deploy`, only your main (entry) Worker will be deployed.
383
- > If using multiple Workers, each must be deployed individually.
384
- > You can inspect the `dist` directory and then run `wrangler deploy -c path-to-worker-output-config` for each.
385
-
386
- ### `interface AuxiliaryWorkerConfig`
387
-
388
- - `configPath: string`
389
-
390
- A required path to your Worker config file.
391
-
392
- - `viteEnvironment?: { name?: string }`
393
-
394
- Optional Vite environment options.
395
- By default, the environment name is the Worker name with `-` characters replaced with `_`.
396
- Setting the name here will override this.
397
-
398
- ## Cloudflare environments
399
-
400
- A Worker config file may contain configuration for multiple [Cloudflare environments](https://developers.cloudflare.com/workers/wrangler/environments/).
401
- With the Cloudflare Vite plugin, you select a Cloudflare environment at dev or build time by providing the `CLOUDFLARE_ENV` environment variable.
402
- Consider the following example `wrangler.toml` file:
403
-
404
- ```toml
405
- # wrangler.toml
406
-
407
- name = "my-worker"
408
- compatibility_date = "2024-12-30"
409
- main = "./src/index.ts"
410
-
411
- vars = { MY_VAR = "Top-level var" }
412
-
413
- [env.staging]
414
- vars = { MY_VAR = "Staging var" }
415
-
416
- [env.production]
417
- vars = { MY_VAR = "Production var" }
418
- ```
419
-
420
- If you run `CLOUDFLARE_ENV=production vite build` then the output `wrangler.json` file generated by the build will be a flattened configuration for the 'production' Cloudflare environment.
421
- This combines [top-level only](https://developers.cloudflare.com/workers/wrangler/configuration/#top-level-only-keys), [inheritable](https://developers.cloudflare.com/workers/wrangler/configuration/#inheritable-keys), and [non-inheritable](https://developers.cloudflare.com/workers/wrangler/configuration/#non-inheritable-keys) keys.
422
- The value of `MY_VAR` will therefore be `'Production var'`.
423
- The name of the Worker will be `'my-worker-production'`.
424
- This is because the environment name is automatically appended to the top-level Worker name.
425
-
426
- > [!NOTE]
427
- > The default Vite environment name for a Worker is always the top-level Worker name.
428
- > This enables you to reference the Worker consistently in your Vite config when using multiple Cloudflare environments.
429
-
430
- Cloudflare environments can also be used in development.
431
- For example, you could run `CLOUDFLARE_ENV=development vite dev`.
432
- It is common to use the default top-level environment as the development environment and then add additional environments as necessary.
433
-
434
- > [!NOTE]
435
- > Running `vite dev` or `vite build` without providing `CLOUDFLARE_ENV` will use the default top-level Cloudflare environment.
436
- > The value of `MY_VAR` will therefore be `'Top-level var'`.
437
- > As Cloudflare environments are applied at dev and build time, specifying `CLOUDFLARE_ENV` when running `vite preview` or `wrangler deploy` will have no effect.
438
-
439
- ### Combining Cloudflare environments and Vite modes
440
-
441
- You may wish to combine the concepts of [Cloudflare environments](https://developers.cloudflare.com/workers/wrangler/environments/) and [Vite modes](https://vite.dev/guide/env-and-mode.html#modes).
442
- With this approach, the Vite mode can be used to select the Cloudflare environment and a single method can be used to determine environment specific configuration and code.
443
- Consider again the previous example:
444
-
445
- ```toml
446
- # wrangler.toml
447
-
448
- name = "my-worker"
449
- compatibility_date = "2024-12-30"
450
- main = "./src/index.ts"
451
-
452
- vars = { MY_VAR = "Top-level var" }
453
-
454
- [env.staging]
455
- vars = { MY_VAR = "Staging var" }
456
-
457
- [env.production]
458
- vars = { MY_VAR = "Production var" }
459
- ```
460
-
461
- Next, provide `.env.staging` and `.env.production` files:
462
-
463
- ```sh
464
- # .env.staging
465
-
466
- CLOUDFLARE_ENV=staging
467
- ```
468
-
469
- ```sh
470
- # .env.production
471
-
472
- CLOUDFLARE_ENV=production
473
- ```
474
-
475
- By default, `vite build` uses the 'production' Vite mode.
476
- Vite will therefore load the `.env.production` file to get the environment variables that are used in the build.
477
- Since the `.env.production` file contains `CLOUDFLARE_ENV=production`, the Cloudflare Vite plugin will select the 'production' Cloudflare environment.
478
- The value of `MY_VAR` will therefore be `'Production var'`.
479
- If you run `vite build --mode staging` then the 'staging' Vite mode will be used and the 'staging' Cloudflare environment will be selected.
480
- The value of `MY_VAR` will therefore be `'Staging var'`.
481
-
482
- ## Secrets
17
+ ## Documentation
483
18
 
484
- Secrets can be provided to your Worker in local development using a [`.dev.vars`](https://developers.cloudflare.com/workers/configuration/secrets/#local-development-with-secrets) file. If you are using [Cloudflare Environments](#cloudflare-environments) then the relevant `.dev.vars` file will be selected. For example, `CLOUDFLARE_ENV=staging vite dev` will load `.dev.vars.staging` if it exists and fall back to `.dev.vars`.
19
+ Full documentation can be found [here](https://developers.cloudflare.com/workers/vite-plugin/).
485
20
 
486
- > [!NOTE]
487
- > The `vite build` command copies the relevant `.dev.vars[.env-name]` file to the output directory. This is only used when running `vite preview` and is not deployed with your Worker.
21
+ ## Features
488
22
 
489
- ## Debugging
490
-
491
- The Cloudflare Vite plugin allows you to conveniently debug your Worker code during local development.
492
-
493
- By default the inspector port used by the plugin is `9229`, which can be customized by providing a different port to the plugin's `inspectorPort` option.
494
-
495
- There are two recommended ways of doing so, which we'll explore in this section.
496
-
497
- ### Devtools
498
-
499
- When running `vite dev` or `vite preview` a `/__debug` route in your local server will be made available which gives you access to [Cloudflare's implementation](/packages/chrome-devtools-patches) of [Chrome's DevTools](https://developer.chrome.com/docs/devtools/overview).
500
-
501
- Navigating to this route will open a devtools tab for each of the workers in your application (Note: in case of multiple workers you might need to allow your browser to open pop-ups).
502
-
503
- Once the tab or tabs are open, you can make a request to your application and start debugging your workers' code.
504
-
505
- Note: If you're not interested in debugging all your workers you can close the tabs of the workers you don't want to debug.
506
-
507
- ### VS Code
508
-
509
- To setup VS Code for breakpoint debugging for your application, you will need to create a `.vscode/launch.json` file that contains a configuration following this structure:
510
-
511
- ```json
512
- {
513
- "configurations": [
514
- {
515
- "name": "<NAME_OF_WORKER>",
516
- "type": "node",
517
- "request": "attach",
518
- "websocketAddress": "ws://localhost:9229/<NAME_OF_WORKER>",
519
- "resolveSourceMapLocations": null,
520
- "attachExistingChildren": false,
521
- "autoAttachChildProcesses": false,
522
- "sourceMaps": true
523
- }
524
- ],
525
- "compounds": [
526
- {
527
- "name": "Debug All Workers",
528
- "configurations": ["<NAME_OF_WORKER>"],
529
- "stopAll": true
530
- }
531
- ]
532
- }
533
- ```
534
-
535
- Where, `<NAME_OF_WORKER>` indicates the name of your worker as specified in your Wrangler configuration.
536
-
537
- Note: if you customized your `inspectorPort` you need to use that port in the `websocketAddress` field.
538
-
539
- If you have more than one worker you need add a configuration in the `configurations` field for each one and then include the configuration name in the `configurations` array in the compound configuration.
540
-
541
- Once your `launch.json` file is ready, after running `vite dev` or `vite preview` you can select **Debug All Workers** at the top of the **Run & Debug** panel to attach debuggers to all the various Workers. Then you can add breakpoints to your code and start debugging.
542
-
543
- Note: You can also manually select the configurations to run (e.g. **Debug Worker1**) to filter which workers you want to debug.
544
-
545
- ## Migrating from `wrangler dev`
546
-
547
- Migrating from `wrangler dev` is a simple process and you can follow the instructions in the [Quick start](#quick-start) to get started.
548
- There are a few key differences to highlight:
549
-
550
- ### Input and output Worker config files
551
-
552
- In the Vite integration, your Worker config file (for example, `wrangler.toml`) is the input configuration and a separate output configuration is created as part of the build.
553
- This output file is a snapshot of your configuration at the time of the build and is modified to reference your build artifacts.
554
- It is the configuration that is used for preview and deployment.
23
+ - Uses the Vite [Environment API](https://vite.dev/guide/api-environment) to integrate Vite with the Workers runtime
24
+ - Provides direct access to [Workers runtime APIs](https://developers.cloudflare.com/workers/runtime-apis/) and [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/)
25
+ - Builds your front-end assets for deployment to Cloudflare, enabling you to build static sites, SPAs, and full-stack applications
26
+ - Official support for [React Router v7](https://reactrouter.com/) with server-side rendering
27
+ - Leverages Vite's hot module replacement for consistently fast updates
28
+ - Supports `vite preview` for previewing your build output in the Workers runtime prior to deployment
555
29
 
556
- ### Redundant fields in the Wrangler config file
30
+ ## Use cases
557
31
 
558
- There are various options in the Worker config file that are ignored when using Vite, as they are either no longer applicable or are replaced by Vite equivalents.
559
- If these options are provided, then warnings will be printed to the console with suggestions for how to proceed.
560
- Examples where the Vite configuration should be used instead include `alias` and `define`.
32
+ - React Router v7 (support for more full-stack frameworks is coming soon)
33
+ - Static sites, such as single-page applications, with or without an integrated backend API
34
+ - Standalone Workers
35
+ - Multi-Worker applications
package/dist/index.js CHANGED
@@ -485,11 +485,12 @@ var require_mime = __commonJS({
485
485
  });
486
486
 
487
487
  // src/index.ts
488
- import assert8 from "node:assert";
488
+ import assert10 from "node:assert";
489
489
  import * as fs5 from "node:fs";
490
490
  import * as fsp2 from "node:fs/promises";
491
491
  import * as path9 from "node:path";
492
492
  import { createMiddleware } from "@hattip/adapter-node";
493
+ import replace from "@rollup/plugin-replace";
493
494
 
494
495
  // ../../node_modules/.pnpm/@jridgewell+sourcemap-codec@1.5.0/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
495
496
  var comma = ",".charCodeAt(0);
@@ -1557,6 +1558,7 @@ var MagicString = class _MagicString {
1557
1558
 
1558
1559
  // src/index.ts
1559
1560
  import { Miniflare } from "miniflare";
1561
+ import colors2 from "picocolors";
1560
1562
  import * as vite7 from "vite";
1561
1563
 
1562
1564
  // src/constants.ts
@@ -12939,8 +12941,9 @@ function getNodeCompatEntries() {
12939
12941
  return entries;
12940
12942
  }
12941
12943
  var NodeJsCompatWarnings = class {
12942
- constructor(environment) {
12943
- this.environment = environment;
12944
+ constructor(environmentName, resolvedViteConfig) {
12945
+ this.environmentName = environmentName;
12946
+ this.resolvedViteConfig = resolvedViteConfig;
12944
12947
  }
12945
12948
  sources = /* @__PURE__ */ new Map();
12946
12949
  timer;
@@ -12948,6 +12951,7 @@ var NodeJsCompatWarnings = class {
12948
12951
  const importers = this.sources.get(source) ?? /* @__PURE__ */ new Set();
12949
12952
  this.sources.set(source, importers);
12950
12953
  importers.add(importer);
12954
+ this.renderWarningsOnIdle();
12951
12955
  }
12952
12956
  renderWarningsOnIdle() {
12953
12957
  if (this.timer) {
@@ -12960,19 +12964,16 @@ var NodeJsCompatWarnings = class {
12960
12964
  }
12961
12965
  renderWarnings() {
12962
12966
  if (this.sources.size > 0) {
12963
- let message = `
12964
-
12965
- Unexpected Node.js imports for environment "${this.environment.name}". Do you need to enable the "nodejs_compat" compatibility flag?
12966
- Refer to https://developers.cloudflare.com/workers/runtime-apis/nodejs/ for more details.
12967
+ let message = `Unexpected Node.js imports for environment "${this.environmentName}". Do you need to enable the "nodejs_compat" compatibility flag? Refer to https://developers.cloudflare.com/workers/runtime-apis/nodejs/ for more details.
12967
12968
  `;
12968
12969
  this.sources.forEach((importers, source) => {
12969
12970
  importers.forEach((importer) => {
12970
- message += ` - "${source}" imported from "${path3.relative(this.environment.config.root, importer)}"
12971
+ message += ` - "${source}" imported from "${path3.relative(this.resolvedViteConfig.root, importer)}"
12971
12972
  `;
12972
12973
  });
12973
12974
  });
12974
- this.environment.logger.warn(message, {
12975
- environment: this.environment.name
12975
+ this.resolvedViteConfig.logger.warn(message, {
12976
+ timestamp: true
12976
12977
  });
12977
12978
  this.sources.clear();
12978
12979
  }
@@ -12992,6 +12993,7 @@ var VITE_DEV_METADATA_HEADER = "__VITE_DEV_METADATA__";
12992
12993
 
12993
12994
  // src/utils.ts
12994
12995
  import * as path4 from "node:path";
12996
+ import getPort, { portNumbers } from "get-port";
12995
12997
  import { Request as MiniflareRequest } from "miniflare";
12996
12998
  import "vite";
12997
12999
  function getOutputDirectory(userConfig, environmentName) {
@@ -13002,6 +13004,10 @@ function getRouterWorker(miniflare2) {
13002
13004
  return miniflare2.getWorker(ROUTER_WORKER_NAME);
13003
13005
  }
13004
13006
  function toMiniflareRequest(request) {
13007
+ const host = request.headers.get("Host");
13008
+ if (host) {
13009
+ request.headers.set("X-Forwarded-Host", host);
13010
+ }
13005
13011
  const secFetchMode = request.headers.get("Sec-Fetch-Mode");
13006
13012
  if (secFetchMode) {
13007
13013
  request.headers.set("X-Mf-Sec-Fetch-Mode", secFetchMode);
@@ -13030,6 +13036,9 @@ var postfixRE = /[?#].*$/;
13030
13036
  function cleanUrl(url) {
13031
13037
  return url.replace(postfixRE, "");
13032
13038
  }
13039
+ function getFirstAvailablePort(start) {
13040
+ return getPort({ port: portNumbers(start, 65535) });
13041
+ }
13033
13042
 
13034
13043
  // src/cloudflare-environment.ts
13035
13044
  var webSocketUndefinedError = "The WebSocket is undefined";
@@ -13440,7 +13449,7 @@ function getEntryWorkerConfig(resolvedPluginConfig) {
13440
13449
  }
13441
13450
  return resolvedPluginConfig.workers[resolvedPluginConfig.entryWorkerEnvironmentName];
13442
13451
  }
13443
- function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer) {
13452
+ function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer, inspectorPort) {
13444
13453
  const resolvedViteConfig = viteDevServer.config;
13445
13454
  const entryWorkerConfig = getEntryWorkerConfig(resolvedPluginConfig);
13446
13455
  const assetsConfig = getAssetsConfig(
@@ -13532,7 +13541,7 @@ function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer) {
13532
13541
  worker: {
13533
13542
  ...workerOptions,
13534
13543
  name: workerOptions.name ?? workerConfig.name,
13535
- unsafeInspectorProxy: resolvedPluginConfig.inspectorPort !== false,
13544
+ unsafeInspectorProxy: inspectorPort !== false,
13536
13545
  modulesRoot: miniflareModulesRoot,
13537
13546
  unsafeEvalBinding: "__VITE_UNSAFE_EVAL__",
13538
13547
  serviceBindings: {
@@ -13574,8 +13583,8 @@ function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer) {
13574
13583
  const logger = new ViteMiniflareLogger(resolvedViteConfig);
13575
13584
  return {
13576
13585
  log: logger,
13577
- inspectorPort: resolvedPluginConfig.inspectorPort || void 0,
13578
- unsafeInspectorProxy: resolvedPluginConfig.inspectorPort !== false,
13586
+ inspectorPort: inspectorPort === false ? void 0 : inspectorPort,
13587
+ unsafeInspectorProxy: inspectorPort !== false,
13579
13588
  handleRuntimeStdio(stdout, stderr) {
13580
13589
  const decoder = new TextDecoder();
13581
13590
  stdout.forEach((data2) => logger.info(decoder.decode(data2)));
@@ -13712,7 +13721,7 @@ function getPreviewModules(main, modulesRules) {
13712
13721
  ]
13713
13722
  };
13714
13723
  }
13715
- function getPreviewMiniflareOptions(vitePreviewServer, workerConfigs, persistState, inspectorPort = DEFAULT_INSPECTOR_PORT) {
13724
+ function getPreviewMiniflareOptions(vitePreviewServer, workerConfigs, persistState, inspectorPort) {
13716
13725
  const resolvedViteConfig = vitePreviewServer.config;
13717
13726
  const workers = workerConfigs.flatMap((config) => {
13718
13727
  const miniflareWorkerOptions = unstable_getMiniflareWorkerOptions(config);
@@ -13731,7 +13740,7 @@ function getPreviewMiniflareOptions(vitePreviewServer, workerConfigs, persistSta
13731
13740
  const logger = new ViteMiniflareLogger(resolvedViteConfig);
13732
13741
  return {
13733
13742
  log: logger,
13734
- inspectorPort: inspectorPort || void 0,
13743
+ inspectorPort: inspectorPort === false ? void 0 : inspectorPort,
13735
13744
  unsafeInspectorProxy: inspectorPort !== false,
13736
13745
  handleRuntimeStdio(stdout, stderr) {
13737
13746
  const decoder = new TextDecoder();
@@ -13781,11 +13790,12 @@ function miniflareLogLevelFromViteLogLevel(level = "info") {
13781
13790
  }
13782
13791
 
13783
13792
  // src/plugin-config.ts
13784
- import assert7 from "node:assert";
13793
+ import assert8 from "node:assert";
13785
13794
  import * as path8 from "node:path";
13786
13795
  import * as vite6 from "vite";
13787
13796
 
13788
13797
  // src/workers-configs.ts
13798
+ import assert7 from "node:assert";
13789
13799
  import * as fs4 from "node:fs";
13790
13800
  import * as path7 from "node:path";
13791
13801
  import { unstable_readConfig as unstable_readConfig2 } from "wrangler";
@@ -13819,8 +13829,7 @@ var nonApplicableWorkerConfigs = {
13819
13829
  "preserve_file_names",
13820
13830
  "rules",
13821
13831
  "site",
13822
- "tsconfig",
13823
- "upload_source_maps"
13832
+ "tsconfig"
13824
13833
  ]
13825
13834
  };
13826
13835
  var nullableNonApplicable = [
@@ -13831,8 +13840,7 @@ var nullableNonApplicable = [
13831
13840
  "no_bundle",
13832
13841
  "preserve_file_names",
13833
13842
  "site",
13834
- "tsconfig",
13835
- "upload_source_maps"
13843
+ "tsconfig"
13836
13844
  ];
13837
13845
  function readWorkerConfig(configPath, env2) {
13838
13846
  const nonApplicable = {
@@ -13994,14 +14002,52 @@ function getWorkerConfig(configPath, env2, opts) {
13994
14002
  nonApplicable
13995
14003
  };
13996
14004
  }
14005
+ function getValidatedWranglerConfigPath(root, requestedConfigPath, isForAuxiliaryWorker = false) {
14006
+ if (requestedConfigPath) {
14007
+ const configPath2 = path7.resolve(root, requestedConfigPath);
14008
+ const forAuxiliaryWorkerErrorMessage = isForAuxiliaryWorker ? " requested for one of your auxiliary workers" : "";
14009
+ const errorMessagePrefix = `The provided configPath (${configPath2})${forAuxiliaryWorkerErrorMessage}`;
14010
+ const fileExtension = path7.extname(configPath2).slice(1);
14011
+ if (!allowedWranglerConfigExtensions.includes(fileExtension)) {
14012
+ const foundExtensionMessage = !fileExtension ? "no extension found" : `"${fileExtension}" found`;
14013
+ throw new Error(
14014
+ `${errorMessagePrefix} doesn't point to a file with the correct file extension. It should point to a jsonc, json or toml file (${foundExtensionMessage} instead)`
14015
+ );
14016
+ }
14017
+ const mainStat = fs4.statSync(configPath2, { throwIfNoEntry: false });
14018
+ if (!mainStat) {
14019
+ throw new Error(
14020
+ `${errorMessagePrefix} doesn't point to an existing file`
14021
+ );
14022
+ }
14023
+ if (mainStat.isDirectory()) {
14024
+ throw new Error(
14025
+ `${errorMessagePrefix} points to a directory. It should point to a file.`
14026
+ );
14027
+ }
14028
+ return configPath2;
14029
+ }
14030
+ assert7(
14031
+ isForAuxiliaryWorker === false,
14032
+ "Unexpected Error: trying to find the wrangler config for an auxiliary worker"
14033
+ );
14034
+ const configPath = findWranglerConfig(root);
14035
+ if (!configPath) {
14036
+ throw new Error(
14037
+ `No config file found in the ${root} directory. Please add a wrangler.(jsonc|json|toml) file.`
14038
+ );
14039
+ }
14040
+ return configPath;
14041
+ }
13997
14042
  function findWranglerConfig(root) {
13998
- for (const extension of ["json", "jsonc", "toml"]) {
14043
+ for (const extension of allowedWranglerConfigExtensions) {
13999
14044
  const configPath = path7.join(root, `wrangler.${extension}`);
14000
14045
  if (fs4.existsSync(configPath)) {
14001
14046
  return configPath;
14002
14047
  }
14003
14048
  }
14004
14049
  }
14050
+ var allowedWranglerConfigExtensions = ["jsonc", "json", "toml"];
14005
14051
 
14006
14052
  // src/plugin-config.ts
14007
14053
  function workerNameToEnvironmentName(workerName) {
@@ -14010,7 +14056,6 @@ function workerNameToEnvironmentName(workerName) {
14010
14056
  function resolvePluginConfig(pluginConfig, userConfig, viteEnv) {
14011
14057
  const configPaths = /* @__PURE__ */ new Set();
14012
14058
  const persistState = pluginConfig.persistState ?? true;
14013
- const inspectorPort = pluginConfig.inspectorPort ?? DEFAULT_INSPECTOR_PORT;
14014
14059
  const experimental = pluginConfig.experimental ?? {};
14015
14060
  const root = userConfig.root ? path8.resolve(userConfig.root) : process.cwd();
14016
14061
  const { CLOUDFLARE_ENV: cloudflareEnv } = vite6.loadEnv(
@@ -14019,22 +14064,23 @@ function resolvePluginConfig(pluginConfig, userConfig, viteEnv) {
14019
14064
  /* prefixes */
14020
14065
  ""
14021
14066
  );
14022
- const configPath = pluginConfig.configPath ? path8.resolve(root, pluginConfig.configPath) : findWranglerConfig(root);
14023
- if (!configPath) {
14024
- throw new Error(
14025
- `Config not found. Have you created a wrangler.json(c) or wrangler.toml file?`
14026
- );
14027
- }
14028
- const entryWorkerResolvedConfig = getWorkerConfig(configPath, cloudflareEnv, {
14029
- visitedConfigPaths: configPaths,
14030
- isEntryWorker: true
14031
- });
14067
+ const entryWorkerConfigPath = getValidatedWranglerConfigPath(
14068
+ root,
14069
+ pluginConfig.configPath
14070
+ );
14071
+ const entryWorkerResolvedConfig = getWorkerConfig(
14072
+ entryWorkerConfigPath,
14073
+ cloudflareEnv,
14074
+ {
14075
+ visitedConfigPaths: configPaths,
14076
+ isEntryWorker: true
14077
+ }
14078
+ );
14032
14079
  if (entryWorkerResolvedConfig.type === "assets-only") {
14033
14080
  return {
14034
14081
  type: "assets-only",
14035
14082
  config: entryWorkerResolvedConfig.config,
14036
14083
  configPaths,
14037
- inspectorPort,
14038
14084
  persistState,
14039
14085
  rawConfigs: {
14040
14086
  entryWorker: entryWorkerResolvedConfig
@@ -14050,15 +14096,20 @@ function resolvePluginConfig(pluginConfig, userConfig, viteEnv) {
14050
14096
  };
14051
14097
  const auxiliaryWorkersResolvedConfigs = [];
14052
14098
  for (const auxiliaryWorker of pluginConfig.auxiliaryWorkers ?? []) {
14099
+ const workerConfigPath = getValidatedWranglerConfigPath(
14100
+ root,
14101
+ auxiliaryWorker.configPath,
14102
+ true
14103
+ );
14053
14104
  const workerResolvedConfig = getWorkerConfig(
14054
- path8.resolve(root, auxiliaryWorker.configPath),
14105
+ workerConfigPath,
14055
14106
  cloudflareEnv,
14056
14107
  {
14057
14108
  visitedConfigPaths: configPaths
14058
14109
  }
14059
14110
  );
14060
14111
  auxiliaryWorkersResolvedConfigs.push(workerResolvedConfig);
14061
- assert7(
14112
+ assert8(
14062
14113
  workerResolvedConfig.type === "worker",
14063
14114
  "Unexpected error: received AssetsOnlyResult with auxiliary workers."
14064
14115
  );
@@ -14075,7 +14126,6 @@ function resolvePluginConfig(pluginConfig, userConfig, viteEnv) {
14075
14126
  type: "workers",
14076
14127
  configPaths,
14077
14128
  persistState,
14078
- inspectorPort,
14079
14129
  workers,
14080
14130
  entryWorkerEnvironmentName,
14081
14131
  rawConfigs: {
@@ -14123,6 +14173,54 @@ function handleWebSocket(httpServer, getFetcher) {
14123
14173
  );
14124
14174
  }
14125
14175
 
14176
+ // src/worker-environments-validation.ts
14177
+ import assert9 from "node:assert";
14178
+ function validateWorkerEnvironmentsResolvedConfigs(resolvedPluginConfig, resolvedViteConfig) {
14179
+ const workersEnvironmentNames = Object.keys(resolvedPluginConfig.workers);
14180
+ const disallowedEnvsConfigs = /* @__PURE__ */ new Map();
14181
+ for (const envName of workersEnvironmentNames) {
14182
+ const workerEnvConfig = resolvedViteConfig.environments[envName];
14183
+ assert9(workerEnvConfig, `Missing environment config for "${envName}"`);
14184
+ const { optimizeDeps, resolve: resolve8 } = workerEnvConfig;
14185
+ const disallowedConfig = {};
14186
+ const disallowedOptimizeDepsExcludeEntries = (optimizeDeps.exclude ?? []).filter((entry) => {
14187
+ if (cloudflareBuiltInModules.includes(entry)) {
14188
+ return false;
14189
+ }
14190
+ if (NODEJS_MODULES_RE.test(entry) && isNodeCompat(resolvedPluginConfig.workers[envName])) {
14191
+ return false;
14192
+ }
14193
+ return true;
14194
+ });
14195
+ if (disallowedOptimizeDepsExcludeEntries.length > 0) {
14196
+ disallowedConfig.optimizeDepsExclude = disallowedOptimizeDepsExcludeEntries;
14197
+ }
14198
+ if (resolve8.external === true || resolve8.external.length > 0) {
14199
+ disallowedConfig.resolveExternal = resolve8.external;
14200
+ }
14201
+ if (Object.keys(disallowedConfig).length > 0) {
14202
+ disallowedEnvsConfigs.set(envName, disallowedConfig);
14203
+ }
14204
+ }
14205
+ if (disallowedEnvsConfigs.size > 0) {
14206
+ const errorMessage = `The following environment configurations are incompatible with the Cloudflare Vite plugin:
14207
+ ${[
14208
+ ...disallowedEnvsConfigs
14209
+ ].map(
14210
+ ([envName, disallowedConfig]) => [
14211
+ disallowedConfig.optimizeDepsExclude ? ` - "${envName}" environment: \`optimizeDeps.exclude\`: ${JSON.stringify(disallowedConfig.optimizeDepsExclude)}
14212
+ ` : null,
14213
+ disallowedConfig.resolveExternal ? ` - "${envName}" environment: \`resolve.external\`: ${JSON.stringify(disallowedConfig.resolveExternal)}
14214
+ ` : null
14215
+ ].join("")
14216
+ ).join(
14217
+ ""
14218
+ )}To resolve this issue, avoid setting \`optimizeDeps.exclude\` and \`resolve.external\` in your Cloudflare Worker environments.
14219
+ `;
14220
+ throw new Error(errorMessage);
14221
+ }
14222
+ }
14223
+
14126
14224
  // src/index.ts
14127
14225
  var workersConfigsWarningShown = false;
14128
14226
  var miniflare;
@@ -14193,7 +14291,7 @@ function cloudflare2(pluginConfig = {}) {
14193
14291
  resolvedPluginConfig.workers
14194
14292
  ).map((environmentName) => {
14195
14293
  const environment = builder.environments[environmentName];
14196
- assert8(
14294
+ assert10(
14197
14295
  environment,
14198
14296
  `${environmentName} environment not found`
14199
14297
  );
@@ -14214,6 +14312,12 @@ function cloudflare2(pluginConfig = {}) {
14214
14312
  },
14215
14313
  configResolved(config) {
14216
14314
  resolvedViteConfig = config;
14315
+ if (resolvedPluginConfig?.type === "workers") {
14316
+ validateWorkerEnvironmentsResolvedConfigs(
14317
+ resolvedPluginConfig,
14318
+ resolvedViteConfig
14319
+ );
14320
+ }
14217
14321
  },
14218
14322
  generateBundle(_, bundle) {
14219
14323
  let config;
@@ -14234,7 +14338,7 @@ function cloudflare2(pluginConfig = {}) {
14234
14338
  if (isEntryWorker && hasClientBuild) {
14235
14339
  const workerOutputDirectory = this.environment.config.build.outDir;
14236
14340
  const clientOutputDirectory = resolvedViteConfig.environments.client?.build.outDir;
14237
- assert8(
14341
+ assert10(
14238
14342
  clientOutputDirectory,
14239
14343
  "Unexpected error: client output directory is undefined"
14240
14344
  );
@@ -14311,23 +14415,36 @@ function cloudflare2(pluginConfig = {}) {
14311
14415
  }
14312
14416
  },
14313
14417
  async configureServer(viteDevServer) {
14314
- assert8(
14418
+ assert10(
14315
14419
  viteDevServer.httpServer,
14316
14420
  "Unexpected error: No Vite HTTP server"
14317
14421
  );
14318
- if (miniflare) {
14319
- await miniflare.setOptions(
14320
- getDevMiniflareOptions(resolvedPluginConfig, viteDevServer)
14422
+ if (!miniflare) {
14423
+ const inputInspectorPort = await getInputInspectorPortOption(
14424
+ pluginConfig,
14425
+ viteDevServer
14321
14426
  );
14322
- } else {
14323
14427
  miniflare = new Miniflare(
14324
- getDevMiniflareOptions(resolvedPluginConfig, viteDevServer)
14428
+ getDevMiniflareOptions(
14429
+ resolvedPluginConfig,
14430
+ viteDevServer,
14431
+ inputInspectorPort
14432
+ )
14433
+ );
14434
+ } else {
14435
+ const resolvedInspectorPort = await getResolvedInspectorPort(pluginConfig);
14436
+ await miniflare.setOptions(
14437
+ getDevMiniflareOptions(
14438
+ resolvedPluginConfig,
14439
+ viteDevServer,
14440
+ resolvedInspectorPort ?? false
14441
+ )
14325
14442
  );
14326
14443
  }
14327
14444
  await initRunners(resolvedPluginConfig, viteDevServer, miniflare);
14328
14445
  const middleware = createMiddleware(
14329
14446
  async ({ request }) => {
14330
- assert8(miniflare, `Miniflare not defined`);
14447
+ assert10(miniflare, `Miniflare not defined`);
14331
14448
  const routerWorker = await getRouterWorker(miniflare);
14332
14449
  return routerWorker.fetch(toMiniflareRequest(request), {
14333
14450
  redirect: "manual"
@@ -14336,7 +14453,7 @@ function cloudflare2(pluginConfig = {}) {
14336
14453
  { alwaysCallNext: false }
14337
14454
  );
14338
14455
  handleWebSocket(viteDevServer.httpServer, async () => {
14339
- assert8(miniflare, `Miniflare not defined`);
14456
+ assert10(miniflare, `Miniflare not defined`);
14340
14457
  const routerWorker = await getRouterWorker(miniflare);
14341
14458
  return routerWorker.fetch;
14342
14459
  });
@@ -14346,14 +14463,18 @@ function cloudflare2(pluginConfig = {}) {
14346
14463
  });
14347
14464
  };
14348
14465
  },
14349
- configurePreviewServer(vitePreviewServer) {
14466
+ async configurePreviewServer(vitePreviewServer) {
14350
14467
  const workerConfigs = getWorkerConfigs(vitePreviewServer.config.root);
14468
+ const inputInspectorPort = await getInputInspectorPortOption(
14469
+ pluginConfig,
14470
+ vitePreviewServer
14471
+ );
14351
14472
  const miniflare2 = new Miniflare(
14352
14473
  getPreviewMiniflareOptions(
14353
14474
  vitePreviewServer,
14354
14475
  workerConfigs,
14355
14476
  pluginConfig.persistState ?? true,
14356
- pluginConfig.inspectorPort
14477
+ inputInspectorPort
14357
14478
  )
14358
14479
  );
14359
14480
  const middleware = createMiddleware(
@@ -14432,7 +14553,7 @@ function cloudflare2(pluginConfig = {}) {
14432
14553
  for (const match of matches) {
14433
14554
  magicString ??= new MagicString(code);
14434
14555
  const [full, _, modulePath] = match;
14435
- assert8(
14556
+ assert10(
14436
14557
  modulePath,
14437
14558
  `Unexpected error: module path not found in reference ${full}.`
14438
14559
  );
@@ -14478,17 +14599,21 @@ function cloudflare2(pluginConfig = {}) {
14478
14599
  configEnvironment(name) {
14479
14600
  if (isNodeCompat(getWorkerConfig2(name))) {
14480
14601
  return {
14602
+ build: {
14603
+ rollupOptions: {
14604
+ plugins: [
14605
+ replace({
14606
+ "process.env.NODE_ENV": JSON.stringify(
14607
+ process.env.NODE_ENV ?? "production"
14608
+ )
14609
+ })
14610
+ ]
14611
+ }
14612
+ },
14481
14613
  resolve: {
14482
14614
  builtins: [...nodeCompatExternals]
14483
14615
  },
14484
14616
  optimizeDeps: {
14485
- // This is a list of dependency entry-points that should be pre-bundled.
14486
- // In this case we provide a list of all the possible polyfills so that they are pre-bundled,
14487
- // ready ahead the first request to the dev server.
14488
- // Without this the dependency optimizer will try to bundle them on-the-fly in the middle of the first request,
14489
- // which can potentially cause problems if it leads to previous pre-bundling to become stale and needing to be reloaded.
14490
- // TODO: work out how to re-enable pre-bundling of these
14491
- // include: [...getNodeCompatEntries()],
14492
14617
  // This is a list of module specifiers that the dependency optimizer should not follow when doing import analysis.
14493
14618
  // In this case we provide a list of all the Node.js modules, both those built-in to workerd and those that will be polyfilled.
14494
14619
  // Obviously we don't want/need the optimizer to try to process modules that are built-in;
@@ -14512,7 +14637,7 @@ function cloudflare2(pluginConfig = {}) {
14512
14637
  return this.resolve(source, importer, options);
14513
14638
  }
14514
14639
  if (this.environment.mode === "dev") {
14515
- assert8(
14640
+ assert10(
14516
14641
  this.environment.depsOptimizer,
14517
14642
  "depsOptimizer is required in dev mode"
14518
14643
  );
@@ -14526,11 +14651,35 @@ function cloudflare2(pluginConfig = {}) {
14526
14651
  },
14527
14652
  async transform(code, id) {
14528
14653
  const workerConfig = getWorkerConfig2(this.environment.name);
14529
- assert8(workerConfig, "Expected a worker config");
14654
+ if (!workerConfig) {
14655
+ return;
14656
+ }
14530
14657
  const resolvedId = await this.resolve(workerConfig.main);
14531
14658
  if (id === resolvedId?.id) {
14532
14659
  return injectGlobalCode(id, code);
14533
14660
  }
14661
+ },
14662
+ async configureServer(viteDevServer) {
14663
+ await Promise.all(
14664
+ Object.values(viteDevServer.environments).flatMap(
14665
+ async (environment) => {
14666
+ const workerConfig = getWorkerConfig2(environment.name);
14667
+ if (isNodeCompat(workerConfig)) {
14668
+ await environment.depsOptimizer?.init();
14669
+ return Array.from(nodeCompatEntries).map((entry) => {
14670
+ const result = resolveNodeJSImport(entry);
14671
+ if (result) {
14672
+ const registration = environment.depsOptimizer?.registerMissingImport(
14673
+ result.unresolved,
14674
+ result.resolved
14675
+ );
14676
+ return registration?.processing;
14677
+ }
14678
+ });
14679
+ }
14680
+ }
14681
+ )
14682
+ );
14534
14683
  }
14535
14684
  },
14536
14685
  // Plugin that provides an __debug path for debugging the Cloudflare Workers.
@@ -14540,39 +14689,35 @@ function cloudflare2(pluginConfig = {}) {
14540
14689
  // the preview middleware here can take precedence
14541
14690
  enforce: "pre",
14542
14691
  configureServer(viteDevServer) {
14543
- if (resolvedPluginConfig.type === "workers" && resolvedPluginConfig.inspectorPort !== false) {
14692
+ if (resolvedPluginConfig.type === "workers" && pluginConfig.inspectorPort !== false) {
14544
14693
  addDebugToVitePrintUrls(viteDevServer);
14545
14694
  }
14546
14695
  const workerNames = resolvedPluginConfig.type === "assets-only" ? [] : Object.values(resolvedPluginConfig.workers).map(
14547
14696
  (worker) => worker.name
14548
14697
  );
14549
- viteDevServer.middlewares.use((req, res, next) => {
14550
- if (req.url === debuggingPath && resolvedPluginConfig.inspectorPort !== false) {
14551
- const html = getDebugPathHtml(
14552
- workerNames,
14553
- resolvedPluginConfig.inspectorPort
14554
- );
14698
+ viteDevServer.middlewares.use(async (req, res, next) => {
14699
+ const resolvedInspectorPort = await getResolvedInspectorPort(pluginConfig);
14700
+ if (req.url === debuggingPath && resolvedInspectorPort) {
14701
+ const html = getDebugPathHtml(workerNames, resolvedInspectorPort);
14555
14702
  res.setHeader("Content-Type", "text/html");
14556
14703
  return res.end(html);
14557
14704
  }
14558
14705
  next();
14559
14706
  });
14560
14707
  },
14561
- configurePreviewServer(vitePreviewServer) {
14708
+ async configurePreviewServer(vitePreviewServer) {
14562
14709
  const workerConfigs = getWorkerConfigs(vitePreviewServer.config.root);
14563
14710
  if (workerConfigs.length >= 1 && pluginConfig.inspectorPort !== false) {
14564
14711
  addDebugToVitePrintUrls(vitePreviewServer);
14565
14712
  }
14566
14713
  const workerNames = workerConfigs.map((worker) => {
14567
- assert8(worker.name, "Expected the Worker to have a name");
14714
+ assert10(worker.name, "Expected the Worker to have a name");
14568
14715
  return worker.name;
14569
14716
  });
14570
- vitePreviewServer.middlewares.use((req, res, next) => {
14571
- if (req.url === debuggingPath && pluginConfig.inspectorPort !== false) {
14572
- const html = getDebugPathHtml(
14573
- workerNames,
14574
- pluginConfig.inspectorPort ?? DEFAULT_INSPECTOR_PORT
14575
- );
14717
+ vitePreviewServer.middlewares.use(async (req, res, next) => {
14718
+ const resolvedInspectorPort = await getResolvedInspectorPort(pluginConfig);
14719
+ if (req.url === debuggingPath && resolvedInspectorPort) {
14720
+ const html = getDebugPathHtml(workerNames, resolvedInspectorPort);
14576
14721
  res.setHeader("Content-Type", "text/html");
14577
14722
  return res.end(html);
14578
14723
  }
@@ -14586,6 +14731,9 @@ function cloudflare2(pluginConfig = {}) {
14586
14731
  apply(_config, env2) {
14587
14732
  return !env2.isPreview;
14588
14733
  },
14734
+ // We must ensure that the `resolveId` hook runs before the built-in ones.
14735
+ // Otherwise we never see the Node.js built-in imports since they get handled by default Vite behavior.
14736
+ enforce: "pre",
14589
14737
  configEnvironment(environmentName) {
14590
14738
  const workerConfig = getWorkerConfig2(environmentName);
14591
14739
  if (workerConfig && !isNodeCompat(workerConfig)) {
@@ -14600,20 +14748,10 @@ function cloudflare2(pluginConfig = {}) {
14600
14748
  { filter: NODEJS_MODULES_RE },
14601
14749
  ({ path: path10, importer }) => {
14602
14750
  const nodeJsCompatWarnings = nodeJsCompatWarningsMap.get(workerConfig);
14603
- assert8(
14604
- nodeJsCompatWarnings,
14605
- `expected nodeJsCompatWarnings to be defined for Worker "${workerConfig.name}"`
14606
- );
14607
- nodeJsCompatWarnings.registerImport(path10, importer);
14751
+ nodeJsCompatWarnings?.registerImport(path10, importer);
14608
14752
  return { path: path10, external: true };
14609
14753
  }
14610
14754
  );
14611
- build.onEnd(() => {
14612
- const nodeJsCompatWarnings = nodeJsCompatWarningsMap.get(workerConfig);
14613
- if (nodeJsCompatWarnings) {
14614
- nodeJsCompatWarnings.renderWarnings();
14615
- }
14616
- });
14617
14755
  }
14618
14756
  }
14619
14757
  ]
@@ -14622,51 +14760,25 @@ function cloudflare2(pluginConfig = {}) {
14622
14760
  };
14623
14761
  }
14624
14762
  },
14625
- configureServer(viteDevServer) {
14626
- for (const environment of Object.values(viteDevServer.environments)) {
14627
- const workerConfig = getWorkerConfig2(environment.name);
14763
+ configResolved(resolvedViteConfig2) {
14764
+ for (const environmentName of Object.keys(
14765
+ resolvedViteConfig2.environments
14766
+ )) {
14767
+ const workerConfig = getWorkerConfig2(environmentName);
14628
14768
  if (workerConfig && !isNodeCompat(workerConfig)) {
14629
14769
  nodeJsCompatWarningsMap.set(
14630
14770
  workerConfig,
14631
- new NodeJsCompatWarnings(environment)
14771
+ new NodeJsCompatWarnings(environmentName, resolvedViteConfig2)
14632
14772
  );
14633
14773
  }
14634
14774
  }
14635
14775
  },
14636
- buildStart() {
14637
- const workerConfig = getWorkerConfig2(this.environment.name);
14638
- if (workerConfig && !isNodeCompat(workerConfig)) {
14639
- nodeJsCompatWarningsMap.set(
14640
- workerConfig,
14641
- new NodeJsCompatWarnings(this.environment)
14642
- );
14643
- }
14644
- },
14645
- buildEnd() {
14646
- const workerConfig = getWorkerConfig2(this.environment.name);
14647
- if (workerConfig && !isNodeCompat(workerConfig)) {
14648
- const nodeJsCompatWarnings = nodeJsCompatWarningsMap.get(workerConfig);
14649
- assert8(
14650
- nodeJsCompatWarnings,
14651
- `expected nodeJsCompatWarnings to be defined for Worker "${workerConfig.name}"`
14652
- );
14653
- nodeJsCompatWarnings.renderWarnings();
14654
- }
14655
- },
14656
- // We must ensure that the `resolveId` hook runs before the built-in ones otherwise we
14657
- // never see the Node.js built-in imports since they get handled by default Vite behavior.
14658
- enforce: "pre",
14659
14776
  async resolveId(source, importer) {
14660
14777
  const workerConfig = getWorkerConfig2(this.environment.name);
14661
14778
  if (workerConfig && !isNodeCompat(workerConfig)) {
14662
14779
  const nodeJsCompatWarnings = nodeJsCompatWarningsMap.get(workerConfig);
14663
- assert8(
14664
- nodeJsCompatWarnings,
14665
- `expected nodeJsCompatWarnings to be defined for Worker "${workerConfig.name}"`
14666
- );
14667
14780
  if (nodejsBuiltins.has(source)) {
14668
- nodeJsCompatWarnings.registerImport(source, importer);
14669
- nodeJsCompatWarnings.renderWarningsOnIdle();
14781
+ nodeJsCompatWarnings?.registerImport(source, importer);
14670
14782
  return {
14671
14783
  id: source,
14672
14784
  external: true
@@ -14677,10 +14789,29 @@ function cloudflare2(pluginConfig = {}) {
14677
14789
  }
14678
14790
  ];
14679
14791
  function getWorkerConfig2(environmentName) {
14680
- assert8(resolvedPluginConfig, "Expected resolvedPluginConfig to be defined");
14792
+ assert10(resolvedPluginConfig, "Expected resolvedPluginConfig to be defined");
14681
14793
  return resolvedPluginConfig.type !== "assets-only" ? resolvedPluginConfig.workers[environmentName] : void 0;
14682
14794
  }
14683
14795
  }
14796
+ async function getInputInspectorPortOption(pluginConfig, viteServer) {
14797
+ const inputInspectorPort = pluginConfig.inspectorPort ?? await getFirstAvailablePort(DEFAULT_INSPECTOR_PORT);
14798
+ if (pluginConfig.inspectorPort === void 0 && inputInspectorPort !== DEFAULT_INSPECTOR_PORT) {
14799
+ viteServer.config.logger.warn(
14800
+ colors2.dim(
14801
+ `Default inspector port ${DEFAULT_INSPECTOR_PORT} not available, using ${inputInspectorPort} instead
14802
+ `
14803
+ )
14804
+ );
14805
+ }
14806
+ return inputInspectorPort;
14807
+ }
14808
+ async function getResolvedInspectorPort(pluginConfig) {
14809
+ if (miniflare && pluginConfig.inspectorPort !== false) {
14810
+ const miniflareInspectorUrl = await miniflare.getInspectorURL();
14811
+ return Number.parseInt(miniflareInspectorUrl.port);
14812
+ }
14813
+ return null;
14814
+ }
14684
14815
  function getDotDevDotVarsContent(configPath, cloudflareEnv) {
14685
14816
  const configDir = path9.dirname(configPath);
14686
14817
  const defaultDotDevDotVarsPath = `${configDir}/.dev.vars`;
@@ -1394,13 +1394,6 @@ async function createModuleRunner(env, webSocket, viteRoot) {
1394
1394
  },
1395
1395
  {
1396
1396
  async runInlinedModule(context, transformed, module) {
1397
- if (module.file.includes("/node_modules") && !module.file.includes("/node_modules/.vite")) {
1398
- throw new Error(
1399
- `[Error] Trying to import non-prebundled module (only prebundled modules are allowed): ${module.id}
1400
-
1401
- (have you excluded the module via \`optimizeDeps.exclude\`?)`
1402
- );
1403
- }
1404
1397
  const codeDefinition = `'use strict';async (${Object.keys(context).join(
1405
1398
  ","
1406
1399
  )})=>{{`;
@@ -1426,13 +1419,6 @@ async function createModuleRunner(env, webSocket, viteRoot) {
1426
1419
  )
1427
1420
  });
1428
1421
  }
1429
- if (!additionalModuleRE.test(filepath) && filepath.includes("/node_modules") && !filepath.includes("/node_modules/.vite")) {
1430
- throw new Error(
1431
- `[Error] Trying to import non-prebundled module (only prebundled modules are allowed): ${filepath}
1432
-
1433
- (have you externalized the module via \`resolve.external\`?)`
1434
- );
1435
- }
1436
1422
  filepath = filepath.replace(/^file:\/\//, "");
1437
1423
  return import(filepath);
1438
1424
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudflare/vite-plugin",
3
- "version": "0.0.0-910007bce",
3
+ "version": "0.0.0-930ebb279",
4
4
  "description": "Cloudflare plugin for Vite",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -34,16 +34,18 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "@hattip/adapter-node": "^0.0.49",
37
+ "@rollup/plugin-replace": "^6.0.1",
38
+ "get-port": "^7.1.0",
37
39
  "picocolors": "^1.1.1",
38
40
  "tinyglobby": "^0.2.12",
39
41
  "unenv": "2.0.0-rc.15",
40
42
  "ws": "8.18.0",
41
- "@cloudflare/unenv-preset": "0.0.0-910007bce",
42
- "miniflare": "0.0.0-910007bce",
43
- "wrangler": "0.0.0-910007bce"
43
+ "miniflare": "0.0.0-930ebb279",
44
+ "@cloudflare/unenv-preset": "0.0.0-930ebb279",
45
+ "wrangler": "0.0.0-930ebb279"
44
46
  },
45
47
  "devDependencies": {
46
- "@cloudflare/workers-types": "^4.20250321.0",
48
+ "@cloudflare/workers-types": "^4.20250405.0",
47
49
  "@types/node": "^22.10.1",
48
50
  "@types/ws": "^8.5.13",
49
51
  "magic-string": "^0.30.12",
@@ -53,9 +55,9 @@
53
55
  "undici": "^5.28.5",
54
56
  "vite": "^6.1.0",
55
57
  "vitest": "~3.0.8",
56
- "@cloudflare/workers-shared": "0.0.0-910007bce",
57
58
  "@cloudflare/mock-npm-registry": "0.0.0",
58
- "@cloudflare/workers-tsconfig": "0.0.0"
59
+ "@cloudflare/workers-tsconfig": "0.0.0",
60
+ "@cloudflare/workers-shared": "0.0.0-930ebb279"
59
61
  },
60
62
  "peerDependencies": {
61
63
  "vite": "^6.1.0",