@cloudflare/vite-plugin 0.0.0-665ebd857 → 0.0.0-66edd2f3b

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/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
- import { createMiddleware } from "@hattip/adapter-node";
492
+ import { createRequest, sendResponse } from "@mjackson/node-fetch-server";
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 colors3 from "picocolors";
1560
1562
  import * as vite7 from "vite";
1561
1563
 
1562
1564
  // src/constants.ts
@@ -1569,6 +1571,7 @@ var ADDITIONAL_MODULE_TYPES = [
1569
1571
  "Text"
1570
1572
  ];
1571
1573
  var DEFAULT_INSPECTOR_PORT = 9229;
1574
+ var kRequestType = Symbol("kRequestType");
1572
1575
 
1573
1576
  // src/additional-modules.ts
1574
1577
  var moduleRules = [
@@ -1587,7 +1590,7 @@ function matchAdditionalModule(source) {
1587
1590
  return null;
1588
1591
  }
1589
1592
  function createModuleReference(type, id) {
1590
- return `__CLOUDFLARE_MODULE__${type}__${id}__`;
1593
+ return `__CLOUDFLARE_MODULE__${type}__${id}__CLOUDFLARE_MODULE__`;
1591
1594
  }
1592
1595
 
1593
1596
  // src/asset-config.ts
@@ -5782,7 +5785,8 @@ var z = /* @__PURE__ */ Object.freeze({
5782
5785
  // ../workers-shared/utils/types.ts
5783
5786
  var InternalConfigSchema = z.object({
5784
5787
  account_id: z.number().optional(),
5785
- script_id: z.number().optional()
5788
+ script_id: z.number().optional(),
5789
+ debug: z.boolean().optional()
5786
5790
  });
5787
5791
  var RouterConfigSchema = z.object({
5788
5792
  invoke_user_worker_ahead_of_assets: z.boolean().optional(),
@@ -5830,14 +5834,14 @@ var AssetConfigSchema = z.object({
5830
5834
  });
5831
5835
 
5832
5836
  // src/asset-config.ts
5833
- function hasAssetsConfigChanged(resolvedPluginConfig, resolvedViteConfig, changedFile) {
5837
+ function hasAssetsConfigChanged(resolvedPluginConfig, resolvedViteConfig, changedFilePath) {
5834
5838
  if (!resolvedPluginConfig.experimental?.headersAndRedirectsDevModeSupport) {
5835
5839
  return false;
5836
5840
  }
5837
5841
  return [
5838
5842
  getRedirectsConfigPath(resolvedViteConfig),
5839
5843
  getHeadersConfigPath(resolvedViteConfig)
5840
- ].includes(path.resolve(changedFile));
5844
+ ].includes(changedFilePath);
5841
5845
  }
5842
5846
  function getAssetsConfig(resolvedPluginConfig, entryWorkerConfig, resolvedConfig) {
5843
5847
  const assetsConfig = resolvedPluginConfig.type === "assets-only" ? resolvedPluginConfig.config.assets : entryWorkerConfig?.assets;
@@ -12645,8 +12649,8 @@ function packageResolve(specifier, base, conditions) {
12645
12649
  let packageJsonPath = fileURLToPath$1(packageJsonUrl);
12646
12650
  let lastPath;
12647
12651
  do {
12648
- const stat = tryStatSync(packageJsonPath.slice(0, -13));
12649
- if (!stat || !stat.isDirectory()) {
12652
+ const stat2 = tryStatSync(packageJsonPath.slice(0, -13));
12653
+ if (!stat2 || !stat2.isDirectory()) {
12650
12654
  lastPath = packageJsonPath;
12651
12655
  packageJsonUrl = new URL$1(
12652
12656
  (isScoped ? "../../../../node_modules/" : "../../../node_modules/") + packageName + "/package.json",
@@ -12776,8 +12780,8 @@ function _resolve(id, options = {}) {
12776
12780
  }
12777
12781
  if (isAbsolute(id)) {
12778
12782
  try {
12779
- const stat = statSync(id);
12780
- if (stat.isFile()) {
12783
+ const stat2 = statSync(id);
12784
+ if (stat2.isFile()) {
12781
12785
  return pathToFileURL(id);
12782
12786
  }
12783
12787
  } catch (error) {
@@ -12878,6 +12882,15 @@ function isNodeCompat(workerConfig) {
12878
12882
  }
12879
12883
  return false;
12880
12884
  }
12885
+ function isNodeAls(workerConfig) {
12886
+ return workerConfig !== void 0 && getNodeCompat(
12887
+ workerConfig.compatibility_date,
12888
+ workerConfig.compatibility_flags ?? []
12889
+ ).mode === "als";
12890
+ }
12891
+ function isNodeAlsModule(path10) {
12892
+ return /^(node:)?async_hooks$/.test(path10);
12893
+ }
12881
12894
  function injectGlobalCode(id, code) {
12882
12895
  const injectedCode = Object.entries(env.inject).map(([globalName, globalInject]) => {
12883
12896
  if (typeof globalInject === "string") {
@@ -12908,7 +12921,7 @@ globalThis.${globalName} = var_${globalName}.${exportName};
12908
12921
  }
12909
12922
  function resolveNodeJSImport(source) {
12910
12923
  const alias = env.alias[source];
12911
- if (alias) {
12924
+ if (alias && !nodeCompatExternals.has(alias)) {
12912
12925
  return {
12913
12926
  unresolved: alias,
12914
12927
  resolved: resolvePathSync(alias, { url: import.meta.url })
@@ -12939,8 +12952,9 @@ function getNodeCompatEntries() {
12939
12952
  return entries;
12940
12953
  }
12941
12954
  var NodeJsCompatWarnings = class {
12942
- constructor(environment) {
12943
- this.environment = environment;
12955
+ constructor(environmentName, resolvedViteConfig) {
12956
+ this.environmentName = environmentName;
12957
+ this.resolvedViteConfig = resolvedViteConfig;
12944
12958
  }
12945
12959
  sources = /* @__PURE__ */ new Map();
12946
12960
  timer;
@@ -12948,6 +12962,7 @@ var NodeJsCompatWarnings = class {
12948
12962
  const importers = this.sources.get(source) ?? /* @__PURE__ */ new Set();
12949
12963
  this.sources.set(source, importers);
12950
12964
  importers.add(importer);
12965
+ this.renderWarningsOnIdle();
12951
12966
  }
12952
12967
  renderWarningsOnIdle() {
12953
12968
  if (this.timer) {
@@ -12960,19 +12975,16 @@ var NodeJsCompatWarnings = class {
12960
12975
  }
12961
12976
  renderWarnings() {
12962
12977
  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.
12978
+ 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
12979
  `;
12968
12980
  this.sources.forEach((importers, source) => {
12969
12981
  importers.forEach((importer) => {
12970
- message += ` - "${source}" imported from "${path3.relative(this.environment.config.root, importer)}"
12982
+ message += ` - "${source}" imported from "${path3.relative(this.resolvedViteConfig.root, importer)}"
12971
12983
  `;
12972
12984
  });
12973
12985
  });
12974
- this.environment.logger.warn(message, {
12975
- environment: this.environment.name
12986
+ this.resolvedViteConfig.logger.warn(message, {
12987
+ timestamp: true
12976
12988
  });
12977
12989
  this.sources.clear();
12978
12990
  }
@@ -12982,7 +12994,7 @@ Refer to https://developers.cloudflare.com/workers/runtime-apis/nodejs/ for more
12982
12994
  // src/shared.ts
12983
12995
  var UNKNOWN_HOST = "http://localhost";
12984
12996
  var INIT_PATH = "/__vite_plugin_cloudflare_init__";
12985
- var ADDITIONAL_MODULE_PATTERN = `__CLOUDFLARE_MODULE__(${ADDITIONAL_MODULE_TYPES.join("|")})__(.*?)__`;
12997
+ var ADDITIONAL_MODULE_PATTERN = `__CLOUDFLARE_MODULE__(${ADDITIONAL_MODULE_TYPES.join("|")})__(.*?)__CLOUDFLARE_MODULE__`;
12986
12998
  var additionalModuleRE = new RegExp(ADDITIONAL_MODULE_PATTERN);
12987
12999
  var additionalModuleGlobalRE = new RegExp(
12988
13000
  ADDITIONAL_MODULE_PATTERN,
@@ -12992,15 +13004,13 @@ var VITE_DEV_METADATA_HEADER = "__VITE_DEV_METADATA__";
12992
13004
 
12993
13005
  // src/utils.ts
12994
13006
  import * as path4 from "node:path";
13007
+ import getPort, { portNumbers } from "get-port";
12995
13008
  import { Request as MiniflareRequest } from "miniflare";
12996
13009
  import "vite";
12997
13010
  function getOutputDirectory(userConfig, environmentName) {
12998
13011
  const rootOutputDirectory = userConfig.build?.outDir ?? "dist";
12999
13012
  return userConfig.environments?.[environmentName]?.build?.outDir ?? path4.join(rootOutputDirectory, environmentName);
13000
13013
  }
13001
- function getRouterWorker(miniflare2) {
13002
- return miniflare2.getWorker(ROUTER_WORKER_NAME);
13003
- }
13004
13014
  function toMiniflareRequest(request) {
13005
13015
  const host = request.headers.get("Host");
13006
13016
  if (host) {
@@ -13017,23 +13027,13 @@ function toMiniflareRequest(request) {
13017
13027
  duplex: "half"
13018
13028
  });
13019
13029
  }
13020
- function nodeHeadersToWebHeaders(nodeHeaders) {
13021
- const headers = new Headers();
13022
- for (const [key, value] of Object.entries(nodeHeaders)) {
13023
- if (typeof value === "string") {
13024
- headers.append(key, value);
13025
- } else if (Array.isArray(value)) {
13026
- for (const item of value) {
13027
- headers.append(key, item);
13028
- }
13029
- }
13030
- }
13031
- return headers;
13032
- }
13033
13030
  var postfixRE = /[?#].*$/;
13034
13031
  function cleanUrl(url) {
13035
13032
  return url.replace(postfixRE, "");
13036
13033
  }
13034
+ function getFirstAvailablePort(start) {
13035
+ return getPort({ port: portNumbers(start, 65535) });
13036
+ }
13037
13037
 
13038
13038
  // src/cloudflare-environment.ts
13039
13039
  var webSocketUndefinedError = "The WebSocket is undefined";
@@ -13255,7 +13255,7 @@ import { unstable_readConfig } from "wrangler";
13255
13255
  function getDeployConfigPath(root) {
13256
13256
  return path5.resolve(root, ".wrangler", "deploy", "config.json");
13257
13257
  }
13258
- function getWorkerConfigs(root) {
13258
+ function getWorkerConfigs(root, mixedModeEnabled) {
13259
13259
  const deployConfigPath = getDeployConfigPath(root);
13260
13260
  const deployConfig = JSON.parse(
13261
13261
  fs2.readFileSync(deployConfigPath, "utf-8")
@@ -13268,7 +13268,10 @@ function getWorkerConfigs(root) {
13268
13268
  path5.dirname(deployConfigPath),
13269
13269
  configPath
13270
13270
  );
13271
- return unstable_readConfig({ config: resolvedConfigPath });
13271
+ return unstable_readConfig(
13272
+ { config: resolvedConfigPath },
13273
+ { experimental: { mixedModeEnabled } }
13274
+ );
13272
13275
  });
13273
13276
  }
13274
13277
  function getRelativePathToWorkerConfig(deployConfigDirectory, root, outputDirectory) {
@@ -13335,17 +13338,24 @@ import * as fsp from "node:fs/promises";
13335
13338
  import * as path6 from "node:path";
13336
13339
  import { fileURLToPath as fileURLToPath2 } from "node:url";
13337
13340
  import {
13341
+ getDefaultDevRegistryPath,
13338
13342
  kCurrentWorker,
13339
13343
  Log,
13340
13344
  LogLevel,
13341
13345
  Response as MiniflareResponse
13342
13346
  } from "miniflare";
13347
+ import colors2 from "picocolors";
13343
13348
  import { globSync } from "tinyglobby";
13344
13349
  import "vite";
13345
- import { unstable_getMiniflareWorkerOptions } from "wrangler";
13346
- function getPersistence(root, persistState) {
13350
+ import {
13351
+ experimental_pickRemoteBindings,
13352
+ experimental_startMixedModeSession,
13353
+ unstable_convertConfigBindingsToStartWorkerBindings,
13354
+ unstable_getMiniflareWorkerOptions
13355
+ } from "wrangler";
13356
+ function getPersistenceRoot(root, persistState) {
13347
13357
  if (persistState === false) {
13348
- return {};
13358
+ return;
13349
13359
  }
13350
13360
  const defaultPersistPath = ".wrangler/state";
13351
13361
  const persistPath = path6.resolve(
@@ -13353,14 +13363,7 @@ function getPersistence(root, persistState) {
13353
13363
  typeof persistState === "object" ? persistState.path : defaultPersistPath,
13354
13364
  "v3"
13355
13365
  );
13356
- return {
13357
- cachePersist: path6.join(persistPath, "cache"),
13358
- d1Persist: path6.join(persistPath, "d1"),
13359
- durableObjectsPersist: path6.join(persistPath, "do"),
13360
- kvPersist: path6.join(persistPath, "kv"),
13361
- r2Persist: path6.join(persistPath, "r2"),
13362
- workflowsPersist: path6.join(persistPath, "workflows")
13363
- };
13366
+ return persistPath;
13364
13367
  }
13365
13368
  function missingWorkerErrorMessage(workerName) {
13366
13369
  return `${workerName} does not match a worker name.`;
@@ -13444,7 +13447,29 @@ function getEntryWorkerConfig(resolvedPluginConfig) {
13444
13447
  }
13445
13448
  return resolvedPluginConfig.workers[resolvedPluginConfig.entryWorkerEnvironmentName];
13446
13449
  }
13447
- function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer) {
13450
+ function logUnknownTails(tails, userWorkers, log) {
13451
+ for (const tailService of tails ?? []) {
13452
+ let name;
13453
+ if (typeof tailService === "string") {
13454
+ name = tailService;
13455
+ } else if (typeof tailService === "object" && "name" in tailService && typeof tailService.name === "string") {
13456
+ name = tailService.name;
13457
+ } else {
13458
+ continue;
13459
+ }
13460
+ const found = userWorkers.some((w) => w.name === name);
13461
+ if (!found) {
13462
+ log(
13463
+ colors2.dim(
13464
+ colors2.yellow(
13465
+ `Tail consumer "${name}" was not found in your config. Make sure you add it to the config or run it in another dev session if you'd like to simulate receiving tail events locally.`
13466
+ )
13467
+ )
13468
+ );
13469
+ }
13470
+ }
13471
+ }
13472
+ async function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer, inspectorPort) {
13448
13473
  const resolvedViteConfig = viteDevServer.config;
13449
13474
  const entryWorkerConfig = getEntryWorkerConfig(resolvedPluginConfig);
13450
13475
  const assetsConfig = getAssetsConfig(
@@ -13495,12 +13520,14 @@ function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer) {
13495
13520
  serviceBindings: {
13496
13521
  __VITE_ASSET_EXISTS__: async (request) => {
13497
13522
  const { pathname } = new URL(request.url);
13498
- const filePath = path6.join(resolvedViteConfig.root, pathname);
13499
- let exists;
13500
- try {
13501
- exists = fs3.statSync(filePath).isFile();
13502
- } catch (error) {
13503
- exists = false;
13523
+ let exists = false;
13524
+ if (pathname.endsWith(".html")) {
13525
+ try {
13526
+ const filePath = path6.join(resolvedViteConfig.root, pathname);
13527
+ const stats = await fsp.stat(filePath);
13528
+ exists = stats.isFile();
13529
+ } catch (error) {
13530
+ }
13504
13531
  }
13505
13532
  return MiniflareResponse.json(exists);
13506
13533
  },
@@ -13514,59 +13541,75 @@ function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer) {
13514
13541
  headers: { "Content-Type": "text/html" }
13515
13542
  });
13516
13543
  } catch (error) {
13517
- throw new Error(`Unexpected error. Failed to load ${pathname}`);
13544
+ throw new Error(`Unexpected error. Failed to load "${pathname}".`);
13518
13545
  }
13519
13546
  }
13520
13547
  }
13521
13548
  }
13522
13549
  ];
13523
- const workersFromConfig = resolvedPluginConfig.type === "workers" ? Object.entries(resolvedPluginConfig.workers).map(
13524
- ([environmentName, workerConfig]) => {
13525
- const miniflareWorkerOptions = unstable_getMiniflareWorkerOptions(
13526
- {
13527
- ...workerConfig,
13528
- assets: void 0
13529
- },
13530
- resolvedPluginConfig.cloudflareEnv
13531
- );
13532
- const { externalWorkers: externalWorkers2 } = miniflareWorkerOptions;
13533
- const { ratelimits, ...workerOptions } = miniflareWorkerOptions.workerOptions;
13534
- return {
13535
- externalWorkers: externalWorkers2,
13536
- worker: {
13537
- ...workerOptions,
13538
- name: workerOptions.name ?? workerConfig.name,
13539
- unsafeInspectorProxy: resolvedPluginConfig.inspectorPort !== false,
13540
- modulesRoot: miniflareModulesRoot,
13541
- unsafeEvalBinding: "__VITE_UNSAFE_EVAL__",
13542
- serviceBindings: {
13543
- ...workerOptions.serviceBindings,
13544
- ...environmentName === resolvedPluginConfig.entryWorkerEnvironmentName && workerConfig.assets?.binding ? {
13545
- [workerConfig.assets.binding]: ASSET_WORKER_NAME
13546
- } : {},
13547
- __VITE_INVOKE_MODULE__: async (request) => {
13548
- const payload = await request.json();
13549
- const invokePayloadData = payload.data;
13550
- assert6(
13551
- invokePayloadData.name === "fetchModule",
13552
- `Invalid invoke event: ${invokePayloadData.name}`
13553
- );
13554
- const [moduleId] = invokePayloadData.data;
13555
- if (additionalModuleRE.test(moduleId)) {
13556
- const result2 = {
13557
- externalize: moduleId,
13558
- type: "module"
13559
- };
13560
- return MiniflareResponse.json({ result: result2 });
13550
+ const workersFromConfig = resolvedPluginConfig.type === "workers" ? await Promise.all(
13551
+ Object.entries(resolvedPluginConfig.workers).map(
13552
+ async ([environmentName, workerConfig]) => {
13553
+ const mixedModeSession = resolvedPluginConfig.experimental.mixedMode ? await maybeStartOrUpdateMixedModeSession(workerConfig) : void 0;
13554
+ const miniflareWorkerOptions = unstable_getMiniflareWorkerOptions(
13555
+ {
13556
+ ...workerConfig,
13557
+ assets: void 0
13558
+ },
13559
+ resolvedPluginConfig.cloudflareEnv,
13560
+ {
13561
+ mixedModeConnectionString: mixedModeSession?.mixedModeConnectionString,
13562
+ mixedModeEnabled: resolvedPluginConfig.experimental.mixedMode
13563
+ }
13564
+ );
13565
+ const { externalWorkers: externalWorkers2 } = miniflareWorkerOptions;
13566
+ const { ratelimits, ...workerOptions } = miniflareWorkerOptions.workerOptions;
13567
+ return {
13568
+ externalWorkers: externalWorkers2,
13569
+ worker: {
13570
+ ...workerOptions,
13571
+ name: workerOptions.name ?? workerConfig.name,
13572
+ unsafeInspectorProxy: inspectorPort !== false,
13573
+ unsafeDirectSockets: environmentName === resolvedPluginConfig.entryWorkerEnvironmentName ? (
13574
+ // Expose the default entrypoint of the entry worker on the dev registry
13575
+ [{ entrypoint: void 0, proxy: true }]
13576
+ ) : [],
13577
+ modulesRoot: miniflareModulesRoot,
13578
+ unsafeEvalBinding: "__VITE_UNSAFE_EVAL__",
13579
+ serviceBindings: {
13580
+ ...workerOptions.serviceBindings,
13581
+ ...environmentName === resolvedPluginConfig.entryWorkerEnvironmentName && workerConfig.assets?.binding ? {
13582
+ [workerConfig.assets.binding]: {
13583
+ node: (req, res) => {
13584
+ req[kRequestType] = "asset";
13585
+ viteDevServer.middlewares(req, res);
13586
+ }
13587
+ }
13588
+ } : {},
13589
+ __VITE_INVOKE_MODULE__: async (request) => {
13590
+ const payload = await request.json();
13591
+ const invokePayloadData = payload.data;
13592
+ assert6(
13593
+ invokePayloadData.name === "fetchModule",
13594
+ `Invalid invoke event: ${invokePayloadData.name}`
13595
+ );
13596
+ const [moduleId] = invokePayloadData.data;
13597
+ if (additionalModuleRE.test(moduleId)) {
13598
+ const result2 = {
13599
+ externalize: moduleId,
13600
+ type: "module"
13601
+ };
13602
+ return MiniflareResponse.json({ result: result2 });
13603
+ }
13604
+ const devEnvironment = viteDevServer.environments[environmentName];
13605
+ const result = await devEnvironment.hot.handleInvoke(payload);
13606
+ return MiniflareResponse.json(result);
13561
13607
  }
13562
- const devEnvironment = viteDevServer.environments[environmentName];
13563
- const result = await devEnvironment.hot.handleInvoke(payload);
13564
- return MiniflareResponse.json(result);
13565
13608
  }
13566
13609
  }
13567
- }
13568
- };
13569
- }
13610
+ };
13611
+ }
13612
+ )
13570
13613
  ) : [];
13571
13614
  const userWorkers = workersFromConfig.map((options) => options.worker);
13572
13615
  const externalWorkers = workersFromConfig.flatMap(
@@ -13578,8 +13621,10 @@ function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer) {
13578
13621
  const logger = new ViteMiniflareLogger(resolvedViteConfig);
13579
13622
  return {
13580
13623
  log: logger,
13581
- inspectorPort: resolvedPluginConfig.inspectorPort || void 0,
13582
- unsafeInspectorProxy: resolvedPluginConfig.inspectorPort !== false,
13624
+ logRequests: false,
13625
+ inspectorPort: inspectorPort === false ? void 0 : inspectorPort,
13626
+ unsafeInspectorProxy: inspectorPort !== false,
13627
+ unsafeDevRegistryPath: getDefaultDevRegistryPath(),
13583
13628
  handleRuntimeStdio(stdout, stderr) {
13584
13629
  const decoder = new TextDecoder();
13585
13630
  stdout.forEach((data2) => logger.info(decoder.decode(data2)));
@@ -13587,7 +13632,7 @@ function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer) {
13587
13632
  (error) => logger.logWithLevel(LogLevel.ERROR, decoder.decode(error))
13588
13633
  );
13589
13634
  },
13590
- ...getPersistence(
13635
+ defaultPersistRoot: getPersistenceRoot(
13591
13636
  resolvedViteConfig.root,
13592
13637
  resolvedPluginConfig.persistState
13593
13638
  ),
@@ -13633,6 +13678,11 @@ function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer) {
13633
13678
  `export const ${className} = createWorkflowEntrypointWrapper('${className}');`
13634
13679
  );
13635
13680
  }
13681
+ logUnknownTails(
13682
+ workerOptions.tails,
13683
+ userWorkers,
13684
+ viteDevServer.config.logger.warn
13685
+ );
13636
13686
  return {
13637
13687
  ...workerOptions,
13638
13688
  modules: [
@@ -13716,27 +13766,48 @@ function getPreviewModules(main, modulesRules) {
13716
13766
  ]
13717
13767
  };
13718
13768
  }
13719
- function getPreviewMiniflareOptions(vitePreviewServer, workerConfigs, persistState, inspectorPort = DEFAULT_INSPECTOR_PORT) {
13769
+ async function getPreviewMiniflareOptions(vitePreviewServer, workerConfigs, persistState, mixedModeEnabled, inspectorPort) {
13720
13770
  const resolvedViteConfig = vitePreviewServer.config;
13721
- const workers = workerConfigs.flatMap((config) => {
13722
- const miniflareWorkerOptions = unstable_getMiniflareWorkerOptions(config);
13723
- const { externalWorkers } = miniflareWorkerOptions;
13724
- const { ratelimits, modulesRules, ...workerOptions } = miniflareWorkerOptions.workerOptions;
13725
- return [
13726
- {
13727
- ...workerOptions,
13728
- name: workerOptions.name ?? config.name,
13729
- unsafeInspectorProxy: inspectorPort !== false,
13730
- ...miniflareWorkerOptions.main ? getPreviewModules(miniflareWorkerOptions.main, modulesRules) : { modules: true, script: "" }
13731
- },
13732
- ...externalWorkers
13733
- ];
13734
- });
13771
+ const workers = (await Promise.all(
13772
+ workerConfigs.map(async (workerConfig, i) => {
13773
+ const mixedModeSession = mixedModeEnabled ? await maybeStartOrUpdateMixedModeSession(workerConfig) : void 0;
13774
+ const miniflareWorkerOptions = unstable_getMiniflareWorkerOptions(
13775
+ workerConfig,
13776
+ void 0,
13777
+ {
13778
+ mixedModeConnectionString: mixedModeSession?.mixedModeConnectionString,
13779
+ mixedModeEnabled
13780
+ }
13781
+ );
13782
+ const { externalWorkers } = miniflareWorkerOptions;
13783
+ const { ratelimits, modulesRules, ...workerOptions } = miniflareWorkerOptions.workerOptions;
13784
+ logUnknownTails(
13785
+ workerOptions.tails,
13786
+ workerConfigs,
13787
+ vitePreviewServer.config.logger.warn
13788
+ );
13789
+ return [
13790
+ {
13791
+ ...workerOptions,
13792
+ name: workerOptions.name ?? workerConfig.name,
13793
+ unsafeInspectorProxy: inspectorPort !== false,
13794
+ unsafeDirectSockets: (
13795
+ // This exposes the default entrypoint of the entry worker on the dev registry
13796
+ // Assuming that the first worker config to be the entry worker.
13797
+ i === 0 ? [{ entrypoint: void 0, proxy: true }] : []
13798
+ ),
13799
+ ...miniflareWorkerOptions.main ? getPreviewModules(miniflareWorkerOptions.main, modulesRules) : { modules: true, script: "" }
13800
+ },
13801
+ ...externalWorkers
13802
+ ];
13803
+ })
13804
+ )).flat();
13735
13805
  const logger = new ViteMiniflareLogger(resolvedViteConfig);
13736
13806
  return {
13737
13807
  log: logger,
13738
- inspectorPort: inspectorPort || void 0,
13808
+ inspectorPort: inspectorPort === false ? void 0 : inspectorPort,
13739
13809
  unsafeInspectorProxy: inspectorPort !== false,
13810
+ unsafeDevRegistryPath: getDefaultDevRegistryPath(),
13740
13811
  handleRuntimeStdio(stdout, stderr) {
13741
13812
  const decoder = new TextDecoder();
13742
13813
  stdout.forEach((data2) => logger.info(decoder.decode(data2)));
@@ -13744,11 +13815,13 @@ function getPreviewMiniflareOptions(vitePreviewServer, workerConfigs, persistSta
13744
13815
  (error) => logger.logWithLevel(LogLevel.ERROR, decoder.decode(error))
13745
13816
  );
13746
13817
  },
13747
- ...getPersistence(resolvedViteConfig.root, persistState),
13818
+ defaultPersistRoot: getPersistenceRoot(
13819
+ resolvedViteConfig.root,
13820
+ persistState
13821
+ ),
13748
13822
  workers
13749
13823
  };
13750
13824
  }
13751
- var removedMessages = [/^Ready on http/, /^Updated and ready on http/];
13752
13825
  var ViteMiniflareLogger = class extends Log {
13753
13826
  logger;
13754
13827
  constructor(config) {
@@ -13756,11 +13829,6 @@ var ViteMiniflareLogger = class extends Log {
13756
13829
  this.logger = config.logger;
13757
13830
  }
13758
13831
  logWithLevel(level, message) {
13759
- for (const removedMessage of removedMessages) {
13760
- if (removedMessage.test(message)) {
13761
- return;
13762
- }
13763
- }
13764
13832
  switch (level) {
13765
13833
  case LogLevel.ERROR:
13766
13834
  return this.logger.error(message);
@@ -13770,6 +13838,8 @@ var ViteMiniflareLogger = class extends Log {
13770
13838
  return this.logger.info(message);
13771
13839
  }
13772
13840
  }
13841
+ logReady() {
13842
+ }
13773
13843
  };
13774
13844
  function miniflareLogLevelFromViteLogLevel(level = "info") {
13775
13845
  switch (level) {
@@ -13783,13 +13853,32 @@ function miniflareLogLevelFromViteLogLevel(level = "info") {
13783
13853
  return LogLevel.NONE;
13784
13854
  }
13785
13855
  }
13856
+ var mixedModeSessionsMap = /* @__PURE__ */ new Map();
13857
+ async function maybeStartOrUpdateMixedModeSession(workerConfig) {
13858
+ const workerRemoteBindings = experimental_pickRemoteBindings(
13859
+ unstable_convertConfigBindingsToStartWorkerBindings(workerConfig) ?? {}
13860
+ );
13861
+ assert6(workerConfig.name, "Found workerConfig without a name");
13862
+ let mixedModeSession = mixedModeSessionsMap.get(workerConfig.name);
13863
+ if (mixedModeSession === void 0) {
13864
+ if (Object.keys(workerRemoteBindings).length > 0) {
13865
+ mixedModeSession = await experimental_startMixedModeSession(workerRemoteBindings);
13866
+ mixedModeSessionsMap.set(workerConfig.name, mixedModeSession);
13867
+ }
13868
+ } else {
13869
+ await mixedModeSession.updateBindings(workerRemoteBindings);
13870
+ }
13871
+ await mixedModeSession?.ready;
13872
+ return mixedModeSession;
13873
+ }
13786
13874
 
13787
13875
  // src/plugin-config.ts
13788
- import assert7 from "node:assert";
13876
+ import assert8 from "node:assert";
13789
13877
  import * as path8 from "node:path";
13790
13878
  import * as vite6 from "vite";
13791
13879
 
13792
13880
  // src/workers-configs.ts
13881
+ import assert7 from "node:assert";
13793
13882
  import * as fs4 from "node:fs";
13794
13883
  import * as path7 from "node:path";
13795
13884
  import { unstable_readConfig as unstable_readConfig2 } from "wrangler";
@@ -13823,8 +13912,7 @@ var nonApplicableWorkerConfigs = {
13823
13912
  "preserve_file_names",
13824
13913
  "rules",
13825
13914
  "site",
13826
- "tsconfig",
13827
- "upload_source_maps"
13915
+ "tsconfig"
13828
13916
  ]
13829
13917
  };
13830
13918
  var nullableNonApplicable = [
@@ -13835,15 +13923,17 @@ var nullableNonApplicable = [
13835
13923
  "no_bundle",
13836
13924
  "preserve_file_names",
13837
13925
  "site",
13838
- "tsconfig",
13839
- "upload_source_maps"
13926
+ "tsconfig"
13840
13927
  ];
13841
- function readWorkerConfig(configPath, env2) {
13928
+ function readWorkerConfig(configPath, env2, mixedModeEnabled) {
13842
13929
  const nonApplicable = {
13843
13930
  replacedByVite: /* @__PURE__ */ new Set(),
13844
13931
  notRelevant: /* @__PURE__ */ new Set()
13845
13932
  };
13846
- const config = unstable_readConfig2({ config: configPath, env: env2 }, {});
13933
+ const config = unstable_readConfig2(
13934
+ { config: configPath, env: env2 },
13935
+ { experimental: { mixedModeEnabled } }
13936
+ );
13847
13937
  const raw = structuredClone(config);
13848
13938
  nullableNonApplicable.forEach((prop) => {
13849
13939
  if (config[prop] !== void 0) {
@@ -13938,11 +14028,15 @@ function isNotRelevant(configName) {
13938
14028
  function missingFieldErrorMessage(field, configPath, env2) {
13939
14029
  return `No ${field} field provided in '${configPath}'${env2 ? ` for '${env2}' environment` : ""}`;
13940
14030
  }
13941
- function getWorkerConfig(configPath, env2, opts) {
14031
+ function getWorkerConfig(configPath, env2, mixedModeEnabled, opts) {
13942
14032
  if (opts?.visitedConfigPaths?.has(configPath)) {
13943
14033
  throw new Error(`Duplicate Wrangler config path found: ${configPath}`);
13944
14034
  }
13945
- const { raw, config, nonApplicable } = readWorkerConfig(configPath, env2);
14035
+ const { raw, config, nonApplicable } = readWorkerConfig(
14036
+ configPath,
14037
+ env2,
14038
+ mixedModeEnabled
14039
+ );
13946
14040
  opts?.visitedConfigPaths?.add(configPath);
13947
14041
  if (!config.name) {
13948
14042
  throw new Error(missingFieldErrorMessage(`'name'`, configPath, env2));
@@ -13998,14 +14092,52 @@ function getWorkerConfig(configPath, env2, opts) {
13998
14092
  nonApplicable
13999
14093
  };
14000
14094
  }
14095
+ function getValidatedWranglerConfigPath(root, requestedConfigPath, isForAuxiliaryWorker = false) {
14096
+ if (requestedConfigPath) {
14097
+ const configPath2 = path7.resolve(root, requestedConfigPath);
14098
+ const forAuxiliaryWorkerErrorMessage = isForAuxiliaryWorker ? " requested for one of your auxiliary workers" : "";
14099
+ const errorMessagePrefix = `The provided configPath (${configPath2})${forAuxiliaryWorkerErrorMessage}`;
14100
+ const fileExtension = path7.extname(configPath2).slice(1);
14101
+ if (!allowedWranglerConfigExtensions.includes(fileExtension)) {
14102
+ const foundExtensionMessage = !fileExtension ? "no extension found" : `"${fileExtension}" found`;
14103
+ throw new Error(
14104
+ `${errorMessagePrefix} doesn't point to a file with the correct file extension. It should point to a jsonc, json or toml file (${foundExtensionMessage} instead)`
14105
+ );
14106
+ }
14107
+ const mainStat = fs4.statSync(configPath2, { throwIfNoEntry: false });
14108
+ if (!mainStat) {
14109
+ throw new Error(
14110
+ `${errorMessagePrefix} doesn't point to an existing file`
14111
+ );
14112
+ }
14113
+ if (mainStat.isDirectory()) {
14114
+ throw new Error(
14115
+ `${errorMessagePrefix} points to a directory. It should point to a file.`
14116
+ );
14117
+ }
14118
+ return configPath2;
14119
+ }
14120
+ assert7(
14121
+ isForAuxiliaryWorker === false,
14122
+ "Unexpected Error: trying to find the wrangler config for an auxiliary worker"
14123
+ );
14124
+ const configPath = findWranglerConfig(root);
14125
+ if (!configPath) {
14126
+ throw new Error(
14127
+ `No config file found in the ${root} directory. Please add a wrangler.(jsonc|json|toml) file.`
14128
+ );
14129
+ }
14130
+ return configPath;
14131
+ }
14001
14132
  function findWranglerConfig(root) {
14002
- for (const extension of ["json", "jsonc", "toml"]) {
14133
+ for (const extension of allowedWranglerConfigExtensions) {
14003
14134
  const configPath = path7.join(root, `wrangler.${extension}`);
14004
14135
  if (fs4.existsSync(configPath)) {
14005
14136
  return configPath;
14006
14137
  }
14007
14138
  }
14008
14139
  }
14140
+ var allowedWranglerConfigExtensions = ["jsonc", "json", "toml"];
14009
14141
 
14010
14142
  // src/plugin-config.ts
14011
14143
  function workerNameToEnvironmentName(workerName) {
@@ -14014,7 +14146,6 @@ function workerNameToEnvironmentName(workerName) {
14014
14146
  function resolvePluginConfig(pluginConfig, userConfig, viteEnv) {
14015
14147
  const configPaths = /* @__PURE__ */ new Set();
14016
14148
  const persistState = pluginConfig.persistState ?? true;
14017
- const inspectorPort = pluginConfig.inspectorPort ?? DEFAULT_INSPECTOR_PORT;
14018
14149
  const experimental = pluginConfig.experimental ?? {};
14019
14150
  const root = userConfig.root ? path8.resolve(userConfig.root) : process.cwd();
14020
14151
  const { CLOUDFLARE_ENV: cloudflareEnv } = vite6.loadEnv(
@@ -14023,22 +14154,24 @@ function resolvePluginConfig(pluginConfig, userConfig, viteEnv) {
14023
14154
  /* prefixes */
14024
14155
  ""
14025
14156
  );
14026
- const configPath = pluginConfig.configPath ? path8.resolve(root, pluginConfig.configPath) : findWranglerConfig(root);
14027
- if (!configPath) {
14028
- throw new Error(
14029
- `Config not found. Have you created a wrangler.json(c) or wrangler.toml file?`
14030
- );
14031
- }
14032
- const entryWorkerResolvedConfig = getWorkerConfig(configPath, cloudflareEnv, {
14033
- visitedConfigPaths: configPaths,
14034
- isEntryWorker: true
14035
- });
14157
+ const entryWorkerConfigPath = getValidatedWranglerConfigPath(
14158
+ root,
14159
+ pluginConfig.configPath
14160
+ );
14161
+ const entryWorkerResolvedConfig = getWorkerConfig(
14162
+ entryWorkerConfigPath,
14163
+ cloudflareEnv,
14164
+ pluginConfig.experimental?.mixedMode ?? false,
14165
+ {
14166
+ visitedConfigPaths: configPaths,
14167
+ isEntryWorker: true
14168
+ }
14169
+ );
14036
14170
  if (entryWorkerResolvedConfig.type === "assets-only") {
14037
14171
  return {
14038
14172
  type: "assets-only",
14039
14173
  config: entryWorkerResolvedConfig.config,
14040
14174
  configPaths,
14041
- inspectorPort,
14042
14175
  persistState,
14043
14176
  rawConfigs: {
14044
14177
  entryWorker: entryWorkerResolvedConfig
@@ -14054,15 +14187,21 @@ function resolvePluginConfig(pluginConfig, userConfig, viteEnv) {
14054
14187
  };
14055
14188
  const auxiliaryWorkersResolvedConfigs = [];
14056
14189
  for (const auxiliaryWorker of pluginConfig.auxiliaryWorkers ?? []) {
14190
+ const workerConfigPath = getValidatedWranglerConfigPath(
14191
+ root,
14192
+ auxiliaryWorker.configPath,
14193
+ true
14194
+ );
14057
14195
  const workerResolvedConfig = getWorkerConfig(
14058
- path8.resolve(root, auxiliaryWorker.configPath),
14196
+ workerConfigPath,
14059
14197
  cloudflareEnv,
14198
+ pluginConfig.experimental?.mixedMode ?? false,
14060
14199
  {
14061
14200
  visitedConfigPaths: configPaths
14062
14201
  }
14063
14202
  );
14064
14203
  auxiliaryWorkersResolvedConfigs.push(workerResolvedConfig);
14065
- assert7(
14204
+ assert8(
14066
14205
  workerResolvedConfig.type === "worker",
14067
14206
  "Unexpected error: received AssetsOnlyResult with auxiliary workers."
14068
14207
  );
@@ -14079,7 +14218,6 @@ function resolvePluginConfig(pluginConfig, userConfig, viteEnv) {
14079
14218
  type: "workers",
14080
14219
  configPaths,
14081
14220
  persistState,
14082
- inspectorPort,
14083
14221
  workers,
14084
14222
  entryWorkerEnvironmentName,
14085
14223
  rawConfigs: {
@@ -14092,6 +14230,7 @@ function resolvePluginConfig(pluginConfig, userConfig, viteEnv) {
14092
14230
  }
14093
14231
 
14094
14232
  // src/websockets.ts
14233
+ import { createHeaders } from "@mjackson/node-fetch-server";
14095
14234
  import { coupleWebSocket } from "miniflare";
14096
14235
  import { WebSocketServer } from "ws";
14097
14236
  function handleWebSocket(httpServer, getFetcher) {
@@ -14103,7 +14242,7 @@ function handleWebSocket(httpServer, getFetcher) {
14103
14242
  if (request.headers["sec-websocket-protocol"]?.startsWith("vite")) {
14104
14243
  return;
14105
14244
  }
14106
- const headers = nodeHeadersToWebHeaders(request.headers);
14245
+ const headers = createHeaders(request);
14107
14246
  const fetcher = await getFetcher();
14108
14247
  const response = await fetcher(url, {
14109
14248
  headers,
@@ -14127,6 +14266,57 @@ function handleWebSocket(httpServer, getFetcher) {
14127
14266
  );
14128
14267
  }
14129
14268
 
14269
+ // src/worker-environments-validation.ts
14270
+ import assert9 from "node:assert";
14271
+ function validateWorkerEnvironmentsResolvedConfigs(resolvedPluginConfig, resolvedViteConfig) {
14272
+ const workersEnvironmentNames = Object.keys(resolvedPluginConfig.workers);
14273
+ const disallowedEnvsConfigs = /* @__PURE__ */ new Map();
14274
+ for (const envName of workersEnvironmentNames) {
14275
+ const workerEnvConfig = resolvedViteConfig.environments[envName];
14276
+ assert9(workerEnvConfig, `Missing environment config for "${envName}"`);
14277
+ const { optimizeDeps, resolve: resolve7 } = workerEnvConfig;
14278
+ const disallowedConfig = {};
14279
+ const disallowedOptimizeDepsExcludeEntries = (optimizeDeps.exclude ?? []).filter((entry) => {
14280
+ if (cloudflareBuiltInModules.includes(entry)) {
14281
+ return false;
14282
+ }
14283
+ if (isNodeAlsModule(entry) && isNodeAls(resolvedPluginConfig.workers[envName])) {
14284
+ return false;
14285
+ }
14286
+ if (NODEJS_MODULES_RE.test(entry) && isNodeCompat(resolvedPluginConfig.workers[envName])) {
14287
+ return false;
14288
+ }
14289
+ return true;
14290
+ });
14291
+ if (disallowedOptimizeDepsExcludeEntries.length > 0) {
14292
+ disallowedConfig.optimizeDepsExclude = disallowedOptimizeDepsExcludeEntries;
14293
+ }
14294
+ if (resolve7.external === true || resolve7.external.length > 0) {
14295
+ disallowedConfig.resolveExternal = resolve7.external;
14296
+ }
14297
+ if (Object.keys(disallowedConfig).length > 0) {
14298
+ disallowedEnvsConfigs.set(envName, disallowedConfig);
14299
+ }
14300
+ }
14301
+ if (disallowedEnvsConfigs.size > 0) {
14302
+ const errorMessage = `The following environment configurations are incompatible with the Cloudflare Vite plugin:
14303
+ ${[
14304
+ ...disallowedEnvsConfigs
14305
+ ].map(
14306
+ ([envName, disallowedConfig]) => [
14307
+ disallowedConfig.optimizeDepsExclude ? ` - "${envName}" environment: \`optimizeDeps.exclude\`: ${JSON.stringify(disallowedConfig.optimizeDepsExclude)}
14308
+ ` : null,
14309
+ disallowedConfig.resolveExternal ? ` - "${envName}" environment: \`resolve.external\`: ${JSON.stringify(disallowedConfig.resolveExternal)}
14310
+ ` : null
14311
+ ].join("")
14312
+ ).join(
14313
+ ""
14314
+ )}To resolve this issue, avoid setting \`optimizeDeps.exclude\` and \`resolve.external\` in your Cloudflare Worker environments.
14315
+ `;
14316
+ throw new Error(errorMessage);
14317
+ }
14318
+ }
14319
+
14130
14320
  // src/index.ts
14131
14321
  var workersConfigsWarningShown = false;
14132
14322
  var miniflare;
@@ -14197,7 +14387,7 @@ function cloudflare2(pluginConfig = {}) {
14197
14387
  resolvedPluginConfig.workers
14198
14388
  ).map((environmentName) => {
14199
14389
  const environment = builder.environments[environmentName];
14200
- assert8(
14390
+ assert10(
14201
14391
  environment,
14202
14392
  `${environmentName} environment not found`
14203
14393
  );
@@ -14218,6 +14408,12 @@ function cloudflare2(pluginConfig = {}) {
14218
14408
  },
14219
14409
  configResolved(config) {
14220
14410
  resolvedViteConfig = config;
14411
+ if (resolvedPluginConfig?.type === "workers") {
14412
+ validateWorkerEnvironmentsResolvedConfigs(
14413
+ resolvedPluginConfig,
14414
+ resolvedViteConfig
14415
+ );
14416
+ }
14221
14417
  },
14222
14418
  generateBundle(_, bundle) {
14223
14419
  let config;
@@ -14238,7 +14434,7 @@ function cloudflare2(pluginConfig = {}) {
14238
14434
  if (isEntryWorker && hasClientBuild) {
14239
14435
  const workerOutputDirectory = this.environment.config.build.outDir;
14240
14436
  const clientOutputDirectory = resolvedViteConfig.environments.client?.build.outDir;
14241
- assert8(
14437
+ assert10(
14242
14438
  clientOutputDirectory,
14243
14439
  "Unexpected error: client output directory is undefined"
14244
14440
  );
@@ -14302,78 +14498,104 @@ function cloudflare2(pluginConfig = {}) {
14302
14498
  }
14303
14499
  },
14304
14500
  hotUpdate(options) {
14305
- if (
14306
- // Vite normalizes `options.file` so we use `path.resolve` for Windows compatibility
14307
- resolvedPluginConfig.configPaths.has(path9.resolve(options.file)) || hasAssetsConfigChanged(
14308
- resolvedPluginConfig,
14309
- resolvedViteConfig,
14310
- options.file
14311
- )
14312
- ) {
14501
+ const changedFilePath = path9.resolve(options.file);
14502
+ if (resolvedPluginConfig.configPaths.has(changedFilePath) || hasDotDevDotVarsFileChanged(resolvedPluginConfig, changedFilePath) || hasAssetsConfigChanged(
14503
+ resolvedPluginConfig,
14504
+ resolvedViteConfig,
14505
+ changedFilePath
14506
+ )) {
14313
14507
  options.server.restart();
14314
14508
  return [];
14315
14509
  }
14316
14510
  },
14317
14511
  async configureServer(viteDevServer) {
14318
- assert8(
14319
- viteDevServer.httpServer,
14320
- "Unexpected error: No Vite HTTP server"
14512
+ const inputInspectorPort = await getInputInspectorPortOption(
14513
+ pluginConfig,
14514
+ viteDevServer
14321
14515
  );
14322
- if (miniflare) {
14323
- await miniflare.setOptions(
14324
- getDevMiniflareOptions(resolvedPluginConfig, viteDevServer)
14325
- );
14516
+ const miniflareDevOptions = await getDevMiniflareOptions(
14517
+ resolvedPluginConfig,
14518
+ viteDevServer,
14519
+ inputInspectorPort
14520
+ );
14521
+ if (!miniflare) {
14522
+ miniflare = new Miniflare(miniflareDevOptions);
14326
14523
  } else {
14327
- miniflare = new Miniflare(
14328
- getDevMiniflareOptions(resolvedPluginConfig, viteDevServer)
14329
- );
14524
+ await miniflare.setOptions(miniflareDevOptions);
14330
14525
  }
14331
14526
  await initRunners(resolvedPluginConfig, viteDevServer, miniflare);
14332
- const middleware = createMiddleware(
14333
- async ({ request }) => {
14334
- assert8(miniflare, `Miniflare not defined`);
14335
- const routerWorker = await getRouterWorker(miniflare);
14336
- return routerWorker.fetch(toMiniflareRequest(request), {
14337
- redirect: "manual"
14338
- });
14339
- },
14340
- { alwaysCallNext: false }
14341
- );
14342
- handleWebSocket(viteDevServer.httpServer, async () => {
14343
- assert8(miniflare, `Miniflare not defined`);
14344
- const routerWorker = await getRouterWorker(miniflare);
14345
- return routerWorker.fetch;
14346
- });
14527
+ if (viteDevServer.httpServer) {
14528
+ handleWebSocket(viteDevServer.httpServer, async () => {
14529
+ assert10(miniflare, `Miniflare not defined`);
14530
+ const routerWorker = await miniflare.getWorker(ROUTER_WORKER_NAME);
14531
+ return routerWorker.fetch;
14532
+ });
14533
+ }
14347
14534
  return () => {
14348
- viteDevServer.middlewares.use((req, res, next) => {
14349
- middleware(req, res, next);
14535
+ viteDevServer.middlewares.use(async (req, res, next) => {
14536
+ try {
14537
+ assert10(miniflare, `Miniflare not defined`);
14538
+ const request = createRequest(req, res);
14539
+ let response;
14540
+ if (req[kRequestType] === "asset") {
14541
+ const assetWorker = await miniflare.getWorker(ASSET_WORKER_NAME);
14542
+ response = await assetWorker.fetch(
14543
+ toMiniflareRequest(request),
14544
+ { redirect: "manual" }
14545
+ );
14546
+ } else {
14547
+ const routerWorker = await miniflare.getWorker(ROUTER_WORKER_NAME);
14548
+ response = await routerWorker.fetch(
14549
+ toMiniflareRequest(request),
14550
+ { redirect: "manual" }
14551
+ );
14552
+ }
14553
+ if (req.httpVersionMajor === 2) {
14554
+ response.headers.delete("transfer-encoding");
14555
+ }
14556
+ await sendResponse(res, response);
14557
+ } catch (error) {
14558
+ next(error);
14559
+ }
14350
14560
  });
14351
14561
  };
14352
14562
  },
14353
- configurePreviewServer(vitePreviewServer) {
14354
- const workerConfigs = getWorkerConfigs(vitePreviewServer.config.root);
14563
+ async configurePreviewServer(vitePreviewServer) {
14564
+ const workerConfigs = getWorkerConfigs(
14565
+ vitePreviewServer.config.root,
14566
+ pluginConfig.experimental?.mixedMode ?? false
14567
+ );
14568
+ const inputInspectorPort = await getInputInspectorPortOption(
14569
+ pluginConfig,
14570
+ vitePreviewServer
14571
+ );
14355
14572
  const miniflare2 = new Miniflare(
14356
- getPreviewMiniflareOptions(
14573
+ await getPreviewMiniflareOptions(
14357
14574
  vitePreviewServer,
14358
14575
  workerConfigs,
14359
14576
  pluginConfig.persistState ?? true,
14360
- pluginConfig.inspectorPort
14577
+ !!pluginConfig.experimental?.mixedMode,
14578
+ inputInspectorPort
14361
14579
  )
14362
14580
  );
14363
- const middleware = createMiddleware(
14364
- ({ request }) => {
14365
- return miniflare2.dispatchFetch(toMiniflareRequest(request), {
14366
- redirect: "manual"
14367
- });
14368
- },
14369
- { alwaysCallNext: false }
14370
- );
14371
14581
  handleWebSocket(
14372
14582
  vitePreviewServer.httpServer,
14373
14583
  () => miniflare2.dispatchFetch
14374
14584
  );
14375
- vitePreviewServer.middlewares.use((req, res, next) => {
14376
- middleware(req, res, next);
14585
+ vitePreviewServer.middlewares.use(async (req, res, next) => {
14586
+ try {
14587
+ const request = createRequest(req, res);
14588
+ const response = await miniflare2.dispatchFetch(
14589
+ toMiniflareRequest(request),
14590
+ { redirect: "manual" }
14591
+ );
14592
+ if (req.httpVersionMajor === 2) {
14593
+ response.headers.delete("transfer-encoding");
14594
+ }
14595
+ await sendResponse(res, response);
14596
+ } catch (error) {
14597
+ next(error);
14598
+ }
14377
14599
  });
14378
14600
  }
14379
14601
  },
@@ -14436,7 +14658,7 @@ function cloudflare2(pluginConfig = {}) {
14436
14658
  for (const match of matches) {
14437
14659
  magicString ??= new MagicString(code);
14438
14660
  const [full, _, modulePath] = match;
14439
- assert8(
14661
+ assert10(
14440
14662
  modulePath,
14441
14663
  `Unexpected error: module path not found in reference ${full}.`
14442
14664
  );
@@ -14482,17 +14704,22 @@ function cloudflare2(pluginConfig = {}) {
14482
14704
  configEnvironment(name) {
14483
14705
  if (isNodeCompat(getWorkerConfig2(name))) {
14484
14706
  return {
14707
+ build: {
14708
+ rollupOptions: {
14709
+ plugins: [
14710
+ replace({
14711
+ "process.env.NODE_ENV": JSON.stringify(
14712
+ process.env.NODE_ENV ?? "production"
14713
+ ),
14714
+ preventAssignment: true
14715
+ })
14716
+ ]
14717
+ }
14718
+ },
14485
14719
  resolve: {
14486
14720
  builtins: [...nodeCompatExternals]
14487
14721
  },
14488
14722
  optimizeDeps: {
14489
- // This is a list of dependency entry-points that should be pre-bundled.
14490
- // In this case we provide a list of all the possible polyfills so that they are pre-bundled,
14491
- // ready ahead the first request to the dev server.
14492
- // Without this the dependency optimizer will try to bundle them on-the-fly in the middle of the first request,
14493
- // which can potentially cause problems if it leads to previous pre-bundling to become stale and needing to be reloaded.
14494
- // TODO: work out how to re-enable pre-bundling of these
14495
- // include: [...getNodeCompatEntries()],
14496
14723
  // This is a list of module specifiers that the dependency optimizer should not follow when doing import analysis.
14497
14724
  // 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.
14498
14725
  // Obviously we don't want/need the optimizer to try to process modules that are built-in;
@@ -14516,7 +14743,7 @@ function cloudflare2(pluginConfig = {}) {
14516
14743
  return this.resolve(source, importer, options);
14517
14744
  }
14518
14745
  if (this.environment.mode === "dev") {
14519
- assert8(
14746
+ assert10(
14520
14747
  this.environment.depsOptimizer,
14521
14748
  "depsOptimizer is required in dev mode"
14522
14749
  );
@@ -14530,11 +14757,54 @@ function cloudflare2(pluginConfig = {}) {
14530
14757
  },
14531
14758
  async transform(code, id) {
14532
14759
  const workerConfig = getWorkerConfig2(this.environment.name);
14533
- assert8(workerConfig, "Expected a worker config");
14760
+ if (!workerConfig) {
14761
+ return;
14762
+ }
14534
14763
  const resolvedId = await this.resolve(workerConfig.main);
14535
14764
  if (id === resolvedId?.id) {
14536
14765
  return injectGlobalCode(id, code);
14537
14766
  }
14767
+ },
14768
+ async configureServer(viteDevServer) {
14769
+ await Promise.all(
14770
+ Object.values(viteDevServer.environments).flatMap(
14771
+ async (environment) => {
14772
+ const workerConfig = getWorkerConfig2(environment.name);
14773
+ if (isNodeCompat(workerConfig)) {
14774
+ await environment.depsOptimizer?.init();
14775
+ return Array.from(nodeCompatEntries).map((entry) => {
14776
+ const result = resolveNodeJSImport(entry);
14777
+ if (result) {
14778
+ const registration = environment.depsOptimizer?.registerMissingImport(
14779
+ result.unresolved,
14780
+ result.resolved
14781
+ );
14782
+ return registration?.processing;
14783
+ }
14784
+ });
14785
+ }
14786
+ }
14787
+ )
14788
+ );
14789
+ }
14790
+ },
14791
+ // Plugin that handles Node.js Async Local Storage (ALS) compatibility support for Vite Environments that are hosted in Cloudflare Workers.
14792
+ {
14793
+ name: "vite-plugin-cloudflare:nodejs-als",
14794
+ apply(_config, env2) {
14795
+ return !env2.isPreview;
14796
+ },
14797
+ configEnvironment(name, config) {
14798
+ if (isNodeAls(getWorkerConfig2(name))) {
14799
+ return {
14800
+ resolve: {
14801
+ builtins: ["async_hooks", "node:async_hooks"]
14802
+ },
14803
+ optimizeDeps: {
14804
+ exclude: ["async_hooks", "node:async_hooks"]
14805
+ }
14806
+ };
14807
+ }
14538
14808
  }
14539
14809
  },
14540
14810
  // Plugin that provides an __debug path for debugging the Cloudflare Workers.
@@ -14544,39 +14814,38 @@ function cloudflare2(pluginConfig = {}) {
14544
14814
  // the preview middleware here can take precedence
14545
14815
  enforce: "pre",
14546
14816
  configureServer(viteDevServer) {
14547
- if (resolvedPluginConfig.type === "workers" && resolvedPluginConfig.inspectorPort !== false) {
14817
+ if (resolvedPluginConfig.type === "workers" && pluginConfig.inspectorPort !== false) {
14548
14818
  addDebugToVitePrintUrls(viteDevServer);
14549
14819
  }
14550
14820
  const workerNames = resolvedPluginConfig.type === "assets-only" ? [] : Object.values(resolvedPluginConfig.workers).map(
14551
14821
  (worker) => worker.name
14552
14822
  );
14553
- viteDevServer.middlewares.use((req, res, next) => {
14554
- if (req.url === debuggingPath && resolvedPluginConfig.inspectorPort !== false) {
14555
- const html = getDebugPathHtml(
14556
- workerNames,
14557
- resolvedPluginConfig.inspectorPort
14558
- );
14823
+ viteDevServer.middlewares.use(async (req, res, next) => {
14824
+ const resolvedInspectorPort = await getResolvedInspectorPort(pluginConfig);
14825
+ if (req.url === debuggingPath && resolvedInspectorPort) {
14826
+ const html = getDebugPathHtml(workerNames, resolvedInspectorPort);
14559
14827
  res.setHeader("Content-Type", "text/html");
14560
14828
  return res.end(html);
14561
14829
  }
14562
14830
  next();
14563
14831
  });
14564
14832
  },
14565
- configurePreviewServer(vitePreviewServer) {
14566
- const workerConfigs = getWorkerConfigs(vitePreviewServer.config.root);
14833
+ async configurePreviewServer(vitePreviewServer) {
14834
+ const workerConfigs = getWorkerConfigs(
14835
+ vitePreviewServer.config.root,
14836
+ pluginConfig.experimental?.mixedMode ?? false
14837
+ );
14567
14838
  if (workerConfigs.length >= 1 && pluginConfig.inspectorPort !== false) {
14568
14839
  addDebugToVitePrintUrls(vitePreviewServer);
14569
14840
  }
14570
14841
  const workerNames = workerConfigs.map((worker) => {
14571
- assert8(worker.name, "Expected the Worker to have a name");
14842
+ assert10(worker.name, "Expected the Worker to have a name");
14572
14843
  return worker.name;
14573
14844
  });
14574
- vitePreviewServer.middlewares.use((req, res, next) => {
14575
- if (req.url === debuggingPath && pluginConfig.inspectorPort !== false) {
14576
- const html = getDebugPathHtml(
14577
- workerNames,
14578
- pluginConfig.inspectorPort ?? DEFAULT_INSPECTOR_PORT
14579
- );
14845
+ vitePreviewServer.middlewares.use(async (req, res, next) => {
14846
+ const resolvedInspectorPort = await getResolvedInspectorPort(pluginConfig);
14847
+ if (req.url === debuggingPath && resolvedInspectorPort) {
14848
+ const html = getDebugPathHtml(workerNames, resolvedInspectorPort);
14580
14849
  res.setHeader("Content-Type", "text/html");
14581
14850
  return res.end(html);
14582
14851
  }
@@ -14590,6 +14859,9 @@ function cloudflare2(pluginConfig = {}) {
14590
14859
  apply(_config, env2) {
14591
14860
  return !env2.isPreview;
14592
14861
  },
14862
+ // We must ensure that the `resolveId` hook runs before the built-in ones.
14863
+ // Otherwise we never see the Node.js built-in imports since they get handled by default Vite behavior.
14864
+ enforce: "pre",
14593
14865
  configEnvironment(environmentName) {
14594
14866
  const workerConfig = getWorkerConfig2(environmentName);
14595
14867
  if (workerConfig && !isNodeCompat(workerConfig)) {
@@ -14603,21 +14875,14 @@ function cloudflare2(pluginConfig = {}) {
14603
14875
  build.onResolve(
14604
14876
  { filter: NODEJS_MODULES_RE },
14605
14877
  ({ path: path10, importer }) => {
14878
+ if (isNodeAls(workerConfig) && isNodeAlsModule(path10)) {
14879
+ return;
14880
+ }
14606
14881
  const nodeJsCompatWarnings = nodeJsCompatWarningsMap.get(workerConfig);
14607
- assert8(
14608
- nodeJsCompatWarnings,
14609
- `expected nodeJsCompatWarnings to be defined for Worker "${workerConfig.name}"`
14610
- );
14611
- nodeJsCompatWarnings.registerImport(path10, importer);
14882
+ nodeJsCompatWarnings?.registerImport(path10, importer);
14612
14883
  return { path: path10, external: true };
14613
14884
  }
14614
14885
  );
14615
- build.onEnd(() => {
14616
- const nodeJsCompatWarnings = nodeJsCompatWarningsMap.get(workerConfig);
14617
- if (nodeJsCompatWarnings) {
14618
- nodeJsCompatWarnings.renderWarnings();
14619
- }
14620
- });
14621
14886
  }
14622
14887
  }
14623
14888
  ]
@@ -14626,47 +14891,28 @@ function cloudflare2(pluginConfig = {}) {
14626
14891
  };
14627
14892
  }
14628
14893
  },
14629
- configureServer(viteDevServer) {
14630
- for (const environment of Object.values(viteDevServer.environments)) {
14631
- const workerConfig = getWorkerConfig2(environment.name);
14894
+ configResolved(resolvedViteConfig2) {
14895
+ for (const environmentName of Object.keys(
14896
+ resolvedViteConfig2.environments
14897
+ )) {
14898
+ const workerConfig = getWorkerConfig2(environmentName);
14632
14899
  if (workerConfig && !isNodeCompat(workerConfig)) {
14633
14900
  nodeJsCompatWarningsMap.set(
14634
14901
  workerConfig,
14635
- new NodeJsCompatWarnings(environment)
14902
+ new NodeJsCompatWarnings(environmentName, resolvedViteConfig2)
14636
14903
  );
14637
14904
  }
14638
14905
  }
14639
14906
  },
14640
- buildStart() {
14641
- const workerConfig = getWorkerConfig2(this.environment.name);
14642
- if (workerConfig && !isNodeCompat(workerConfig)) {
14643
- nodeJsCompatWarningsMap.set(
14644
- workerConfig,
14645
- new NodeJsCompatWarnings(this.environment)
14646
- );
14647
- }
14648
- },
14649
- buildEnd() {
14650
- const workerConfig = getWorkerConfig2(this.environment.name);
14651
- if (workerConfig && !isNodeCompat(workerConfig)) {
14652
- const nodeJsCompatWarnings = nodeJsCompatWarningsMap.get(workerConfig);
14653
- assert8(
14654
- nodeJsCompatWarnings,
14655
- `expected nodeJsCompatWarnings to be defined for Worker "${workerConfig.name}"`
14656
- );
14657
- nodeJsCompatWarnings.renderWarnings();
14658
- }
14659
- },
14660
- // We must ensure that the `resolveId` hook runs before the built-in ones otherwise we
14661
- // never see the Node.js built-in imports since they get handled by default Vite behavior.
14662
- enforce: "pre",
14663
14907
  async resolveId(source, importer) {
14664
14908
  const workerConfig = getWorkerConfig2(this.environment.name);
14665
14909
  if (workerConfig && !isNodeCompat(workerConfig)) {
14910
+ if (isNodeAls(workerConfig) && isNodeAlsModule(source)) {
14911
+ return;
14912
+ }
14666
14913
  const nodeJsCompatWarnings = nodeJsCompatWarningsMap.get(workerConfig);
14667
14914
  if (nodejsBuiltins.has(source)) {
14668
14915
  nodeJsCompatWarnings?.registerImport(source, importer);
14669
- nodeJsCompatWarnings?.renderWarningsOnIdle();
14670
14916
  return {
14671
14917
  id: source,
14672
14918
  external: true
@@ -14677,10 +14923,35 @@ function cloudflare2(pluginConfig = {}) {
14677
14923
  }
14678
14924
  ];
14679
14925
  function getWorkerConfig2(environmentName) {
14680
- assert8(resolvedPluginConfig, "Expected resolvedPluginConfig to be defined");
14926
+ assert10(resolvedPluginConfig, "Expected resolvedPluginConfig to be defined");
14681
14927
  return resolvedPluginConfig.type !== "assets-only" ? resolvedPluginConfig.workers[environmentName] : void 0;
14682
14928
  }
14683
14929
  }
14930
+ async function getInputInspectorPortOption(pluginConfig, viteServer) {
14931
+ if (pluginConfig.inspectorPort === void 0 || pluginConfig.inspectorPort === 0) {
14932
+ const resolvedInspectorPort = await getResolvedInspectorPort(pluginConfig);
14933
+ if (resolvedInspectorPort !== null) {
14934
+ return resolvedInspectorPort;
14935
+ }
14936
+ }
14937
+ const inputInspectorPort = pluginConfig.inspectorPort ?? await getFirstAvailablePort(DEFAULT_INSPECTOR_PORT);
14938
+ if (pluginConfig.inspectorPort === void 0 && inputInspectorPort !== DEFAULT_INSPECTOR_PORT) {
14939
+ viteServer.config.logger.warn(
14940
+ colors3.dim(
14941
+ `Default inspector port ${DEFAULT_INSPECTOR_PORT} not available, using ${inputInspectorPort} instead
14942
+ `
14943
+ )
14944
+ );
14945
+ }
14946
+ return inputInspectorPort;
14947
+ }
14948
+ async function getResolvedInspectorPort(pluginConfig) {
14949
+ if (miniflare && pluginConfig.inspectorPort !== false) {
14950
+ const miniflareInspectorUrl = await miniflare.getInspectorURL();
14951
+ return Number.parseInt(miniflareInspectorUrl.port);
14952
+ }
14953
+ return null;
14954
+ }
14684
14955
  function getDotDevDotVarsContent(configPath, cloudflareEnv) {
14685
14956
  const configDir = path9.dirname(configPath);
14686
14957
  const defaultDotDevDotVarsPath = `${configDir}/.dev.vars`;
@@ -14692,6 +14963,19 @@ function getDotDevDotVarsContent(configPath, cloudflareEnv) {
14692
14963
  }
14693
14964
  return null;
14694
14965
  }
14966
+ function hasDotDevDotVarsFileChanged(resolvedPluginConfig, changedFilePath) {
14967
+ return [...resolvedPluginConfig.configPaths].some((configPath) => {
14968
+ const dotDevDotVars = path9.join(path9.dirname(configPath), ".dev.vars");
14969
+ if (dotDevDotVars === changedFilePath) {
14970
+ return true;
14971
+ }
14972
+ if (resolvedPluginConfig.cloudflareEnv) {
14973
+ const dotDevDotVarsForEnv = `${dotDevDotVars}.${resolvedPluginConfig.cloudflareEnv}`;
14974
+ return dotDevDotVarsForEnv === changedFilePath;
14975
+ }
14976
+ return false;
14977
+ });
14978
+ }
14695
14979
  export {
14696
14980
  cloudflare2 as cloudflare
14697
14981
  };