@cloudflare/vite-plugin 0.0.0-dbbeb23c7 → 0.0.0-dee6068af

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,6 +1,6 @@
1
1
  # `@cloudflare/vite-plugin`
2
2
 
3
- [Intro](#intro) | [Quick start](#quick-start) | [Tutorial](#tutorial) | [API](#api) | [Cloudflare environments](#cloudflare-environments) | [Migrating from `wrangler dev`](#migrating-from-wrangler-dev)
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
4
 
5
5
  ## Intro
6
6
 
@@ -374,6 +374,10 @@ It accepts an optional `PluginConfig` parameter.
374
374
  All requests are routed through your entry Worker.
375
375
  During the build, each Worker is output to a separate subdirectory of `dist`.
376
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
+
377
381
  > [!NOTE]
378
382
  > When running `wrangler deploy`, only your main (entry) Worker will be deployed.
379
383
  > If using multiple Workers, each must be deployed individually.
@@ -482,6 +486,62 @@ Secrets can be provided to your Worker in local development using a [`.dev.vars`
482
486
  > [!NOTE]
483
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.
484
488
 
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
+
485
545
  ## Migrating from `wrangler dev`
486
546
 
487
547
  Migrating from `wrangler dev` is a simple process and you can follow the instructions in the [Quick start](#quick-start) to get started.
package/dist/index.d.ts CHANGED
@@ -17,6 +17,7 @@ interface AuxiliaryWorkerConfig extends BaseWorkerConfig {
17
17
  interface PluginConfig extends EntryWorkerConfig {
18
18
  auxiliaryWorkers?: AuxiliaryWorkerConfig[];
19
19
  persistState?: PersistState;
20
+ inspectorPort?: number | false;
20
21
  }
21
22
 
22
23
  /**
@@ -28,4 +29,4 @@ interface PluginConfig extends EntryWorkerConfig {
28
29
  */
29
30
  declare function cloudflare(pluginConfig?: PluginConfig): vite.Plugin[];
30
31
 
31
- export { cloudflare };
32
+ export { type PluginConfig, cloudflare };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- import assert9 from "node:assert";
2
+ import assert8 from "node:assert";
3
3
  import * as fs5 from "node:fs";
4
4
  import * as fsp2 from "node:fs/promises";
5
5
  import { builtinModules as builtinModules2 } from "node:module";
@@ -1083,6 +1083,7 @@ var ADDITIONAL_MODULE_TYPES = [
1083
1083
  "Data",
1084
1084
  "Text"
1085
1085
  ];
1086
+ var DEFAULT_INSPECTOR_PORT = 9229;
1086
1087
 
1087
1088
  // src/additional-modules.ts
1088
1089
  var moduleRules = [
@@ -8150,6 +8151,9 @@ function getOutputDirectory(userConfig, environmentName) {
8150
8151
  const rootOutputDirectory = userConfig.build?.outDir ?? "dist";
8151
8152
  return userConfig.environments?.[environmentName]?.build?.outDir ?? path2.join(rootOutputDirectory, environmentName);
8152
8153
  }
8154
+ function getRouterWorker(miniflare) {
8155
+ return miniflare.getWorker(ROUTER_WORKER_NAME);
8156
+ }
8153
8157
  function toMiniflareRequest(request) {
8154
8158
  return new MiniflareRequest(request.url, {
8155
8159
  method: request.method,
@@ -8338,15 +8342,65 @@ function initRunners(resolvedPluginConfig, viteDevServer, miniflare) {
8338
8342
  );
8339
8343
  }
8340
8344
 
8341
- // src/deploy-config.ts
8345
+ // src/debugging.ts
8342
8346
  import assert4 from "node:assert";
8347
+ import colors from "picocolors";
8348
+ var debuggingPath = "/__debug";
8349
+ function addDebugToVitePrintUrls(server) {
8350
+ const originalPrintUrls = server.printUrls;
8351
+ server.printUrls = () => {
8352
+ originalPrintUrls();
8353
+ const localUrl = server.resolvedUrls?.local[0];
8354
+ if (localUrl) {
8355
+ const { protocol, hostname, port } = new URL(localUrl);
8356
+ const colorDebugUrl = (url) => colors.dim(
8357
+ colors.yellow(
8358
+ url.replace(/:(\d+)\//, (_, port2) => `:${colors.bold(port2)}/`)
8359
+ )
8360
+ );
8361
+ server.config.logger.info(
8362
+ ` ${colors.green("\u279C")} ${colors.bold("Debug")}: ${colorDebugUrl(`${protocol}//${hostname}:${port}${debuggingPath}`)}`
8363
+ );
8364
+ }
8365
+ };
8366
+ }
8367
+ function getDebugPathHtml(workerNames, inspectorPort) {
8368
+ assert4(workerNames.length >= 1, "no workers present to debug");
8369
+ const workerDevtoolsUrls = workerNames.map((workerName) => {
8370
+ const localHost = `localhost:${inspectorPort}/${workerName}`;
8371
+ const searchParams = new URLSearchParams({
8372
+ theme: "systemPreferred",
8373
+ debugger: "true",
8374
+ ws: localHost,
8375
+ domain: workerName
8376
+ });
8377
+ const devtoolsFrontendUrl = `https://devtools.devprod.cloudflare.dev/js_app?${searchParams}`;
8378
+ return devtoolsFrontendUrl;
8379
+ });
8380
+ return `
8381
+ <script>
8382
+ const workerUrls = ${JSON.stringify(workerDevtoolsUrls)};
8383
+ const [firstUrl, ...rest] = workerUrls;
8384
+ for (const workerUrl of rest) {
8385
+ // open new tabs for the devtools of the various workers
8386
+ window.open(workerUrl);
8387
+ }
8388
+ // redirect the current tab to the devtools of the first worker
8389
+ window.location.replace(firstUrl);
8390
+ </script>
8391
+ `;
8392
+ }
8393
+
8394
+ // src/deploy-config.ts
8395
+ import assert5 from "node:assert";
8343
8396
  import * as fs2 from "node:fs";
8344
8397
  import * as path3 from "node:path";
8345
8398
  import "vite";
8399
+ import { unstable_readConfig } from "wrangler";
8346
8400
  function getDeployConfigPath(root) {
8347
8401
  return path3.resolve(root, ".wrangler", "deploy", "config.json");
8348
8402
  }
8349
- function getWorkerConfigPaths(root) {
8403
+ function getWorkerConfigs(root) {
8350
8404
  const deployConfigPath = getDeployConfigPath(root);
8351
8405
  const deployConfig = JSON.parse(
8352
8406
  fs2.readFileSync(deployConfigPath, "utf-8")
@@ -8354,9 +8408,13 @@ function getWorkerConfigPaths(root) {
8354
8408
  return [
8355
8409
  { configPath: deployConfig.configPath },
8356
8410
  ...deployConfig.auxiliaryWorkers
8357
- ].map(
8358
- ({ configPath }) => path3.resolve(path3.dirname(deployConfigPath), configPath)
8359
- );
8411
+ ].map(({ configPath }) => {
8412
+ const resolvedConfigPath = path3.resolve(
8413
+ path3.dirname(deployConfigPath),
8414
+ configPath
8415
+ );
8416
+ return unstable_readConfig({ config: resolvedConfigPath });
8417
+ });
8360
8418
  }
8361
8419
  function getRelativePathToWorkerConfig(deployConfigDirectory, root, outputDirectory) {
8362
8420
  return path3.relative(
@@ -8370,7 +8428,7 @@ function writeDeployConfig(resolvedPluginConfig, resolvedViteConfig) {
8370
8428
  fs2.mkdirSync(deployConfigDirectory, { recursive: true });
8371
8429
  if (resolvedPluginConfig.type === "assets-only") {
8372
8430
  const clientOutputDirectory = resolvedViteConfig.environments.client?.build.outDir;
8373
- assert4(
8431
+ assert5(
8374
8432
  clientOutputDirectory,
8375
8433
  "Unexpected error: client environment output directory is undefined"
8376
8434
  );
@@ -8388,7 +8446,7 @@ function writeDeployConfig(resolvedPluginConfig, resolvedViteConfig) {
8388
8446
  const auxiliaryWorkers = [];
8389
8447
  for (const environmentName of Object.keys(resolvedPluginConfig.workers)) {
8390
8448
  const outputDirectory = resolvedViteConfig.environments[environmentName]?.build.outDir;
8391
- assert4(
8449
+ assert5(
8392
8450
  outputDirectory,
8393
8451
  `Unexpected error: ${environmentName} environment output directory is undefined`
8394
8452
  );
@@ -8403,7 +8461,7 @@ function writeDeployConfig(resolvedPluginConfig, resolvedViteConfig) {
8403
8461
  auxiliaryWorkers.push({ configPath });
8404
8462
  }
8405
8463
  }
8406
- assert4(
8464
+ assert5(
8407
8465
  entryWorkerConfigPath,
8408
8466
  `Unexpected error: entryWorkerConfigPath is undefined`
8409
8467
  );
@@ -8415,14 +8473,6 @@ function writeDeployConfig(resolvedPluginConfig, resolvedViteConfig) {
8415
8473
  }
8416
8474
  }
8417
8475
 
8418
- // src/dev.ts
8419
- import assert5 from "node:assert";
8420
- function getDevEntryWorker(resolvedPluginConfig, miniflare) {
8421
- const entryWorkerConfig = resolvedPluginConfig.type === "assets-only" ? resolvedPluginConfig.config : resolvedPluginConfig.workers[resolvedPluginConfig.entryWorkerEnvironmentName];
8422
- assert5(entryWorkerConfig, "Unexpected error: No entry worker configuration");
8423
- return entryWorkerConfig.assets ? miniflare.getWorker(ROUTER_WORKER_NAME) : miniflare.getWorker(entryWorkerConfig.name);
8424
- }
8425
-
8426
8476
  // src/miniflare-options.ts
8427
8477
  import assert6 from "node:assert";
8428
8478
  import * as fs3 from "node:fs";
@@ -8438,8 +8488,7 @@ import {
8438
8488
  import { globSync } from "tinyglobby";
8439
8489
  import "vite";
8440
8490
  import {
8441
- unstable_getMiniflareWorkerOptions,
8442
- unstable_readConfig
8491
+ unstable_getMiniflareWorkerOptions
8443
8492
  } from "wrangler";
8444
8493
  function getPersistence(root, persistState) {
8445
8494
  if (persistState === false) {
@@ -8633,6 +8682,7 @@ function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer) {
8633
8682
  worker: {
8634
8683
  ...workerOptions,
8635
8684
  name: workerOptions.name ?? workerConfig.name,
8685
+ unsafeInspectorProxy: resolvedPluginConfig.inspectorPort !== false,
8636
8686
  modulesRoot: miniflareModulesRoot,
8637
8687
  unsafeEvalBinding: "__VITE_UNSAFE_EVAL__",
8638
8688
  serviceBindings: {
@@ -8674,6 +8724,8 @@ function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer) {
8674
8724
  const logger = new ViteMiniflareLogger(resolvedViteConfig);
8675
8725
  return {
8676
8726
  log: logger,
8727
+ inspectorPort: resolvedPluginConfig.inspectorPort || void 0,
8728
+ unsafeInspectorProxy: resolvedPluginConfig.inspectorPort !== false,
8677
8729
  handleRuntimeStdio(stdout, stderr) {
8678
8730
  const decoder = new TextDecoder();
8679
8731
  stdout.forEach((data2) => logger.info(decoder.decode(data2)));
@@ -8810,12 +8862,8 @@ function getPreviewModules(main, modulesRules) {
8810
8862
  ]
8811
8863
  };
8812
8864
  }
8813
- function getPreviewMiniflareOptions(vitePreviewServer, persistState) {
8865
+ function getPreviewMiniflareOptions(vitePreviewServer, workerConfigs, persistState, inspectorPort = DEFAULT_INSPECTOR_PORT) {
8814
8866
  const resolvedViteConfig = vitePreviewServer.config;
8815
- const configPaths = getWorkerConfigPaths(resolvedViteConfig.root);
8816
- const workerConfigs = configPaths.map(
8817
- (configPath) => unstable_readConfig({ config: configPath })
8818
- );
8819
8867
  const workers = workerConfigs.flatMap((config) => {
8820
8868
  const miniflareWorkerOptions = unstable_getMiniflareWorkerOptions(config);
8821
8869
  const { externalWorkers } = miniflareWorkerOptions;
@@ -8824,6 +8872,7 @@ function getPreviewMiniflareOptions(vitePreviewServer, persistState) {
8824
8872
  {
8825
8873
  ...workerOptions,
8826
8874
  name: workerOptions.name ?? config.name,
8875
+ unsafeInspectorProxy: inspectorPort !== false,
8827
8876
  ...miniflareWorkerOptions.main ? getPreviewModules(miniflareWorkerOptions.main, modulesRules) : { modules: true, script: "" }
8828
8877
  },
8829
8878
  ...externalWorkers
@@ -8832,6 +8881,8 @@ function getPreviewMiniflareOptions(vitePreviewServer, persistState) {
8832
8881
  const logger = new ViteMiniflareLogger(resolvedViteConfig);
8833
8882
  return {
8834
8883
  log: logger,
8884
+ inspectorPort: inspectorPort || void 0,
8885
+ unsafeInspectorProxy: inspectorPort !== false,
8835
8886
  handleRuntimeStdio(stdout, stderr) {
8836
8887
  const decoder = new TextDecoder();
8837
8888
  stdout.forEach((data2) => logger.info(decoder.decode(data2)));
@@ -8877,15 +8928,14 @@ function miniflareLogLevelFromViteLogLevel(level = "info") {
8877
8928
  }
8878
8929
 
8879
8930
  // src/plugin-config.ts
8880
- import assert8 from "node:assert";
8931
+ import assert7 from "node:assert";
8881
8932
  import * as path6 from "node:path";
8882
8933
  import * as vite5 from "vite";
8883
8934
 
8884
8935
  // src/workers-configs.ts
8885
- import assert7 from "node:assert";
8886
8936
  import * as fs4 from "node:fs";
8887
8937
  import * as path5 from "node:path";
8888
- import { unstable_readConfig as unstable_readConfig2 } from "wrangler";
8938
+ import { unstable_readConfig as unstable_readConfig3 } from "wrangler";
8889
8939
  var nonApplicableWorkerConfigs = {
8890
8940
  /**
8891
8941
  * Object containing configs that have a vite replacement, the object's field contain details about the config's replacement
@@ -8936,7 +8986,7 @@ function readWorkerConfig(configPath, env2) {
8936
8986
  replacedByVite: /* @__PURE__ */ new Set(),
8937
8987
  notRelevant: /* @__PURE__ */ new Set()
8938
8988
  };
8939
- const config = unstable_readConfig2({ config: configPath, env: env2 }, {});
8989
+ const config = unstable_readConfig3({ config: configPath, env: env2 }, {});
8940
8990
  const raw = structuredClone(config);
8941
8991
  nullableNonApplicable.forEach((prop) => {
8942
8992
  if (config[prop] !== void 0) {
@@ -9037,34 +9087,38 @@ function getWorkerConfig(configPath, env2, opts) {
9037
9087
  }
9038
9088
  const { raw, config, nonApplicable } = readWorkerConfig(configPath, env2);
9039
9089
  opts?.visitedConfigPaths?.add(configPath);
9040
- assert7(
9041
- config.topLevelName,
9042
- missingFieldErrorMessage(`top-level 'name'`, configPath, env2)
9043
- );
9044
- assert7(config.name, missingFieldErrorMessage(`'name'`, configPath, env2));
9045
- assert7(
9046
- config.compatibility_date,
9047
- missingFieldErrorMessage(`'compatibility_date'`, configPath, env2)
9048
- );
9049
- if (opts?.isEntryWorker && !config.main) {
9050
- assert7(
9051
- config.assets,
9052
- missingFieldErrorMessage(`'main' or 'assets'`, configPath, env2)
9090
+ if (!config.name) {
9091
+ throw new Error(missingFieldErrorMessage(`'name'`, configPath, env2));
9092
+ }
9093
+ if (!config.topLevelName) {
9094
+ throw new Error(
9095
+ missingFieldErrorMessage(`top-level 'name'`, configPath, env2)
9053
9096
  );
9097
+ }
9098
+ if (!config.compatibility_date) {
9099
+ throw new Error(
9100
+ missingFieldErrorMessage(`'compatibility_date`, configPath, env2)
9101
+ );
9102
+ }
9103
+ const requiredFields = {
9104
+ topLevelName: config.topLevelName,
9105
+ name: config.name,
9106
+ compatibility_date: config.compatibility_date
9107
+ };
9108
+ if (opts?.isEntryWorker && !config.main) {
9054
9109
  return {
9055
9110
  type: "assets-only",
9056
9111
  raw,
9057
9112
  config: {
9058
9113
  ...config,
9059
- topLevelName: config.topLevelName,
9060
- name: config.name,
9061
- compatibility_date: config.compatibility_date,
9062
- assets: config.assets
9114
+ ...requiredFields
9063
9115
  },
9064
9116
  nonApplicable
9065
9117
  };
9066
9118
  }
9067
- assert7(config.main, missingFieldErrorMessage(`'main'`, configPath, env2));
9119
+ if (!config.main) {
9120
+ throw new Error(missingFieldErrorMessage(`'main'`, configPath, env2));
9121
+ }
9068
9122
  const mainStat = fs4.statSync(config.main, { throwIfNoEntry: false });
9069
9123
  if (!mainStat) {
9070
9124
  throw new Error(
@@ -9081,9 +9135,7 @@ function getWorkerConfig(configPath, env2, opts) {
9081
9135
  raw,
9082
9136
  config: {
9083
9137
  ...config,
9084
- topLevelName: config.topLevelName,
9085
- name: config.name,
9086
- compatibility_date: config.compatibility_date,
9138
+ ...requiredFields,
9087
9139
  main: config.main
9088
9140
  },
9089
9141
  nonApplicable
@@ -9105,6 +9157,7 @@ function workerNameToEnvironmentName(workerName) {
9105
9157
  function resolvePluginConfig(pluginConfig, userConfig, viteEnv) {
9106
9158
  const configPaths = /* @__PURE__ */ new Set();
9107
9159
  const persistState = pluginConfig.persistState ?? true;
9160
+ const inspectorPort = pluginConfig.inspectorPort ?? DEFAULT_INSPECTOR_PORT;
9108
9161
  const root = userConfig.root ? path6.resolve(userConfig.root) : process.cwd();
9109
9162
  const { CLOUDFLARE_ENV: cloudflareEnv } = vite5.loadEnv(
9110
9163
  viteEnv.mode,
@@ -9113,10 +9166,11 @@ function resolvePluginConfig(pluginConfig, userConfig, viteEnv) {
9113
9166
  ""
9114
9167
  );
9115
9168
  const configPath = pluginConfig.configPath ? path6.resolve(root, pluginConfig.configPath) : findWranglerConfig(root);
9116
- assert8(
9117
- configPath,
9118
- `Config not found. Have you created a wrangler.json(c) or wrangler.toml file?`
9119
- );
9169
+ if (!configPath) {
9170
+ throw new Error(
9171
+ `Config not found. Have you created a wrangler.json(c) or wrangler.toml file?`
9172
+ );
9173
+ }
9120
9174
  const entryWorkerResolvedConfig = getWorkerConfig(configPath, cloudflareEnv, {
9121
9175
  visitedConfigPaths: configPaths,
9122
9176
  isEntryWorker: true
@@ -9126,6 +9180,7 @@ function resolvePluginConfig(pluginConfig, userConfig, viteEnv) {
9126
9180
  type: "assets-only",
9127
9181
  config: entryWorkerResolvedConfig.config,
9128
9182
  configPaths,
9183
+ inspectorPort,
9129
9184
  persistState,
9130
9185
  rawConfigs: {
9131
9186
  entryWorker: entryWorkerResolvedConfig
@@ -9148,7 +9203,7 @@ function resolvePluginConfig(pluginConfig, userConfig, viteEnv) {
9148
9203
  }
9149
9204
  );
9150
9205
  auxiliaryWorkersResolvedConfigs.push(workerResolvedConfig);
9151
- assert8(
9206
+ assert7(
9152
9207
  workerResolvedConfig.type === "worker",
9153
9208
  "Unexpected error: received AssetsOnlyResult with auxiliary workers."
9154
9209
  );
@@ -9165,6 +9220,7 @@ function resolvePluginConfig(pluginConfig, userConfig, viteEnv) {
9165
9220
  type: "workers",
9166
9221
  configPaths,
9167
9222
  persistState,
9223
+ inspectorPort,
9168
9224
  workers,
9169
9225
  entryWorkerEnvironmentName,
9170
9226
  rawConfigs: {
@@ -9211,15 +9267,18 @@ function handleWebSocket(httpServer, fetcher) {
9211
9267
  }
9212
9268
 
9213
9269
  // src/index.ts
9270
+ var workersConfigsWarningShown = false;
9214
9271
  function cloudflare2(pluginConfig = {}) {
9215
9272
  let resolvedPluginConfig;
9216
9273
  let resolvedViteConfig;
9217
9274
  let miniflare;
9218
- let workersConfigsWarningShown = false;
9219
9275
  const additionalModulePaths = /* @__PURE__ */ new Set();
9276
+ let hasClientBuild = false;
9220
9277
  return [
9221
9278
  {
9222
9279
  name: "vite-plugin-cloudflare",
9280
+ // This only applies to this plugin so is safe to use while other plugins migrate to the Environment API
9281
+ sharedDuringBuild: true,
9223
9282
  config(userConfig, env2) {
9224
9283
  if (env2.isPreview) {
9225
9284
  return { appType: "custom" };
@@ -9276,7 +9335,7 @@ function cloudflare2(pluginConfig = {}) {
9276
9335
  resolvedPluginConfig.workers
9277
9336
  ).map((environmentName) => {
9278
9337
  const environment = builder.environments[environmentName];
9279
- assert9(
9338
+ assert8(
9280
9339
  environment,
9281
9340
  `${environmentName} environment not found`
9282
9341
  );
@@ -9292,6 +9351,9 @@ function cloudflare2(pluginConfig = {}) {
9292
9351
  }
9293
9352
  };
9294
9353
  },
9354
+ buildStart() {
9355
+ workersConfigsWarningShown = false;
9356
+ },
9295
9357
  configResolved(config) {
9296
9358
  resolvedViteConfig = config;
9297
9359
  },
@@ -9306,18 +9368,27 @@ function cloudflare2(pluginConfig = {}) {
9306
9368
  return;
9307
9369
  }
9308
9370
  workerConfig.main = entryChunk[0];
9371
+ workerConfig.no_bundle = true;
9372
+ workerConfig.rules = [
9373
+ { type: "ESModule", globs: ["**/*.js", "**/*.mjs"] }
9374
+ ];
9309
9375
  const isEntryWorker = this.environment.name === resolvedPluginConfig.entryWorkerEnvironmentName;
9310
- if (isEntryWorker && workerConfig.assets) {
9376
+ if (isEntryWorker && hasClientBuild) {
9311
9377
  const workerOutputDirectory = this.environment.config.build.outDir;
9312
9378
  const clientOutputDirectory = resolvedViteConfig.environments.client?.build.outDir;
9313
- assert9(
9379
+ assert8(
9314
9380
  clientOutputDirectory,
9315
9381
  "Unexpected error: client output directory is undefined"
9316
9382
  );
9317
- workerConfig.assets.directory = path7.relative(
9318
- path7.resolve(resolvedViteConfig.root, workerOutputDirectory),
9319
- path7.resolve(resolvedViteConfig.root, clientOutputDirectory)
9320
- );
9383
+ workerConfig.assets = {
9384
+ ...workerConfig.assets,
9385
+ directory: path7.relative(
9386
+ path7.resolve(resolvedViteConfig.root, workerOutputDirectory),
9387
+ path7.resolve(resolvedViteConfig.root, clientOutputDirectory)
9388
+ )
9389
+ };
9390
+ } else {
9391
+ workerConfig.assets = void 0;
9321
9392
  }
9322
9393
  config = workerConfig;
9323
9394
  if (workerConfig.configPath) {
@@ -9335,7 +9406,10 @@ function cloudflare2(pluginConfig = {}) {
9335
9406
  }
9336
9407
  } else if (this.environment.name === "client") {
9337
9408
  const assetsOnlyConfig = resolvedPluginConfig.config;
9338
- assetsOnlyConfig.assets.directory = ".";
9409
+ assetsOnlyConfig.assets = {
9410
+ ...assetsOnlyConfig.assets,
9411
+ directory: "."
9412
+ };
9339
9413
  const filesToAssetsIgnore = ["wrangler.json", ".dev.vars"];
9340
9414
  this.emitFile({
9341
9415
  type: "asset",
@@ -9348,8 +9422,6 @@ function cloudflare2(pluginConfig = {}) {
9348
9422
  if (!config) {
9349
9423
  return;
9350
9424
  }
9351
- config.no_bundle = true;
9352
- config.rules = [{ type: "ESModule", globs: ["**/*.js", "**/*.mjs"] }];
9353
9425
  if (config.unsafe && Object.keys(config.unsafe).length === 0) {
9354
9426
  config.unsafe = void 0;
9355
9427
  }
@@ -9360,6 +9432,9 @@ function cloudflare2(pluginConfig = {}) {
9360
9432
  });
9361
9433
  },
9362
9434
  writeBundle() {
9435
+ if (this.environment.name === "client") {
9436
+ hasClientBuild = true;
9437
+ }
9363
9438
  if (this.environment.name === (resolvedPluginConfig.type === "assets-only" ? "client" : resolvedPluginConfig.entryWorkerEnvironmentName)) {
9364
9439
  writeDeployConfig(resolvedPluginConfig, resolvedViteConfig);
9365
9440
  }
@@ -9376,7 +9451,7 @@ function cloudflare2(pluginConfig = {}) {
9376
9451
  }
9377
9452
  },
9378
9453
  async configureServer(viteDevServer) {
9379
- assert9(
9454
+ assert8(
9380
9455
  viteDevServer.httpServer,
9381
9456
  "Unexpected error: No Vite HTTP server"
9382
9457
  );
@@ -9384,19 +9459,16 @@ function cloudflare2(pluginConfig = {}) {
9384
9459
  getDevMiniflareOptions(resolvedPluginConfig, viteDevServer)
9385
9460
  );
9386
9461
  await initRunners(resolvedPluginConfig, viteDevServer, miniflare);
9387
- const entryWorker = await getDevEntryWorker(
9388
- resolvedPluginConfig,
9389
- miniflare
9390
- );
9462
+ const routerWorker = await getRouterWorker(miniflare);
9391
9463
  const middleware = createMiddleware(
9392
9464
  ({ request }) => {
9393
- return entryWorker.fetch(toMiniflareRequest(request), {
9465
+ return routerWorker.fetch(toMiniflareRequest(request), {
9394
9466
  redirect: "manual"
9395
9467
  });
9396
9468
  },
9397
9469
  { alwaysCallNext: false }
9398
9470
  );
9399
- handleWebSocket(viteDevServer.httpServer, entryWorker.fetch);
9471
+ handleWebSocket(viteDevServer.httpServer, routerWorker.fetch);
9400
9472
  return () => {
9401
9473
  viteDevServer.middlewares.use((req, res, next) => {
9402
9474
  middleware(req, res, next);
@@ -9404,10 +9476,13 @@ function cloudflare2(pluginConfig = {}) {
9404
9476
  };
9405
9477
  },
9406
9478
  configurePreviewServer(vitePreviewServer) {
9479
+ const workerConfigs = getWorkerConfigs(vitePreviewServer.config.root);
9407
9480
  const miniflare2 = new Miniflare(
9408
9481
  getPreviewMiniflareOptions(
9409
9482
  vitePreviewServer,
9410
- pluginConfig.persistState ?? true
9483
+ workerConfigs,
9484
+ pluginConfig.persistState ?? true,
9485
+ pluginConfig.inspectorPort
9411
9486
  )
9412
9487
  );
9413
9488
  const middleware = createMiddleware(
@@ -9424,6 +9499,25 @@ function cloudflare2(pluginConfig = {}) {
9424
9499
  });
9425
9500
  }
9426
9501
  },
9502
+ // Plugin to support `.wasm?init` extension
9503
+ {
9504
+ name: "vite-plugin-cloudflare:wasm-helper",
9505
+ enforce: "pre",
9506
+ applyToEnvironment(environment) {
9507
+ return getWorkerConfig2(environment.name) !== void 0;
9508
+ },
9509
+ load(id) {
9510
+ if (!id.endsWith(".wasm?init")) {
9511
+ return;
9512
+ }
9513
+ return `
9514
+ import wasm from "${cleanUrl(id)}";
9515
+ export default function(opts = {}) {
9516
+ return WebAssembly.instantiate(wasm, opts);
9517
+ }
9518
+ `;
9519
+ }
9520
+ },
9427
9521
  // Plugin to support additional modules
9428
9522
  {
9429
9523
  name: "vite-plugin-cloudflare:additional-modules",
@@ -9463,7 +9557,7 @@ function cloudflare2(pluginConfig = {}) {
9463
9557
  for (const match of matches) {
9464
9558
  magicString ??= new MagicString(code);
9465
9559
  const [full, _, modulePath] = match;
9466
- assert9(
9560
+ assert8(
9467
9561
  modulePath,
9468
9562
  `Unexpected error: module path not found in reference ${full}.`
9469
9563
  );
@@ -9546,7 +9640,7 @@ function cloudflare2(pluginConfig = {}) {
9546
9640
  return this.resolve(source, importer, options);
9547
9641
  }
9548
9642
  if (this.environment.mode === "dev") {
9549
- assert9(
9643
+ assert8(
9550
9644
  this.environment.depsOptimizer,
9551
9645
  "depsOptimizer is required in dev mode"
9552
9646
  );
@@ -9560,16 +9654,63 @@ function cloudflare2(pluginConfig = {}) {
9560
9654
  },
9561
9655
  async transform(code, id) {
9562
9656
  const workerConfig = getWorkerConfig2(this.environment.name);
9563
- assert9(workerConfig, "Expected a worker config");
9657
+ assert8(workerConfig, "Expected a worker config");
9564
9658
  const resolvedId = await this.resolve(workerConfig.main);
9565
9659
  if (id === resolvedId?.id) {
9566
9660
  return injectGlobalCode(id, code);
9567
9661
  }
9568
9662
  }
9663
+ },
9664
+ // Plugin that provides an __debug path for debugging the Cloudflare Workers.
9665
+ {
9666
+ name: "vite-plugin-cloudflare:debug",
9667
+ // Note: this plugin needs to run before the main vite-plugin-cloudflare so that
9668
+ // the preview middleware here can take precedence
9669
+ enforce: "pre",
9670
+ configureServer(viteDevServer) {
9671
+ if (resolvedPluginConfig.type === "workers" && resolvedPluginConfig.inspectorPort !== false) {
9672
+ addDebugToVitePrintUrls(viteDevServer);
9673
+ }
9674
+ const workerNames = resolvedPluginConfig.type === "assets-only" ? [] : Object.values(resolvedPluginConfig.workers).map(
9675
+ (worker) => worker.name
9676
+ );
9677
+ viteDevServer.middlewares.use((req, res, next) => {
9678
+ if (req.url === debuggingPath && resolvedPluginConfig.inspectorPort !== false) {
9679
+ const html = getDebugPathHtml(
9680
+ workerNames,
9681
+ resolvedPluginConfig.inspectorPort
9682
+ );
9683
+ res.setHeader("Content-Type", "text/html");
9684
+ return res.end(html);
9685
+ }
9686
+ next();
9687
+ });
9688
+ },
9689
+ configurePreviewServer(vitePreviewServer) {
9690
+ const workerConfigs = getWorkerConfigs(vitePreviewServer.config.root);
9691
+ if (workerConfigs.length >= 1 && pluginConfig.inspectorPort !== false) {
9692
+ addDebugToVitePrintUrls(vitePreviewServer);
9693
+ }
9694
+ const workerNames = workerConfigs.map((worker) => {
9695
+ assert8(worker.name);
9696
+ return worker.name;
9697
+ });
9698
+ vitePreviewServer.middlewares.use((req, res, next) => {
9699
+ if (req.url === debuggingPath && pluginConfig.inspectorPort !== false) {
9700
+ const html = getDebugPathHtml(
9701
+ workerNames,
9702
+ pluginConfig.inspectorPort ?? DEFAULT_INSPECTOR_PORT
9703
+ );
9704
+ res.setHeader("Content-Type", "text/html");
9705
+ return res.end(html);
9706
+ }
9707
+ next();
9708
+ });
9709
+ }
9569
9710
  }
9570
9711
  ];
9571
9712
  function getWorkerConfig2(environmentName) {
9572
- assert9(resolvedPluginConfig, "Expected resolvedPluginConfig to be defined");
9713
+ assert8(resolvedPluginConfig, "Expected resolvedPluginConfig to be defined");
9573
9714
  return resolvedPluginConfig.type !== "assets-only" ? resolvedPluginConfig.workers[environmentName] : void 0;
9574
9715
  }
9575
9716
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudflare/vite-plugin",
3
- "version": "0.0.0-dbbeb23c7",
3
+ "version": "0.0.0-dee6068af",
4
4
  "description": "Cloudflare plugin for Vite",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -34,15 +34,16 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "@hattip/adapter-node": "^0.0.49",
37
+ "picocolors": "^1.1.1",
37
38
  "tinyglobby": "^0.2.12",
38
39
  "unenv": "2.0.0-rc.15",
39
40
  "ws": "8.18.0",
40
- "@cloudflare/unenv-preset": "0.0.0-dbbeb23c7",
41
- "miniflare": "0.0.0-dbbeb23c7",
42
- "wrangler": "0.0.0-dbbeb23c7"
41
+ "miniflare": "0.0.0-dee6068af",
42
+ "wrangler": "0.0.0-dee6068af",
43
+ "@cloudflare/unenv-preset": "0.0.0-dee6068af"
43
44
  },
44
45
  "devDependencies": {
45
- "@cloudflare/workers-types": "^4.20250317.0",
46
+ "@cloudflare/workers-types": "^4.20250319.0",
46
47
  "@types/node": "^22.10.1",
47
48
  "@types/ws": "^8.5.13",
48
49
  "magic-string": "^0.30.12",
@@ -52,9 +53,9 @@
52
53
  "undici": "^5.28.5",
53
54
  "vite": "^6.1.0",
54
55
  "vitest": "~3.0.8",
55
- "@cloudflare/workers-shared": "0.0.0-dbbeb23c7",
56
+ "@cloudflare/mock-npm-registry": "0.0.0",
56
57
  "@cloudflare/workers-tsconfig": "0.0.0",
57
- "@cloudflare/mock-npm-registry": "0.0.0"
58
+ "@cloudflare/workers-shared": "0.0.0-dee6068af"
58
59
  },
59
60
  "peerDependencies": {
60
61
  "vite": "^6.1.0",