@cloudflare/vite-plugin 1.4.0 → 1.5.1

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.
@@ -4728,6 +4728,7 @@ var normalizeConfiguration = (configuration) => {
4728
4728
  version: 2,
4729
4729
  rules: {}
4730
4730
  },
4731
+ has_static_routing: configuration?.has_static_routing ?? false,
4731
4732
  account_id: configuration?.account_id ?? -1,
4732
4733
  script_id: configuration?.script_id ?? -1,
4733
4734
  debug: configuration?.debug ?? false
@@ -4906,24 +4907,27 @@ var replacer = (str, replacements) => {
4906
4907
  }
4907
4908
  return str;
4908
4909
  };
4910
+ var generateRuleRegExp = (rule) => {
4911
+ rule = rule.split("*").map(escapeRegex).join("(?<splat>.*)");
4912
+ const host_matches = rule.matchAll(HOST_PLACEHOLDER_REGEX);
4913
+ for (const host_match of host_matches) {
4914
+ rule = rule.split(host_match[0]).join(`(?<${host_match[1]}>[^/.]+)`);
4915
+ }
4916
+ const path_matches = rule.matchAll(PLACEHOLDER_REGEX);
4917
+ for (const path_match of path_matches) {
4918
+ rule = rule.split(path_match[0]).join(`(?<${path_match[1]}>[^/]+)`);
4919
+ }
4920
+ rule = "^" + rule + "$";
4921
+ return RegExp(rule);
4922
+ };
4909
4923
  var generateRulesMatcher = (rules, replacerFn = (match) => match) => {
4910
4924
  if (!rules) {
4911
4925
  return () => [];
4912
4926
  }
4913
4927
  const compiledRules = Object.entries(rules).map(([rule, match]) => {
4914
4928
  const crossHost = rule.startsWith("https://");
4915
- rule = rule.split("*").map(escapeRegex).join("(?<splat>.*)");
4916
- const host_matches = rule.matchAll(HOST_PLACEHOLDER_REGEX);
4917
- for (const host_match of host_matches) {
4918
- rule = rule.split(host_match[0]).join(`(?<${host_match[1]}>[^/.]+)`);
4919
- }
4920
- const path_matches = rule.matchAll(PLACEHOLDER_REGEX);
4921
- for (const path_match of path_matches) {
4922
- rule = rule.split(path_match[0]).join(`(?<${path_match[1]}>[^/]+)`);
4923
- }
4924
- rule = "^" + rule + "$";
4925
4929
  try {
4926
- const regExp = new RegExp(rule);
4930
+ const regExp = generateRuleRegExp(rule);
4927
4931
  return [{ crossHost, regExp }, match];
4928
4932
  } catch {
4929
4933
  }
@@ -5140,10 +5144,11 @@ var resolveAssetIntentToResponse = async (assetIntent, request, env, configurati
5140
5144
  });
5141
5145
  };
5142
5146
  var canFetch = async (request, env, configuration, exists) => {
5143
- if (!(flagIsEnabled(
5147
+ const shouldKeepNotFoundHandling = configuration.has_static_routing || flagIsEnabled(
5144
5148
  configuration,
5145
5149
  SEC_FETCH_MODE_NAVIGATE_HEADER_PREFERS_ASSET_SERVING
5146
- ) && request.headers.get("Sec-Fetch-Mode") === "navigate")) {
5150
+ ) && request.headers.get("Sec-Fetch-Mode") === "navigate";
5151
+ if (!shouldKeepNotFoundHandling) {
5147
5152
  configuration = {
5148
5153
  ...configuration,
5149
5154
  not_found_handling: "none"
@@ -5994,6 +5999,7 @@ var ADDITIONAL_MODULE_TYPES = [
5994
5999
  "Data",
5995
6000
  "Text"
5996
6001
  ];
6002
+ var kRequestType = Symbol("kRequestType");
5997
6003
 
5998
6004
  // src/shared.ts
5999
6005
  var UNKNOWN_HOST = "http://localhost";
@@ -6017,7 +6023,7 @@ var CustomAssetWorker = class extends worker_default {
6017
6023
  const url = new URL(eTag, UNKNOWN_HOST);
6018
6024
  const response = await this.env.__VITE_FETCH_ASSET__.fetch(url);
6019
6025
  if (!response.body) {
6020
- throw new Error(`Unexpected error. No HTML found for ${eTag}.`);
6026
+ throw new Error(`Unexpected error. No HTML found for "${eTag}".`);
6021
6027
  }
6022
6028
  return {
6023
6029
  readableStream: response.body,
@@ -1,3 +1,60 @@
1
+ // ../workers-shared/utils/tracing.ts
2
+ function mockJaegerBindingSpan() {
3
+ return {
4
+ addLogs: () => {
5
+ },
6
+ setTags: () => {
7
+ },
8
+ end: () => {
9
+ },
10
+ isRecording: true
11
+ };
12
+ }
13
+ function mockJaegerBinding() {
14
+ return {
15
+ enterSpan: (_, span, ...args) => {
16
+ return span(mockJaegerBindingSpan(), ...args);
17
+ },
18
+ getSpanContext: () => ({
19
+ traceId: "test-trace",
20
+ spanId: "test-span",
21
+ parentSpanId: "test-parent-span",
22
+ traceFlags: 0
23
+ }),
24
+ runWithSpanContext: (_, callback, ...args) => {
25
+ return callback(...args);
26
+ },
27
+ traceId: "test-trace",
28
+ spanId: "test-span",
29
+ parentSpanId: "test-parent-span",
30
+ cfTraceIdHeader: "test-trace:test-span:0"
31
+ };
32
+ }
33
+
34
+ // ../workers-shared/asset-worker/src/utils/rules-engine.ts
35
+ var ESCAPE_REGEX_CHARACTERS = /[-/\\^$*+?.()|[\]{}]/g;
36
+ var escapeRegex = (str) => {
37
+ return str.replace(ESCAPE_REGEX_CHARACTERS, "\\$&");
38
+ };
39
+ var generateGlobOnlyRuleRegExp = (rule) => {
40
+ rule = rule.split("*").map(escapeRegex).join(".*");
41
+ rule = "^" + rule + "$";
42
+ return RegExp(rule);
43
+ };
44
+ var generateStaticRoutingRuleMatcher = (rules) => ({ request }) => {
45
+ const { pathname } = new URL(request.url);
46
+ for (const rule of rules) {
47
+ try {
48
+ const regExp = generateGlobOnlyRuleRegExp(rule);
49
+ if (regExp.test(pathname)) {
50
+ return true;
51
+ }
52
+ } catch {
53
+ }
54
+ }
55
+ return false;
56
+ };
57
+
1
58
  // ../workers-shared/utils/performance.ts
2
59
  var PerformanceTimer = class {
3
60
  performanceTimer;
@@ -4483,39 +4540,6 @@ function setupSentry(request, context, dsn, clientId, clientSecret, coloMetadata
4483
4540
  return sentry;
4484
4541
  }
4485
4542
 
4486
- // ../workers-shared/utils/tracing.ts
4487
- function mockJaegerBindingSpan() {
4488
- return {
4489
- addLogs: () => {
4490
- },
4491
- setTags: () => {
4492
- },
4493
- end: () => {
4494
- },
4495
- isRecording: true
4496
- };
4497
- }
4498
- function mockJaegerBinding() {
4499
- return {
4500
- enterSpan: (_, span, ...args) => {
4501
- return span(mockJaegerBindingSpan(), ...args);
4502
- },
4503
- getSpanContext: () => ({
4504
- traceId: "test-trace",
4505
- spanId: "test-span",
4506
- parentSpanId: "test-parent-span",
4507
- traceFlags: 0
4508
- }),
4509
- runWithSpanContext: (_, callback, ...args) => {
4510
- return callback(...args);
4511
- },
4512
- traceId: "test-trace",
4513
- spanId: "test-span",
4514
- parentSpanId: "test-parent-span",
4515
- cfTraceIdHeader: "test-trace:test-span:0"
4516
- };
4517
- }
4518
-
4519
4543
  // ../workers-shared/router-worker/src/analytics.ts
4520
4544
  var VERSION = 1;
4521
4545
  var Analytics = class {
@@ -4551,7 +4575,9 @@ var Analytics = class {
4551
4575
  // double3
4552
4576
  this.data.coloTier ?? -1,
4553
4577
  // double4
4554
- this.data.userWorkerAhead === void 0 ? -1 : Number(this.data.userWorkerAhead)
4578
+ this.data.userWorkerAhead === void 0 ? -1 : Number(this.data.userWorkerAhead),
4579
+ this.data.staticRoutingDecision ?? 0 /* NOT_PROVIDED */
4580
+ // double6
4555
4581
  ],
4556
4582
  blobs: [
4557
4583
  this.data.hostname?.substring(0, 256),
@@ -4576,7 +4602,10 @@ var applyConfigurationDefaults = (configuration) => {
4576
4602
  has_user_worker: configuration?.has_user_worker ?? false,
4577
4603
  account_id: configuration?.account_id ?? -1,
4578
4604
  script_id: configuration?.script_id ?? -1,
4579
- debug: configuration?.debug ?? false
4605
+ debug: configuration?.debug ?? false,
4606
+ static_routing: configuration?.static_routing ?? {
4607
+ user_worker: []
4608
+ }
4580
4609
  };
4581
4610
  };
4582
4611
 
@@ -4603,6 +4632,7 @@ var worker_default = {
4603
4632
  env.CONFIG?.account_id,
4604
4633
  env.CONFIG?.script_id
4605
4634
  );
4635
+ const hasStaticRouting = env.CONFIG.static_routing !== void 0;
4606
4636
  const config = applyConfigurationDefaults(env.CONFIG);
4607
4637
  const url = new URL(request.url);
4608
4638
  if (env.COLO_METADATA && env.VERSION_METADATA && env.CONFIG) {
@@ -4619,6 +4649,55 @@ var worker_default = {
4619
4649
  });
4620
4650
  }
4621
4651
  const maybeSecondRequest = request.clone();
4652
+ if (config.static_routing) {
4653
+ const excludeRulesMatcher = generateStaticRoutingRuleMatcher(
4654
+ config.static_routing.asset_worker ?? []
4655
+ );
4656
+ if (excludeRulesMatcher({
4657
+ request
4658
+ })) {
4659
+ analytics.setData({
4660
+ dispatchtype: "asset" /* ASSETS */,
4661
+ staticRoutingDecision: 2 /* ROUTED */
4662
+ });
4663
+ return await env.JAEGER.enterSpan("dispatch_assets", async (span) => {
4664
+ span.setTags({
4665
+ hasUserWorker: config.has_user_worker,
4666
+ asset: "static_routing",
4667
+ dispatchType: "asset" /* ASSETS */
4668
+ });
4669
+ return env.ASSET_WORKER.fetch(maybeSecondRequest);
4670
+ });
4671
+ }
4672
+ const includeRulesMatcher = generateStaticRoutingRuleMatcher(
4673
+ config.static_routing.user_worker
4674
+ );
4675
+ if (includeRulesMatcher({
4676
+ request
4677
+ })) {
4678
+ if (!config.has_user_worker) {
4679
+ throw new Error(
4680
+ "Fetch for user worker without having a user worker binding"
4681
+ );
4682
+ }
4683
+ analytics.setData({
4684
+ dispatchtype: "worker" /* WORKER */,
4685
+ staticRoutingDecision: 2 /* ROUTED */
4686
+ });
4687
+ return await env.JAEGER.enterSpan("dispatch_worker", async (span) => {
4688
+ span.setTags({
4689
+ hasUserWorker: true,
4690
+ asset: "static_routing",
4691
+ dispatchType: "worker" /* WORKER */
4692
+ });
4693
+ userWorkerInvocation = true;
4694
+ return env.USER_WORKER.fetch(maybeSecondRequest);
4695
+ });
4696
+ }
4697
+ analytics.setData({
4698
+ staticRoutingDecision: hasStaticRouting ? 1 /* NOT_ROUTED */ : 0 /* NOT_PROVIDED */
4699
+ });
4700
+ }
4622
4701
  if (config.invoke_user_worker_ahead_of_assets) {
4623
4702
  if (!config.has_user_worker) {
4624
4703
  throw new Error(
package/dist/index.js CHANGED
@@ -1571,6 +1571,7 @@ var ADDITIONAL_MODULE_TYPES = [
1571
1571
  "Text"
1572
1572
  ];
1573
1573
  var DEFAULT_INSPECTOR_PORT = 9229;
1574
+ var kRequestType = Symbol("kRequestType");
1574
1575
 
1575
1576
  // src/additional-modules.ts
1576
1577
  var moduleRules = [
@@ -5787,8 +5788,13 @@ var InternalConfigSchema = z.object({
5787
5788
  script_id: z.number().optional(),
5788
5789
  debug: z.boolean().optional()
5789
5790
  });
5791
+ var StaticRoutingSchema = z.object({
5792
+ user_worker: z.array(z.string()),
5793
+ asset_worker: z.array(z.string()).optional()
5794
+ });
5790
5795
  var RouterConfigSchema = z.object({
5791
5796
  invoke_user_worker_ahead_of_assets: z.boolean().optional(),
5797
+ static_routing: StaticRoutingSchema.optional(),
5792
5798
  has_user_worker: z.boolean().optional(),
5793
5799
  ...InternalConfigSchema.shape
5794
5800
  });
@@ -5829,6 +5835,7 @@ var AssetConfigSchema = z.object({
5829
5835
  not_found_handling: z.enum(["single-page-application", "404-page", "none"]).optional(),
5830
5836
  redirects: RedirectsSchema,
5831
5837
  headers: HeadersSchema,
5838
+ has_static_routing: z.boolean().optional(),
5832
5839
  ...InternalConfigSchema.shape
5833
5840
  });
5834
5841
 
@@ -12648,8 +12655,8 @@ function packageResolve(specifier, base, conditions) {
12648
12655
  let packageJsonPath = fileURLToPath$1(packageJsonUrl);
12649
12656
  let lastPath;
12650
12657
  do {
12651
- const stat = tryStatSync(packageJsonPath.slice(0, -13));
12652
- if (!stat || !stat.isDirectory()) {
12658
+ const stat2 = tryStatSync(packageJsonPath.slice(0, -13));
12659
+ if (!stat2 || !stat2.isDirectory()) {
12653
12660
  lastPath = packageJsonPath;
12654
12661
  packageJsonUrl = new URL$1(
12655
12662
  (isScoped ? "../../../../node_modules/" : "../../../node_modules/") + packageName + "/package.json",
@@ -12779,8 +12786,8 @@ function _resolve(id, options = {}) {
12779
12786
  }
12780
12787
  if (isAbsolute(id)) {
12781
12788
  try {
12782
- const stat = statSync(id);
12783
- if (stat.isFile()) {
12789
+ const stat2 = statSync(id);
12790
+ if (stat2.isFile()) {
12784
12791
  return pathToFileURL(id);
12785
12792
  }
12786
12793
  } catch (error) {
@@ -13010,9 +13017,6 @@ function getOutputDirectory(userConfig, environmentName) {
13010
13017
  const rootOutputDirectory = userConfig.build?.outDir ?? "dist";
13011
13018
  return userConfig.environments?.[environmentName]?.build?.outDir ?? path4.join(rootOutputDirectory, environmentName);
13012
13019
  }
13013
- function getRouterWorker(miniflare2) {
13014
- return miniflare2.getWorker(ROUTER_WORKER_NAME);
13015
- }
13016
13020
  function toMiniflareRequest(request) {
13017
13021
  const host = request.headers.get("Host");
13018
13022
  if (host) {
@@ -13522,12 +13526,14 @@ async function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer, inspe
13522
13526
  serviceBindings: {
13523
13527
  __VITE_ASSET_EXISTS__: async (request) => {
13524
13528
  const { pathname } = new URL(request.url);
13525
- const filePath = path6.join(resolvedViteConfig.root, pathname);
13526
- let exists;
13527
- try {
13528
- exists = fs3.statSync(filePath).isFile();
13529
- } catch (error) {
13530
- exists = false;
13529
+ let exists = false;
13530
+ if (pathname.endsWith(".html")) {
13531
+ try {
13532
+ const filePath = path6.join(resolvedViteConfig.root, pathname);
13533
+ const stats = await fsp.stat(filePath);
13534
+ exists = stats.isFile();
13535
+ } catch (error) {
13536
+ }
13531
13537
  }
13532
13538
  return MiniflareResponse.json(exists);
13533
13539
  },
@@ -13541,7 +13547,7 @@ async function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer, inspe
13541
13547
  headers: { "Content-Type": "text/html" }
13542
13548
  });
13543
13549
  } catch (error) {
13544
- throw new Error(`Unexpected error. Failed to load ${pathname}`);
13550
+ throw new Error(`Unexpected error. Failed to load "${pathname}".`);
13545
13551
  }
13546
13552
  }
13547
13553
  }
@@ -13579,7 +13585,12 @@ async function getDevMiniflareOptions(resolvedPluginConfig, viteDevServer, inspe
13579
13585
  serviceBindings: {
13580
13586
  ...workerOptions.serviceBindings,
13581
13587
  ...environmentName === resolvedPluginConfig.entryWorkerEnvironmentName && workerConfig.assets?.binding ? {
13582
- [workerConfig.assets.binding]: ASSET_WORKER_NAME
13588
+ [workerConfig.assets.binding]: {
13589
+ node: (req, res) => {
13590
+ req[kRequestType] = "asset";
13591
+ viteDevServer.middlewares(req, res);
13592
+ }
13593
+ }
13583
13594
  } : {},
13584
13595
  __VITE_INVOKE_MODULE__: async (request) => {
13585
13596
  const payload = await request.json();
@@ -14522,7 +14533,7 @@ function cloudflare2(pluginConfig = {}) {
14522
14533
  if (viteDevServer.httpServer) {
14523
14534
  handleWebSocket(viteDevServer.httpServer, async () => {
14524
14535
  assert10(miniflare, `Miniflare not defined`);
14525
- const routerWorker = await getRouterWorker(miniflare);
14536
+ const routerWorker = await miniflare.getWorker(ROUTER_WORKER_NAME);
14526
14537
  return routerWorker.fetch;
14527
14538
  });
14528
14539
  }
@@ -14530,14 +14541,21 @@ function cloudflare2(pluginConfig = {}) {
14530
14541
  viteDevServer.middlewares.use(async (req, res, next) => {
14531
14542
  try {
14532
14543
  assert10(miniflare, `Miniflare not defined`);
14533
- const routerWorker = await getRouterWorker(miniflare);
14534
14544
  const request = createRequest(req, res);
14535
- const response = await routerWorker.fetch(
14536
- toMiniflareRequest(request),
14537
- {
14538
- redirect: "manual"
14539
- }
14540
- );
14545
+ let response;
14546
+ if (req[kRequestType] === "asset") {
14547
+ const assetWorker = await miniflare.getWorker(ASSET_WORKER_NAME);
14548
+ response = await assetWorker.fetch(
14549
+ toMiniflareRequest(request),
14550
+ { redirect: "manual" }
14551
+ );
14552
+ } else {
14553
+ const routerWorker = await miniflare.getWorker(ROUTER_WORKER_NAME);
14554
+ response = await routerWorker.fetch(
14555
+ toMiniflareRequest(request),
14556
+ { redirect: "manual" }
14557
+ );
14558
+ }
14541
14559
  if (req.httpVersionMajor === 2) {
14542
14560
  response.headers.delete("transfer-encoding");
14543
14561
  }
@@ -11,6 +11,7 @@ var ADDITIONAL_MODULE_TYPES = [
11
11
  "Data",
12
12
  "Text"
13
13
  ];
14
+ var kRequestType = Symbol("kRequestType");
14
15
 
15
16
  // src/shared.ts
16
17
  var UNKNOWN_HOST = "http://localhost";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudflare/vite-plugin",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "description": "Cloudflare plugin for Vite",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -41,22 +41,21 @@
41
41
  "tinyglobby": "^0.2.12",
42
42
  "unenv": "2.0.0-rc.17",
43
43
  "ws": "8.18.0",
44
- "wrangler": "4.19.0",
45
- "miniflare": "4.20250525.1"
44
+ "miniflare": "4.20250604.0",
45
+ "wrangler": "4.19.2"
46
46
  },
47
47
  "devDependencies": {
48
- "@cloudflare/workers-types": "^4.20250525.0",
48
+ "@cloudflare/workers-types": "^4.20250604.0",
49
49
  "@types/node": "^22.10.1",
50
50
  "@types/ws": "^8.5.13",
51
51
  "magic-string": "^0.30.12",
52
52
  "mlly": "^1.7.4",
53
53
  "tsup": "8.3.0",
54
54
  "typescript": "^5.7.2",
55
- "undici": "^5.28.5",
56
55
  "vite": "^6.1.0",
57
56
  "vitest": "~3.1.1",
58
57
  "@cloudflare/mock-npm-registry": "0.0.0",
59
- "@cloudflare/workers-shared": "0.17.5",
58
+ "@cloudflare/workers-shared": "0.17.6",
60
59
  "@cloudflare/workers-tsconfig": "0.0.0"
61
60
  },
62
61
  "peerDependencies": {