wrangler 0.0.0-e14e589 → 0.0.0-e928f94

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/src/dev.tsx CHANGED
@@ -22,6 +22,7 @@ import commandExists from "command-exists";
22
22
  import assert from "assert";
23
23
  import { getAPIToken } from "./user";
24
24
  import fetch from "node-fetch";
25
+ import makeModuleCollector from "./module-collection";
25
26
 
26
27
  type CfScriptFormat = void | "modules" | "service-worker";
27
28
 
@@ -32,9 +33,14 @@ type Props = {
32
33
  format: CfScriptFormat;
33
34
  accountId: void | string;
34
35
  initialMode: "local" | "remote";
35
- variables?: { [name: string]: CfVariable };
36
- public?: void | string;
37
- site?: void | string;
36
+ jsxFactory: void | string;
37
+ jsxFragment: void | string;
38
+ variables: { [name: string]: CfVariable };
39
+ public: void | string;
40
+ site: void | string;
41
+ compatibilityDate: void | string;
42
+ compatibilityFlags: void | string[];
43
+ usageModel: void | "bundled" | "unbound";
38
44
  };
39
45
 
40
46
  export function Dev(props: Props): JSX.Element {
@@ -47,7 +53,13 @@ export function Dev(props: Props): JSX.Element {
47
53
  const apiToken = getAPIToken();
48
54
  const directory = useTmpDir();
49
55
 
50
- const bundle = useEsbuild(props.entry, directory, props.public);
56
+ const bundle = useEsbuild({
57
+ entry: props.entry,
58
+ destination: directory,
59
+ staticRoot: props.public,
60
+ jsxFactory: props.jsxFactory,
61
+ jsxFragment: props.jsxFragment,
62
+ });
51
63
  if (bundle && bundle.type === "commonjs" && !props.format && props.public) {
52
64
  throw new Error(
53
65
  "You cannot use the service worker format with a `public` directory."
@@ -90,6 +102,9 @@ export function Dev(props: Props): JSX.Element {
90
102
  site={props.site}
91
103
  public={props.public}
92
104
  port={props.port}
105
+ compatibilityDate={props.compatibilityDate}
106
+ compatibilityFlags={props.compatibilityFlags}
107
+ usageModel={props.usageModel}
93
108
  />
94
109
  )}
95
110
  <Box borderStyle="round" paddingLeft={1} paddingRight={1}>
@@ -145,6 +160,9 @@ function Remote(props: {
145
160
  accountId: void | string;
146
161
  apiToken: void | string;
147
162
  variables: { [name: string]: CfVariable };
163
+ compatibilityDate: string | void;
164
+ compatibilityFlags: void | string[];
165
+ usageModel: void | "bundled" | "unbound";
148
166
  }) {
149
167
  assert(props.accountId, "accountId is required");
150
168
  assert(props.apiToken, "apiToken is required");
@@ -152,12 +170,15 @@ function Remote(props: {
152
170
  name: props.name,
153
171
  bundle: props.bundle,
154
172
  format: props.format,
155
- modules: [],
173
+ modules: props.bundle ? props.bundle.modules : [],
156
174
  accountId: props.accountId,
157
175
  apiToken: props.apiToken,
158
176
  variables: props.variables,
159
177
  sitesFolder: props.site,
160
178
  port: props.port,
179
+ compatibilityDate: props.compatibilityDate,
180
+ compatibilityFlags: props.compatibilityFlags,
181
+ usageModel: props.usageModel,
161
182
  });
162
183
 
163
184
  useProxy({ token, publicRoot: props.public, port: props.port });
@@ -228,6 +249,7 @@ function useLocalWorker(props: {
228
249
  port.toString(),
229
250
  "--kv-persist",
230
251
  "--cache-persist",
252
+ "--do-persist",
231
253
  ...Object.entries(variables)
232
254
  .map(([varKey, varVal]) => {
233
255
  if (typeof varVal === "string") {
@@ -237,6 +259,8 @@ function useLocalWorker(props: {
237
259
  typeof varVal.namespaceId === "string"
238
260
  ) {
239
261
  return `--kv ${varKey}`;
262
+ } else if ("class_name" in varVal) {
263
+ return `--do ${varKey}=${varVal.class_name}`;
240
264
  }
241
265
  })
242
266
  .filter(Boolean),
@@ -254,7 +278,7 @@ function useLocalWorker(props: {
254
278
  }
255
279
  });
256
280
 
257
- local.current.stdout.on("data", (data: string) => {
281
+ local.current.stdout.on("data", (_data: string) => {
258
282
  // console.log(`stdout: ${data}`);
259
283
  });
260
284
 
@@ -269,7 +293,7 @@ function useLocalWorker(props: {
269
293
  }
270
294
  });
271
295
 
272
- removeSignalExitListener.current = onExit((code, signal) => {
296
+ removeSignalExitListener.current = onExit((_code, _signal) => {
273
297
  console.log("⎔ Shutting down local server.");
274
298
  local.current?.kill();
275
299
  local.current = undefined;
@@ -320,18 +344,23 @@ type EsbuildBundle = {
320
344
  entry: string;
321
345
  type: "esm" | "commonjs";
322
346
  exports: string[];
347
+ modules: CfModule[];
323
348
  };
324
349
 
325
- function useEsbuild(
326
- entry: string,
327
- destination: string | void,
328
- staticRoot: void | string
329
- ): EsbuildBundle | void {
350
+ function useEsbuild(props: {
351
+ entry: string;
352
+ destination: string | void;
353
+ staticRoot: void | string;
354
+ jsxFactory: string | void;
355
+ jsxFragment: string | void;
356
+ }): EsbuildBundle | void {
357
+ const { entry, destination, staticRoot, jsxFactory, jsxFragment } = props;
330
358
  const [bundle, setBundle] = useState<EsbuildBundle>();
331
359
  useEffect(() => {
332
360
  let result: esbuild.BuildResult;
333
361
  async function build() {
334
362
  if (!destination) return;
363
+ const moduleCollector = makeModuleCollector();
335
364
  result = await esbuild.build({
336
365
  entryPoints: [entry],
337
366
  bundle: true,
@@ -339,7 +368,14 @@ function useEsbuild(
339
368
  metafile: true,
340
369
  format: "esm",
341
370
  sourcemap: true,
371
+ loader: {
372
+ ".js": "jsx",
373
+ },
374
+ ...(jsxFactory && { jsxFactory }),
375
+ ...(jsxFragment && { jsxFragment }),
342
376
  external: ["__STATIC_CONTENT_MANIFEST"],
377
+ conditions: ["worker", "browser"],
378
+ plugins: [moduleCollector.plugin],
343
379
  // TODO: import.meta.url
344
380
  watch: {
345
381
  async onRebuild(error) {
@@ -363,13 +399,14 @@ function useEsbuild(
363
399
  path: chunks[0],
364
400
  type: chunks[1].exports.length > 0 ? "esm" : "commonjs",
365
401
  exports: chunks[1].exports,
402
+ modules: moduleCollector.modules,
366
403
  });
367
404
  }
368
405
  build();
369
406
  return () => {
370
407
  result?.stop();
371
408
  };
372
- }, [entry, destination, staticRoot]);
409
+ }, [entry, destination, staticRoot, jsxFactory, jsxFragment]);
373
410
  return bundle;
374
411
  }
375
412
 
@@ -383,6 +420,9 @@ function useWorker(props: {
383
420
  variables: { [name: string]: CfVariable };
384
421
  sitesFolder: void | string;
385
422
  port: number;
423
+ compatibilityDate: string | void;
424
+ compatibilityFlags: string[] | void;
425
+ usageModel: void | "bundled" | "unbound";
386
426
  }): CfPreviewToken | void {
387
427
  const {
388
428
  name,
@@ -393,6 +433,9 @@ function useWorker(props: {
393
433
  apiToken,
394
434
  variables,
395
435
  sitesFolder,
436
+ compatibilityDate,
437
+ compatibilityFlags,
438
+ usageModel,
396
439
  port,
397
440
  } = props;
398
441
  const [token, setToken] = useState<CfPreviewToken>();
@@ -415,12 +458,11 @@ function useWorker(props: {
415
458
  } else {
416
459
  console.log("⎔ Starting server...");
417
460
  }
418
- const scriptName = path.basename(bundle.path);
419
461
 
420
462
  const assets = sitesFolder
421
463
  ? await syncAssets(
422
464
  accountId,
423
- scriptName,
465
+ path.basename(bundle.path),
424
466
  sitesFolder,
425
467
  true,
426
468
  undefined // TODO: env
@@ -432,13 +474,10 @@ function useWorker(props: {
432
474
 
433
475
  const content = await readFile(bundle.path, "utf-8");
434
476
  const init: CfWorkerInit = {
477
+ name,
435
478
  main: {
436
- name: name || path.basename(bundle.path),
437
- type:
438
- format ||
439
- (bundle.type === "esm" ? "modules" : "service-worker") === "modules"
440
- ? "esm"
441
- : "commonjs",
479
+ name: path.basename(bundle.path),
480
+ type: format || bundle.type === "esm" ? "esm" : "commonjs",
442
481
  content,
443
482
  },
444
483
  modules: assets.manifest
@@ -454,6 +493,10 @@ function useWorker(props: {
454
493
  __STATIC_CONTENT: { namespaceId: assets.namespace },
455
494
  }
456
495
  : variables,
496
+ migrations: undefined, // no migrations in dev
497
+ compatibility_date: compatibilityDate,
498
+ compatibility_flags: compatibilityFlags,
499
+ usage_model: usageModel,
457
500
  };
458
501
  setToken(
459
502
  await createWorker(init, {
@@ -464,7 +507,18 @@ function useWorker(props: {
464
507
  console.log(`⬣ Listening at http://localhost:${port}`);
465
508
  }
466
509
  start();
467
- }, [name, bundle, format, accountId, apiToken, port, sitesFolder]);
510
+ }, [
511
+ name,
512
+ bundle,
513
+ format,
514
+ accountId,
515
+ apiToken,
516
+ port,
517
+ sitesFolder,
518
+ compatibilityDate,
519
+ compatibilityFlags,
520
+ usageModel,
521
+ ]);
468
522
  return token;
469
523
  }
470
524
 
@@ -589,7 +643,7 @@ function useTunnel(toggle: boolean) {
589
643
  }
590
644
  });
591
645
 
592
- removeSignalExitListener.current = onExit((code, signal) => {
646
+ removeSignalExitListener.current = onExit((_code, _signal) => {
593
647
  console.log("⎔ Shutting down local tunnel.");
594
648
  tunnel.current?.kill();
595
649
  tunnel.current = undefined;
package/src/dialogs.tsx CHANGED
@@ -43,7 +43,7 @@ type PromptProps = {
43
43
  onSubmit: (text: string) => void;
44
44
  };
45
45
 
46
- export function Prompt(props: PromptProps) {
46
+ function Prompt(props: PromptProps) {
47
47
  const [value, setValue] = useState("");
48
48
 
49
49
  return (
package/src/index.tsx CHANGED
@@ -40,7 +40,7 @@ import { createTail } from "./tail";
40
40
  import onExit from "signal-exit";
41
41
  import { setTimeout } from "node:timers/promises";
42
42
  import * as fs from "node:fs";
43
- import execa from "execa";
43
+ import { execa } from "execa";
44
44
 
45
45
  async function readConfig(path?: string): Promise<Config> {
46
46
  const config: Config = {};
@@ -55,6 +55,44 @@ async function readConfig(path?: string): Promise<Config> {
55
55
  Object.assign(config, parsed);
56
56
  }
57
57
 
58
+ const inheritedFields = [
59
+ "name",
60
+ "account_id",
61
+ "workers_dev",
62
+ "compatibility_date",
63
+ "compatibility_flags",
64
+ "zone_id",
65
+ "routes",
66
+ "route",
67
+ "jsx_factory",
68
+ "jsx_fragment",
69
+ "site",
70
+ "triggers",
71
+ "usage_model",
72
+ ];
73
+
74
+ Object.keys(config.env || {}).forEach((env) => {
75
+ inheritedFields.forEach((field) => {
76
+ if (config[field] !== undefined && config.env[env][field] === undefined) {
77
+ config.env[env][field] = config[field]; // TODO: - shallow copy?
78
+ }
79
+ });
80
+ });
81
+
82
+ const mirroredFields = ["vars", "kv_namespaces", "durable_objects"];
83
+ Object.keys(config.env || {}).forEach((env) => {
84
+ mirroredFields.forEach((field) => {
85
+ // if it exists on top level, it should exist on env defns
86
+ Object.keys(config[field] || {}).forEach((fieldKey) => {
87
+ if (!(fieldKey in config.env[env][field])) {
88
+ console.error(
89
+ `In your configuration, "${field}.${fieldKey}" exists at a top level, but not on "env.${env}". This is not what you probably want, since the field "${field}" is not inherited by environments. Please add "${field}.${fieldKey}" to "env.${env}".`
90
+ );
91
+ }
92
+ });
93
+ });
94
+ });
95
+
58
96
  // todo: validate, add defaults
59
97
  // let's just do some basics for now
60
98
 
@@ -155,8 +193,7 @@ export async function main(argv: string[]): Promise<void> {
155
193
  try {
156
194
  await writeFile(
157
195
  destination,
158
- `compatibility_date = "${compatibilityDate}"
159
- `
196
+ `compatibility_date = "${compatibilityDate}"` + "\n"
160
197
  );
161
198
  console.log(`✨ Succesfully created wrangler.toml`);
162
199
  // TODO: suggest next steps?
@@ -356,7 +393,7 @@ export async function main(argv: string[]): Promise<void> {
356
393
  .option("host", {
357
394
  type: "string",
358
395
  describe:
359
- "Host to forward requests to, defaults to the zone of project or to tutorial.cloudflareworkers.com if unauthenticated",
396
+ "Host to forward requests to, defaults to the zone of project",
360
397
  })
361
398
  .option("local-protocol", {
362
399
  default: "http",
@@ -376,6 +413,14 @@ export async function main(argv: string[]): Promise<void> {
376
413
  describe:
377
414
  "Protocol to forward requests to host on, defaults to https.",
378
415
  choices: ["http", "https"],
416
+ })
417
+ .option("jsx-factory", {
418
+ describe: "The function that is called for each JSX element",
419
+ type: "string",
420
+ })
421
+ .option("jsx-fragment", {
422
+ describe: "The function that is called for each JSX fragment",
423
+ type: "string",
379
424
  });
380
425
  },
381
426
  async (args) => {
@@ -402,7 +447,18 @@ export async function main(argv: string[]): Promise<void> {
402
447
 
403
448
  // -- snip, end --
404
449
 
405
- const envRootObj = args.env ? config[`env.${args.env}`] : config;
450
+ const envRootObj = args.env ? config.env[args.env] || {} : config;
451
+
452
+ // TODO: this error shouldn't actually happen,
453
+ // but we haven't fixed it internally yet
454
+ if ("durable_objects" in envRootObj) {
455
+ if (!(args.name || config.name)) {
456
+ console.warn(
457
+ 'A worker with durable objects need to be named, or it may not work as expected. Add a "name" into wrangler.toml, or pass it in the command line with --name.'
458
+ );
459
+ }
460
+ // TODO: if not already published, publish a draft worker
461
+ }
406
462
 
407
463
  render(
408
464
  <Dev
@@ -410,10 +466,15 @@ export async function main(argv: string[]): Promise<void> {
410
466
  entry={filename}
411
467
  format={format}
412
468
  initialMode={args.local ? "local" : "remote"}
469
+ jsxFactory={args["jsx-factory"] || envRootObj?.jsx_factory}
470
+ jsxFragment={args["jsx-fragment"] || envRootObj?.jsx_fragment}
413
471
  accountId={config.account_id}
414
472
  site={args.site || config.site?.bucket}
415
473
  port={args.port || config.dev?.port}
416
474
  public={args.public}
475
+ compatibilityDate={config.compatibility_date}
476
+ compatibilityFlags={config.compatibility_flags}
477
+ usageModel={config.usage_model}
417
478
  variables={{
418
479
  ...(envRootObj?.vars || {}),
419
480
  ...(envRootObj?.kv_namespaces || []).reduce(
@@ -429,6 +490,12 @@ export async function main(argv: string[]): Promise<void> {
429
490
  },
430
491
  {}
431
492
  ),
493
+ ...(envRootObj?.durable_objects?.bindings || []).reduce(
494
+ (obj, { name, class_name, script_name }) => {
495
+ return { ...obj, [name]: { class_name, script_name } };
496
+ },
497
+ {}
498
+ ),
432
499
  }}
433
500
  />
434
501
  );
@@ -476,6 +543,14 @@ export async function main(argv: string[]): Promise<void> {
476
543
  type: "boolean",
477
544
  default: "false",
478
545
  hidden: true,
546
+ })
547
+ .option("jsx-factory", {
548
+ describe: "The function that is called for each JSX element",
549
+ type: "string",
550
+ })
551
+ .option("jsx-fragment", {
552
+ describe: "The function that is called for each JSX fragment",
553
+ type: "string",
479
554
  });
480
555
  },
481
556
  async (args) => {
@@ -510,6 +585,8 @@ export async function main(argv: string[]): Promise<void> {
510
585
  script: args.script,
511
586
  env: args.env,
512
587
  triggers: args.triggers,
588
+ jsxFactory: args["jsx-factory"],
589
+ jsxFragment: args["jsx-fragment"],
513
590
  routes: args.routes,
514
591
  public: args.public,
515
592
  site: args.site,
@@ -1095,7 +1172,7 @@ export async function main(argv: string[]): Promise<void> {
1095
1172
  console.log(
1096
1173
  `{ binding = "${args.namespace}", ${
1097
1174
  args.preview ? "preview_" : ""
1098
- }id = ${response.id} }`
1175
+ }id = "${response.id}" }`
1099
1176
  );
1100
1177
  }
1101
1178
  )
@@ -1175,7 +1252,7 @@ export async function main(argv: string[]): Promise<void> {
1175
1252
  const id =
1176
1253
  args["namespace-id"] ||
1177
1254
  (args.env
1178
- ? config[`env.${args.env}`]
1255
+ ? config.env[args.env] || {}
1179
1256
  : config
1180
1257
  ).kv_namespaces.find(
1181
1258
  (namespace) => namespace.binding === args.binding
@@ -1239,7 +1316,7 @@ export async function main(argv: string[]): Promise<void> {
1239
1316
  (yargs) => {
1240
1317
  return yargs
1241
1318
  .command(
1242
- "put <key> <value>",
1319
+ "put <key> [value]",
1243
1320
  "Writes a single key/value pair to the given namespace.",
1244
1321
  (yargs) => {
1245
1322
  return yargs
@@ -1280,7 +1357,8 @@ export async function main(argv: string[]): Promise<void> {
1280
1357
  .option("path", {
1281
1358
  type: "string",
1282
1359
  describe: "Read value from the file at a given path.",
1283
- });
1360
+ })
1361
+ .check(demandOneOfOption("value", "path"));
1284
1362
  },
1285
1363
  async ({ key, ttl, expiration, ...args }) => {
1286
1364
  const namespaceId = getNamespaceId(args);
@@ -1289,7 +1367,16 @@ export async function main(argv: string[]): Promise<void> {
1289
1367
  : args.value;
1290
1368
  const config = args.config as Config;
1291
1369
 
1292
- console.log(`writing ${key}=${value} to namespace ${namespaceId}`);
1370
+ if (args.path) {
1371
+ console.log(
1372
+ `writing the contents of ${args.path} to the key "${key}" on namespace ${namespaceId}`
1373
+ );
1374
+ } else {
1375
+ console.log(
1376
+ `writing the value "${value}" to key "${key}" on namespace ${namespaceId}`
1377
+ );
1378
+ }
1379
+
1293
1380
  if (args.local) {
1294
1381
  const { Miniflare } = await import("miniflare");
1295
1382
  const mf = new Miniflare({
@@ -1501,6 +1588,10 @@ export async function main(argv: string[]): Promise<void> {
1501
1588
  async ({ key, ...args }) => {
1502
1589
  const namespaceId = getNamespaceId(args);
1503
1590
 
1591
+ console.log(
1592
+ `deleting the key "${key}" on namespace ${namespaceId}`
1593
+ );
1594
+
1504
1595
  if (args.local) {
1505
1596
  const { Miniflare } = await import("miniflare");
1506
1597
  const mf = new Miniflare({
@@ -1730,6 +1821,7 @@ export async function main(argv: string[]): Promise<void> {
1730
1821
 
1731
1822
  yargs
1732
1823
  .option("config", {
1824
+ alias: "c",
1733
1825
  describe: "Path to .toml configuration file",
1734
1826
  type: "string",
1735
1827
  async coerce(arg) {
@@ -1737,18 +1829,30 @@ export async function main(argv: string[]): Promise<void> {
1737
1829
  },
1738
1830
  })
1739
1831
  .option("local", {
1832
+ alias: "l",
1740
1833
  describe: "Run on my machine",
1741
1834
  type: "boolean",
1742
1835
  default: false, // I bet this will a point of contention. We'll revisit it.
1743
1836
  });
1744
1837
 
1745
1838
  yargs.group(["config", "help", "version"], "Flags:");
1746
-
1839
+ yargs.help().alias("h", "help");
1840
+ yargs.version(wranglerVersion).alias("v", "version");
1747
1841
  await initialiseUserConfig();
1748
- await yargs.parse(argv, (err, argv, output) => {
1749
- if (output) {
1750
- console.log(output);
1751
- }
1752
- });
1753
- yargs.version(wranglerVersion);
1842
+
1843
+ await yargs.parse(
1844
+ argv
1845
+ /* TODO: we'd like to use the parse callback,
1846
+ but there's a serious bug with it
1847
+ https://github.com/yargs/yargs/issues/1975#issuecomment-874237906
1848
+
1849
+ , (err, argv, output) => {
1850
+ if (output) {
1851
+ console.log(output);
1852
+ }
1853
+ console.log({ err });
1854
+ console.log("what now");
1855
+ }
1856
+ */
1857
+ );
1754
1858
  }
package/src/kv.tsx CHANGED
@@ -118,7 +118,7 @@ export function getNamespaceId({
118
118
  if (!config) {
119
119
  throw new Error(
120
120
  "Failed to find a config file.\n" +
121
- "Either use --namespace to upload directly or create a configuration file with a binding."
121
+ "Either use --namespace-id to upload directly or create a configuration file with a binding."
122
122
  );
123
123
  }
124
124
 
@@ -149,7 +149,7 @@ export function getNamespaceId({
149
149
  // there's no KV namespaces
150
150
  if (!config.kv_namespaces || config.kv_namespaces.length === 0) {
151
151
  throw new Error(
152
- "No KV Namespace to upload to! Either use --namespace to upload directly or add a KV namespace to your wrangler config file."
152
+ "No KV Namespace to upload to! Either use --namespace-id to upload directly or add a KV namespace to your wrangler config file."
153
153
  );
154
154
  }
155
155
 
@@ -0,0 +1,64 @@
1
+ import type { CfModule } from "./api/worker";
2
+ import type esbuild from "esbuild";
3
+ import path from "node:path";
4
+ import { readFile } from "node:fs/promises";
5
+ import crypto from "node:crypto";
6
+
7
+ // This is a combination of an esbuild plugin and a mutable array
8
+ // that we use to collect module references from source code.
9
+ // There will be modules that _shouldn't_ be inlined directly into
10
+ // the bundle. (eg. wasm modules, some text files, etc). We can include
11
+ // those files as modules in the multi part forker form upload. This
12
+ // plugin+array is used to collect references to these modules, reference
13
+ // them correctly in the bundle, and add them to the form upload.
14
+
15
+ export default function makeModuleCollector(): {
16
+ modules: CfModule[];
17
+ plugin: esbuild.Plugin;
18
+ } {
19
+ const modules: CfModule[] = [];
20
+ return {
21
+ modules,
22
+ plugin: {
23
+ name: "wrangler-module-collector",
24
+ setup(build) {
25
+ build.onStart(() => {
26
+ // reset the moduels collection
27
+ modules.splice(0);
28
+ });
29
+
30
+ build.onResolve(
31
+ // filter on "known" file types,
32
+ // we can expand this list later
33
+ { filter: /.*\.(pem|txt|html|wasm)$/ },
34
+ async (args: esbuild.OnResolveArgs) => {
35
+ // take the file and massage it to a
36
+ // transportable/manageable format
37
+ const fileExt = path.extname(args.path);
38
+ const filePath = path.join(args.resolveDir, args.path);
39
+ const fileContent = await readFile(filePath);
40
+ const fileHash = crypto
41
+ .createHash("sha1")
42
+ .update(fileContent)
43
+ .digest("hex");
44
+ const fileName = `${fileHash}-${path.basename(args.path)}`;
45
+
46
+ // add the module to the array
47
+ modules.push({
48
+ name: fileName,
49
+ content: fileContent,
50
+ type: fileExt === ".wasm" ? "compiled-wasm" : "text",
51
+ });
52
+
53
+ return {
54
+ path: fileName, // change the reference to the changed module
55
+ external: true, // mark it as external in the bundle
56
+ namespace: "wrangler-module-collector-ns", // just a tag, this isn't strictly necessary
57
+ watchFiles: [filePath], // we also add the file to esbuild's watch list
58
+ };
59
+ }
60
+ );
61
+ },
62
+ },
63
+ };
64
+ }