wrangler 2.13.0 → 2.14.0

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.
@@ -0,0 +1,220 @@
1
+ import { mkdir, writeFile } from "fs/promises";
2
+ import path from "path";
3
+ import dedent from "ts-dedent";
4
+ import traverseModuleGraph from "../traverse-module-graph";
5
+ import { runInTempDir } from "./helpers/run-in-tmp";
6
+ import type { ConfigModuleRuleType } from "../config";
7
+
8
+ /*
9
+ * This file contains inline comments with the word "javascript"
10
+ * This signals to a compatible editor extension that the template string
11
+ * contents should be syntax-highlighted as JavaScript. One such extension
12
+ * is zjcompt.es6-string-javascript, but there are others.
13
+ */
14
+
15
+ describe("traverse module graph", () => {
16
+ runInTempDir();
17
+
18
+ it("should not detect JS without module rules", async () => {
19
+ await writeFile(
20
+ "./index.js",
21
+ dedent/* javascript */ `
22
+ import { HELLO } from "./other.js"
23
+ export default {
24
+ async fetch(request) {
25
+ return new Response(HELLO)
26
+ }
27
+ }
28
+ `
29
+ );
30
+ await writeFile(
31
+ "./other.js",
32
+ dedent/* javascript */ `
33
+ export const HELLO = "WORLD"
34
+ `
35
+ );
36
+
37
+ const bundle = await traverseModuleGraph(
38
+ {
39
+ file: path.join(process.cwd(), "./index.js"),
40
+ directory: process.cwd(),
41
+ format: "modules",
42
+ moduleRoot: process.cwd(),
43
+ },
44
+ []
45
+ );
46
+
47
+ expect(bundle.modules).toStrictEqual([]);
48
+ });
49
+
50
+ it.each([
51
+ ["ESModule", "esm"],
52
+ ["CommonJS", "commonjs"],
53
+ ])("should detect JS as %s", async (type, format) => {
54
+ await writeFile(
55
+ "./index.js",
56
+ dedent/* javascript */ `
57
+ import { HELLO } from "./other.js"
58
+ export default {
59
+ async fetch(request) {
60
+ return new Response(HELLO)
61
+ }
62
+ }
63
+ `
64
+ );
65
+ await writeFile(
66
+ "./other.js",
67
+ dedent/* javascript */ `
68
+ export const HELLO = "WORLD"
69
+ `
70
+ );
71
+
72
+ const bundle = await traverseModuleGraph(
73
+ {
74
+ file: path.join(process.cwd(), "./index.js"),
75
+ directory: process.cwd(),
76
+ format: "modules",
77
+ moduleRoot: process.cwd(),
78
+ },
79
+ [{ type: type as ConfigModuleRuleType, globs: ["**/*.js"] }]
80
+ );
81
+
82
+ expect(bundle.modules[0].type).toStrictEqual(format);
83
+ });
84
+
85
+ it("should not resolve JS outside the module root", async () => {
86
+ await mkdir("./src/nested", { recursive: true });
87
+ await writeFile(
88
+ "./src/nested/index.js",
89
+ dedent/* javascript */ `
90
+ import { HELLO } from "../other.js"
91
+ export default {
92
+ async fetch(request) {
93
+ return new Response(HELLO)
94
+ }
95
+ }
96
+ `
97
+ );
98
+ await writeFile(
99
+ "./src/other.js",
100
+ dedent/* javascript */ `
101
+ export const HELLO = "WORLD"
102
+ `
103
+ );
104
+
105
+ const bundle = await traverseModuleGraph(
106
+ {
107
+ file: path.join(process.cwd(), "./src/nested/index.js"),
108
+ directory: path.join(process.cwd(), "./src/nested"),
109
+ format: "modules",
110
+ // The default module root is dirname(file)
111
+ moduleRoot: path.join(process.cwd(), "./src/nested"),
112
+ },
113
+ [{ type: "ESModule", globs: ["**/*.js"] }]
114
+ );
115
+
116
+ expect(bundle.modules).toStrictEqual([]);
117
+ });
118
+
119
+ it("should resolve JS with module root", async () => {
120
+ await mkdir("./src/nested", { recursive: true });
121
+ await writeFile(
122
+ "./src/nested/index.js",
123
+ dedent/* javascript */ `
124
+ import { HELLO } from "../other.js"
125
+ export default {
126
+ async fetch(request) {
127
+ return new Response(HELLO)
128
+ }
129
+ }
130
+ `
131
+ );
132
+ await writeFile(
133
+ "./src/other.js",
134
+ dedent/* javascript */ `
135
+ export const HELLO = "WORLD"
136
+ `
137
+ );
138
+
139
+ const bundle = await traverseModuleGraph(
140
+ {
141
+ file: path.join(process.cwd(), "./src/nested/index.js"),
142
+ directory: path.join(process.cwd(), "./src/nested"),
143
+ format: "modules",
144
+ // The default module root is dirname(file)
145
+ moduleRoot: path.join(process.cwd(), "./src"),
146
+ },
147
+ [{ type: "ESModule", globs: ["**/*.js"] }]
148
+ );
149
+
150
+ expect(bundle.modules[0].name).toStrictEqual("other.js");
151
+ });
152
+
153
+ it("should ignore files not matched by glob", async () => {
154
+ await mkdir("./src/nested", { recursive: true });
155
+ await writeFile(
156
+ "./src/nested/index.js",
157
+ dedent/* javascript */ `
158
+ import { HELLO } from "../other.js"
159
+ export default {
160
+ async fetch(request) {
161
+ return new Response(HELLO)
162
+ }
163
+ }
164
+ `
165
+ );
166
+ await writeFile(
167
+ "./src/other.js",
168
+ dedent/* javascript */ `
169
+ export const HELLO = "WORLD"
170
+ `
171
+ );
172
+
173
+ const bundle = await traverseModuleGraph(
174
+ {
175
+ file: path.join(process.cwd(), "./src/nested/index.js"),
176
+ directory: path.join(process.cwd(), "./src/nested"),
177
+ format: "modules",
178
+ // The default module root is dirname(file)
179
+ moduleRoot: path.join(process.cwd(), "./src"),
180
+ },
181
+ [{ type: "ESModule", globs: ["**/*.mjs"] }]
182
+ );
183
+
184
+ expect(bundle.modules.length).toStrictEqual(0);
185
+ });
186
+
187
+ it("should resolve files that match the default rules", async () => {
188
+ await mkdir("./src", { recursive: true });
189
+ await writeFile(
190
+ "./src/index.js",
191
+ dedent/* javascript */ `
192
+ import HELLO from "../other.txt"
193
+ export default {
194
+ async fetch(request) {
195
+ return new Response(HELLO)
196
+ }
197
+ }
198
+ `
199
+ );
200
+ await writeFile(
201
+ "./src/other.txt",
202
+ dedent/* javascript */ `
203
+ export const HELLO = "WORLD"
204
+ `
205
+ );
206
+
207
+ const bundle = await traverseModuleGraph(
208
+ {
209
+ file: path.join(process.cwd(), "./src/index.js"),
210
+ directory: path.join(process.cwd(), "./src"),
211
+ format: "modules",
212
+ // The default module root is dirname(file)
213
+ moduleRoot: path.join(process.cwd(), "./src"),
214
+ },
215
+ []
216
+ );
217
+
218
+ expect(bundle.modules[0].name).toStrictEqual("other.txt");
219
+ });
220
+ });
package/src/api/dev.ts CHANGED
@@ -143,7 +143,6 @@ export async function unstable_dev(
143
143
  enablePagesAssetsServiceBinding,
144
144
  liveReload,
145
145
  showInteractiveDevSession,
146
- forceLocal,
147
146
  onReady: (address, port) => {
148
147
  readyPort = port;
149
148
  readyAddress = address;
@@ -232,6 +231,7 @@ export async function unstable_dev(
232
231
  experimentalLocal: experimentalLocal ?? false,
233
232
  experimentalLocalRemoteKv: experimentalLocalRemoteKv ?? false,
234
233
  enablePagesAssetsServiceBinding,
234
+ forceLocal,
235
235
  liveReload,
236
236
  onReady: (address, port) => {
237
237
  readyPort = port;
@@ -301,27 +301,16 @@ export async function unstable_dev(
301
301
  export function parseRequestInput(
302
302
  readyAddress: string,
303
303
  readyPort: number,
304
- input?: RequestInfo,
304
+ input: RequestInfo = "/",
305
305
  init?: RequestInit,
306
306
  protocol: "http" | "https" = "http"
307
307
  ): [RequestInfo, RequestInit | undefined] {
308
308
  if (input instanceof Request) {
309
309
  return [input, undefined];
310
- } else if (input instanceof URL) {
311
- input = `${protocol}://${readyAddress}:${readyPort}${input.pathname}`;
312
- } else if (typeof input === "string") {
313
- try {
314
- // Want to strip the URL to only get the pathname, but the user could pass in only the pathname
315
- // Will error if we try and pass "/something" into new URL("/something")
316
- input = `${protocol}://${readyAddress}:${readyPort}${
317
- new URL(input).pathname
318
- }`;
319
- } catch {
320
- input = `${protocol}://${readyAddress}:${readyPort}${input}`;
321
- }
322
- } else {
323
- input = `${protocol}://${readyAddress}:${readyPort}`;
324
310
  }
325
-
326
- return [input, init];
311
+ const url = new URL(`${input}`, `${protocol}://${readyAddress}:${readyPort}`);
312
+ url.protocol = protocol;
313
+ url.hostname = readyAddress;
314
+ url.port = readyPort.toString();
315
+ return [url, init];
327
316
  }
@@ -49,6 +49,7 @@ function createWorkerBundleFormData(workerBundle: BundleResult): FormData {
49
49
  bindings: {
50
50
  vars: undefined,
51
51
  kv_namespaces: undefined,
52
+ send_email: undefined,
52
53
  wasm_modules: undefined,
53
54
  text_blobs: undefined,
54
55
  data_blobs: undefined,
package/src/bundle.ts CHANGED
@@ -13,6 +13,13 @@ import type { DurableObjectBindings } from "./config/environment";
13
13
  import type { WorkerRegistry } from "./dev-registry";
14
14
  import type { Entry } from "./entry";
15
15
  import type { CfModule } from "./worker";
16
+
17
+ export const COMMON_ESBUILD_OPTIONS = {
18
+ // Our workerd runtime uses the same V8 version as recent Chrome, which is highly ES2022 compliant: https://kangax.github.io/compat-table/es2016plus/
19
+ target: "es2022",
20
+ loader: { ".js": "jsx", ".mjs": "jsx", ".cjs": "jsx" },
21
+ } as const;
22
+
16
23
  export type BundleResult = {
17
24
  modules: CfModule[];
18
25
  dependencies: esbuild.Metafile["outputs"][string]["inputs"];
@@ -357,8 +364,7 @@ export async function bundleWorker(
357
364
  inject,
358
365
  external: ["__STATIC_CONTENT_MANIFEST"],
359
366
  format: entry.format === "modules" ? "esm" : "iife",
360
- // Our workerd runtime uses the same V8 version as recent Chrome, which is highly ES2022 compliant: https://kangax.github.io/compat-table/es2016plus/
361
- target: "es2022",
367
+ target: COMMON_ESBUILD_OPTIONS.target,
362
368
  sourcemap: sourcemap ?? true, // this needs to use ?? to accept false
363
369
  // Include a reference to the output folder in the sourcemap.
364
370
  // This is omitted by default, but we need it to properly resolve source paths in error output.
@@ -377,9 +383,7 @@ export async function bundleWorker(
377
383
  },
378
384
  }),
379
385
  loader: {
380
- ".js": "jsx",
381
- ".mjs": "jsx",
382
- ".cjs": "jsx",
386
+ ...COMMON_ESBUILD_OPTIONS.loader,
383
387
  ...(loader || {}),
384
388
  },
385
389
  plugins: [
@@ -74,6 +74,12 @@ interface EnvironmentInheritable {
74
74
  */
75
75
  main: string | undefined;
76
76
 
77
+ /**
78
+ * The directory in which module rules should be evaluated in a `--no-bundle` worker
79
+ * This defaults to dirname(main) when left undefined
80
+ */
81
+ base_dir: string | undefined;
82
+
77
83
  /**
78
84
  * Whether we use <name>.<subdomain>.workers.dev to
79
85
  * test and deploy your worker.
@@ -339,6 +345,24 @@ interface EnvironmentNonInheritable {
339
345
  preview_id?: string;
340
346
  }[];
341
347
 
348
+ /**
349
+ * These specify bindings to send email from inside your Worker.
350
+ *
351
+ * NOTE: This field is not automatically inherited from the top level environment,
352
+ * and so must be specified in every named environment.
353
+ *
354
+ * @default `[]`
355
+ * @nonInheritable
356
+ */
357
+ send_email: {
358
+ /** The binding name used to refer to the this binding */
359
+ name: string;
360
+ /** If this binding should be restricted to a specific verified address */
361
+ destination_address?: string;
362
+ /** If this binding should be restricted to a set of verified addresses */
363
+ allowed_destination_addresses?: string[];
364
+ }[];
365
+
342
366
  /**
343
367
  * Specifies Queues that are bound to this Worker environment.
344
368
  *
@@ -97,6 +97,7 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) {
97
97
  data_blobs,
98
98
  durable_objects,
99
99
  kv_namespaces,
100
+ send_email,
100
101
  queues,
101
102
  d1_databases,
102
103
  r2_buckets,
@@ -155,6 +156,23 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) {
155
156
  });
156
157
  }
157
158
 
159
+ if (send_email !== undefined && send_email.length > 0) {
160
+ output.push({
161
+ type: "Send Email",
162
+ entries: send_email.map(
163
+ ({ name, destination_address, allowed_destination_addresses }) => {
164
+ return {
165
+ key: name,
166
+ value:
167
+ destination_address ||
168
+ allowed_destination_addresses?.join(", ") ||
169
+ "unrestricted",
170
+ };
171
+ }
172
+ ),
173
+ });
174
+ }
175
+
158
176
  if (queues !== undefined && queues.length > 0) {
159
177
  output.push({
160
178
  type: "Queues",
@@ -358,6 +358,26 @@ function normalizeAndValidateMainField(
358
358
  }
359
359
  }
360
360
 
361
+ /**
362
+ * Validate the `base_dir` field and return the normalized values.
363
+ */
364
+ function normalizeAndValidateBaseDirField(
365
+ configPath: string | undefined,
366
+ rawDir: string | undefined
367
+ ): string | undefined {
368
+ const configDir = path.dirname(configPath ?? "wrangler.toml");
369
+ if (rawDir !== undefined) {
370
+ if (typeof rawDir === "string") {
371
+ const directory = path.resolve(configDir);
372
+ return path.resolve(directory, rawDir);
373
+ } else {
374
+ return rawDir;
375
+ }
376
+ } else {
377
+ return;
378
+ }
379
+ }
380
+
361
381
  /**
362
382
  * Validate the `dev` configuration and return the normalized values.
363
383
  */
@@ -1011,6 +1031,17 @@ function normalizeAndValidateEnvironment(
1011
1031
  ),
1012
1032
  deprecatedUpload
1013
1033
  ),
1034
+ base_dir: normalizeAndValidateBaseDirField(
1035
+ configPath,
1036
+ inheritable(
1037
+ diagnostics,
1038
+ topLevelEnv,
1039
+ rawEnv,
1040
+ "base_dir",
1041
+ isString,
1042
+ undefined
1043
+ )
1044
+ ),
1014
1045
  route,
1015
1046
  routes,
1016
1047
  triggers: inheritable(
@@ -1074,6 +1105,16 @@ function normalizeAndValidateEnvironment(
1074
1105
  validateBindingArray(envName, validateKVBinding),
1075
1106
  []
1076
1107
  ),
1108
+ send_email: notInheritable(
1109
+ diagnostics,
1110
+ topLevelEnv,
1111
+ rawConfig,
1112
+ rawEnv,
1113
+ envName,
1114
+ "send_email",
1115
+ validateBindingArray(envName, validateSendEmailBinding),
1116
+ []
1117
+ ),
1077
1118
  queues: notInheritable(
1078
1119
  diagnostics,
1079
1120
  topLevelEnv,
@@ -1765,6 +1806,53 @@ const validateKVBinding: ValidatorFn = (diagnostics, field, value) => {
1765
1806
  return isValid;
1766
1807
  };
1767
1808
 
1809
+ const validateSendEmailBinding: ValidatorFn = (diagnostics, field, value) => {
1810
+ if (typeof value !== "object" || value === null) {
1811
+ diagnostics.errors.push(
1812
+ `"send_email" bindings should be objects, but got ${JSON.stringify(
1813
+ value
1814
+ )}`
1815
+ );
1816
+ return false;
1817
+ }
1818
+ let isValid = true;
1819
+ // send email bindings must have a name.
1820
+ if (!isRequiredProperty(value, "name", "string")) {
1821
+ diagnostics.errors.push(
1822
+ `"${field}" bindings should have a string "name" field but got ${JSON.stringify(
1823
+ value
1824
+ )}.`
1825
+ );
1826
+ isValid = false;
1827
+ }
1828
+ if (!isOptionalProperty(value, "destination_address", "string")) {
1829
+ diagnostics.errors.push(
1830
+ `"${field}" bindings should, optionally, have a string "destination_address" field but got ${JSON.stringify(
1831
+ value
1832
+ )}.`
1833
+ );
1834
+ isValid = false;
1835
+ }
1836
+ if (!isOptionalProperty(value, "allowed_destination_addresses", "object")) {
1837
+ diagnostics.errors.push(
1838
+ `"${field}" bindings should, optionally, have a []string "allowed_destination_addresses" field but got ${JSON.stringify(
1839
+ value
1840
+ )}.`
1841
+ );
1842
+ isValid = false;
1843
+ }
1844
+ if (
1845
+ "destination_address" in value &&
1846
+ "allowed_destination_addresses" in value
1847
+ ) {
1848
+ diagnostics.errors.push(
1849
+ `"${field}" bindings should have either a "destination_address" or "allowed_destination_addresses" field, but not both.`
1850
+ );
1851
+ isValid = false;
1852
+ }
1853
+ return isValid;
1854
+ };
1855
+
1768
1856
  const validateQueueBinding: ValidatorFn = (diagnostics, field, value) => {
1769
1857
  if (typeof value !== "object" || value === null) {
1770
1858
  diagnostics.errors.push(
@@ -32,6 +32,12 @@ export type WorkerMetadataBinding =
32
32
  | { type: "text_blob"; name: string; part: string }
33
33
  | { type: "data_blob"; name: string; part: string }
34
34
  | { type: "kv_namespace"; name: string; namespace_id: string }
35
+ | {
36
+ type: "send_email";
37
+ name: string;
38
+ destination_address?: string;
39
+ allowed_destination_addresses?: string[];
40
+ }
35
41
  | {
36
42
  type: "durable_object_namespace";
37
43
  name: string;
@@ -105,6 +111,17 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
105
111
  });
106
112
  });
107
113
 
114
+ bindings.send_email?.forEach(
115
+ ({ name, destination_address, allowed_destination_addresses }) => {
116
+ metadataBindings.push({
117
+ name: name,
118
+ type: "send_email",
119
+ destination_address,
120
+ allowed_destination_addresses,
121
+ });
122
+ }
123
+ );
124
+
108
125
  bindings.durable_objects?.bindings.forEach(
109
126
  ({ name, class_name, script_name, environment }) => {
110
127
  metadataBindings.push({
@@ -37,7 +37,7 @@ export type QueryResult = {
37
37
  };
38
38
  query?: string;
39
39
  };
40
- // Max number of bytes to send in a single /execute call
40
+ // Max number of statements to send in a single /execute call
41
41
  const QUERY_LIMIT = 10_000;
42
42
 
43
43
  export function Options(yargs: CommonYargsArgv) {
@@ -14,6 +14,7 @@ import {
14
14
  import { runCustomBuild } from "../entry";
15
15
  import { logger } from "../logger";
16
16
  import { waitForPortToBeAvailable } from "../proxy";
17
+ import traverseModuleGraph from "../traverse-module-graph";
17
18
  import {
18
19
  setupBindings,
19
20
  getMiniflare3,
@@ -253,14 +254,7 @@ async function runEsbuild({
253
254
  dependencies,
254
255
  sourceMapPath,
255
256
  }: Awaited<ReturnType<typeof bundleWorker>> = noBundle
256
- ? {
257
- modules: [],
258
- dependencies: {},
259
- resolvedEntryPointPath: entry.file,
260
- bundleType: entry.format === "modules" ? "esm" : "commonjs",
261
- stop: undefined,
262
- sourceMapPath: undefined,
263
- }
257
+ ? await traverseModuleGraph(entry, rules)
264
258
  : await bundleWorker(entry, destination, {
265
259
  serveAssetsFromWorker,
266
260
  jsxFactory,
@@ -4,6 +4,7 @@ import { useApp } from "ink";
4
4
  import { useState, useEffect } from "react";
5
5
  import { bundleWorker, rewriteNodeCompatBuildFailure } from "../bundle";
6
6
  import { logBuildFailure, logger } from "../logger";
7
+ import traverseModuleGraph from "../traverse-module-graph";
7
8
  import type { Config } from "../config";
8
9
  import type { WorkerRegistry } from "../dev-registry";
9
10
  import type { Entry } from "../entry";
@@ -107,14 +108,7 @@ export function useEsbuild({
107
108
  stop,
108
109
  sourceMapPath,
109
110
  }: Awaited<ReturnType<typeof bundleWorker>> = noBundle
110
- ? {
111
- modules: [],
112
- dependencies: {},
113
- resolvedEntryPointPath: entry.file,
114
- bundleType: entry.format === "modules" ? "esm" : "commonjs",
115
- stop: undefined,
116
- sourceMapPath: undefined,
117
- }
111
+ ? await traverseModuleGraph(entry, rules)
118
112
  : await bundleWorker(entry, destination, {
119
113
  serveAssetsFromWorker,
120
114
  jsxFactory,
@@ -13,7 +13,7 @@ import type { HttpTerminator } from "http-terminator";
13
13
  const DEV_REGISTRY_PORT = "6284";
14
14
  const DEV_REGISTRY_HOST = `http://localhost:${DEV_REGISTRY_PORT}`;
15
15
 
16
- let server: Server;
16
+ let server: Server | null;
17
17
  let terminator: HttpTerminator;
18
18
 
19
19
  export type WorkerRegistry = Record<string, WorkerDefinition>;
@@ -102,6 +102,7 @@ export async function startWorkerRegistry() {
102
102
  */
103
103
  export async function stopWorkerRegistry() {
104
104
  await terminator?.terminate();
105
+ server = null;
105
106
  }
106
107
 
107
108
  /**
package/src/dev.tsx CHANGED
@@ -852,6 +852,7 @@ function getBindings(
852
852
  ),
853
853
  ...(args.kv || []),
854
854
  ],
855
+ send_email: configParam.send_email,
855
856
  // Use a copy of combinedVars since we're modifying it later
856
857
  vars: {
857
858
  ...getVarsForDev(configParam, env),
package/src/entry.ts CHANGED
@@ -3,6 +3,7 @@ import { existsSync, statSync } from "node:fs";
3
3
  import path from "node:path";
4
4
  import * as esbuild from "esbuild";
5
5
  import { execaCommand } from "execa";
6
+ import { COMMON_ESBUILD_OPTIONS } from "./bundle";
6
7
  import { logger } from "./logger";
7
8
  import { getBasePath } from "./paths";
8
9
  import type { Config } from "./config";
@@ -15,7 +16,16 @@ import type { Metafile } from "esbuild";
15
16
  *
16
17
  * It consists not just of a `file`, but also of a `directory` that is used to resolve relative paths.
17
18
  */
18
- export type Entry = { file: string; directory: string; format: CfScriptFormat };
19
+ export type Entry = {
20
+ /** A worker's entrypoint */
21
+ file: string;
22
+ /** A worker's directory. Usually where the wrangler.toml file is located */
23
+ directory: string;
24
+ /** Is this a module worker or a service worker? */
25
+ format: CfScriptFormat;
26
+ /** The directory that contains all of a `--no-bundle` worker's modules. Usually `${directory}/src`. Defaults to path.dirname(file) */
27
+ moduleRoot: string;
28
+ };
19
29
 
20
30
  /**
21
31
  * Compute the entry-point for the Worker.
@@ -99,7 +109,12 @@ export async function getEntry(
99
109
  );
100
110
  }
101
111
 
102
- return { file, directory, format };
112
+ return {
113
+ file,
114
+ directory,
115
+ format,
116
+ moduleRoot: config.base_dir ?? path.dirname(file),
117
+ };
103
118
  }
104
119
 
105
120
  export async function runCustomBuild(
@@ -147,17 +162,12 @@ export default async function guessWorkerFormat(
147
162
  tsconfig?: string | undefined
148
163
  ): Promise<CfScriptFormat> {
149
164
  const result = await esbuild.build({
165
+ ...COMMON_ESBUILD_OPTIONS,
150
166
  entryPoints: [entryFile],
151
167
  absWorkingDir: entryWorkingDirectory,
152
168
  metafile: true,
153
169
  bundle: false,
154
- target: "es2022",
155
170
  write: false,
156
- loader: {
157
- ".js": "jsx",
158
- ".mjs": "jsx",
159
- ".cjs": "jsx",
160
- },
161
171
  ...(tsconfig && { tsconfig }),
162
172
  });
163
173
  // result.metafile is defined because of the `metafile: true` option above.