wrangler 2.0.1 → 2.0.5

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.
@@ -30,10 +30,9 @@ describe("pages", () => {
30
30
  wrangler pages publish [directory] 🆙 Publish a directory of static assets as a Pages deployment
31
31
 
32
32
  Flags:
33
- -c, --config Path to .toml configuration file [string]
34
- -h, --help Show help [boolean]
35
- -v, --version Show version number [boolean]
36
- --legacy-env Use legacy environments [boolean]
33
+ -c, --config Path to .toml configuration file [string]
34
+ -h, --help Show help [boolean]
35
+ -v, --version Show version number [boolean]
37
36
 
38
37
  🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose"
39
38
  `);
@@ -258,20 +257,19 @@ describe("pages", () => {
258
257
  🆙 Publish a directory of static assets as a Pages deployment
259
258
 
260
259
  Positionals:
261
- directory The directory of Pages Functions [string] [default: \\"functions\\"]
260
+ directory The directory of static files to upload [string]
262
261
 
263
262
  Flags:
264
- -c, --config Path to .toml configuration file [string]
265
- -h, --help Show help [boolean]
266
- -v, --version Show version number [boolean]
267
- --legacy-env Use legacy environments [boolean]
263
+ -c, --config Path to .toml configuration file [string]
264
+ -h, --help Show help [boolean]
265
+ -v, --version Show version number [boolean]
268
266
 
269
267
  Options:
270
- --project-name The name of the project you want to list deployments for [string]
271
- --branch The branch of the project you want to list deployments for [string]
272
- --commit-hash The branch of the project you want to list deployments for [string]
273
- --commit-message The branch of the project you want to list deployments for [string]
274
- --commit-dirty The branch of the project you want to list deployments for [boolean]
268
+ --project-name The name of the project you want to deploy to [string]
269
+ --branch The name of the branch you want to deploy to [string]
270
+ --commit-hash The SHA to attach to this deployment [string]
271
+ --commit-message The commit message to attach to this deployment [string]
272
+ --commit-dirty Whether or not the workspace should be considered dirty for this deployment [boolean]
275
273
 
276
274
  🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose"
277
275
  `);
@@ -1,6 +1,7 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import * as TOML from "@iarna/toml";
4
+ import * as esbuild from "esbuild";
4
5
  import { writeAuthConfigFile } from "../user";
5
6
  import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
6
7
  import {
@@ -878,6 +879,78 @@ export default{
878
879
  expect(std.err).toMatchInlineSnapshot(`""`);
879
880
  });
880
881
 
882
+ it("should preserve exports on a module format worker", async () => {
883
+ writeWranglerToml();
884
+ fs.writeFileSync(
885
+ "index.js",
886
+ `
887
+ export const abc = 123;
888
+ export const def = "show me the money";
889
+ export default {};`
890
+ );
891
+
892
+ await runWrangler("publish index.js --dry-run --outdir out");
893
+
894
+ expect(
895
+ (
896
+ await esbuild.build({
897
+ entryPoints: [path.resolve("./out/index.js")],
898
+ metafile: true,
899
+ write: false,
900
+ })
901
+ ).metafile?.outputs["index.js"].exports
902
+ ).toMatchInlineSnapshot(`
903
+ Array [
904
+ "abc",
905
+ "def",
906
+ "default",
907
+ ]
908
+ `);
909
+
910
+ expect(std).toMatchInlineSnapshot(`
911
+ Object {
912
+ "debug": "",
913
+ "err": "",
914
+ "out": "--dry-run: exiting now.",
915
+ "warn": "",
916
+ }
917
+ `);
918
+ });
919
+
920
+ it("should not preserve exports on a service-worker format worker", async () => {
921
+ writeWranglerToml();
922
+ fs.writeFileSync(
923
+ "index.js",
924
+ `
925
+ export const abc = 123;
926
+ export const def = "show me the money";
927
+ addEventListener('fetch', event => {});`
928
+ );
929
+
930
+ await runWrangler("publish index.js --dry-run --outdir out");
931
+
932
+ expect(
933
+ (
934
+ await esbuild.build({
935
+ entryPoints: [path.resolve("./out/index.js")],
936
+ metafile: true,
937
+ write: false,
938
+ })
939
+ ).metafile?.outputs["index.js"].exports
940
+ ).toMatchInlineSnapshot(`Array []`);
941
+
942
+ expect(std).toMatchInlineSnapshot(`
943
+ Object {
944
+ "debug": "",
945
+ "err": "",
946
+ "out": "--dry-run: exiting now.",
947
+ "warn": "▲ [WARNING] The entrypoint index.js has exports like an ES Module, but hasn't defined a default export like a module worker normally would. Building the worker using \\"service-worker\\" format...
948
+
949
+ ",
950
+ }
951
+ `);
952
+ });
953
+
881
954
  it("should be able to transpile entry-points in sub-directories (sw)", async () => {
882
955
  writeWranglerToml();
883
956
  writeWorkerSource({ basePath: "./src", type: "sw" });
@@ -2476,18 +2549,66 @@ export default{
2476
2549
  },
2477
2550
  });
2478
2551
 
2479
- await expect(
2480
- runWrangler("publish index.js")
2481
- ).rejects.toThrowErrorMatchingInlineSnapshot(
2482
- `"Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\""`
2483
- );
2552
+ await expect(runWrangler("publish index.js")).rejects
2553
+ .toThrowErrorMatchingInlineSnapshot(`
2554
+ "The expected output file at \\"index.js\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
2555
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build."
2556
+ `);
2484
2557
  expect(std.out).toMatchInlineSnapshot(`
2485
2558
  "Running custom build: node -e \\"console.log('custom build');\\"
2486
2559
 
2487
2560
  If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2488
2561
  `);
2489
2562
  expect(std.err).toMatchInlineSnapshot(`
2490
- "X [ERROR] Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\"
2563
+ "X [ERROR] The expected output file at \\"index.js\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
2564
+
2565
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build.
2566
+
2567
+ "
2568
+ `);
2569
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2570
+ });
2571
+
2572
+ it("should throw an error if the entry is a directory after the build finishes", async () => {
2573
+ writeWranglerToml({
2574
+ main: "./",
2575
+ build: {
2576
+ command: `node -e "console.log('custom build');"`,
2577
+ },
2578
+ });
2579
+
2580
+ fs.writeFileSync("./worker.js", "some content", "utf-8");
2581
+ fs.mkdirSync("./dist");
2582
+ fs.writeFileSync("./dist/index.ts", "some content", "utf-8");
2583
+
2584
+ await expect(runWrangler("publish")).rejects
2585
+ .toThrowErrorMatchingInlineSnapshot(`
2586
+ "The expected output file at \\".\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
2587
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build.
2588
+ The provided entry-point path, \\".\\", points to a directory, rather than a file.
2589
+
2590
+ Did you mean to set the main field to one of:
2591
+ \`\`\`
2592
+ main = \\"./worker.js\\"
2593
+ main = \\"./dist/index.ts\\"
2594
+ \`\`\`"
2595
+ `);
2596
+ expect(std.out).toMatchInlineSnapshot(`
2597
+ "Running custom build: node -e \\"console.log('custom build');\\"
2598
+
2599
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2600
+ `);
2601
+ expect(std.err).toMatchInlineSnapshot(`
2602
+ "X [ERROR] The expected output file at \\".\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
2603
+
2604
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build.
2605
+ The provided entry-point path, \\".\\", points to a directory, rather than a file.
2606
+
2607
+ Did you mean to set the main field to one of:
2608
+ \`\`\`
2609
+ main = \\"./worker.js\\"
2610
+ main = \\"./dist/index.ts\\"
2611
+ \`\`\`
2491
2612
 
2492
2613
  "
2493
2614
  `);
@@ -80,10 +80,9 @@ describe("wrangler", () => {
80
80
  name The name of the new bucket [string] [required]
81
81
 
82
82
  Flags:
83
- -c, --config Path to .toml configuration file [string]
84
- -h, --help Show help [boolean]
85
- -v, --version Show version number [boolean]
86
- --legacy-env Use legacy environments [boolean]
83
+ -c, --config Path to .toml configuration file [string]
84
+ -h, --help Show help [boolean]
85
+ -v, --version Show version number [boolean]
87
86
  X [ERROR] Not enough non-option arguments: got 0, need at least 1
88
87
 
89
88
  "
@@ -109,10 +108,9 @@ describe("wrangler", () => {
109
108
  name The name of the new bucket [string] [required]
110
109
 
111
110
  Flags:
112
- -c, --config Path to .toml configuration file [string]
113
- -h, --help Show help [boolean]
114
- -v, --version Show version number [boolean]
115
- --legacy-env Use legacy environments [boolean]
111
+ -c, --config Path to .toml configuration file [string]
112
+ -h, --help Show help [boolean]
113
+ -v, --version Show version number [boolean]
116
114
  X [ERROR] Unknown arguments: def, ghi
117
115
 
118
116
  "
@@ -164,10 +162,9 @@ describe("wrangler", () => {
164
162
  name The name of the bucket to delete [string] [required]
165
163
 
166
164
  Flags:
167
- -c, --config Path to .toml configuration file [string]
168
- -h, --help Show help [boolean]
169
- -v, --version Show version number [boolean]
170
- --legacy-env Use legacy environments [boolean]
165
+ -c, --config Path to .toml configuration file [string]
166
+ -h, --help Show help [boolean]
167
+ -v, --version Show version number [boolean]
171
168
  X [ERROR] Not enough non-option arguments: got 0, need at least 1
172
169
 
173
170
  "
@@ -193,10 +190,9 @@ describe("wrangler", () => {
193
190
  name The name of the bucket to delete [string] [required]
194
191
 
195
192
  Flags:
196
- -c, --config Path to .toml configuration file [string]
197
- -h, --help Show help [boolean]
198
- -v, --version Show version number [boolean]
199
- --legacy-env Use legacy environments [boolean]
193
+ -c, --config Path to .toml configuration file [string]
194
+ -h, --help Show help [boolean]
195
+ -v, --version Show version number [boolean]
200
196
  X [ERROR] Unknown arguments: def, ghi
201
197
 
202
198
  "
package/src/bundle.ts CHANGED
@@ -66,7 +66,7 @@ export async function bundleWorker(
66
66
  absWorkingDir: entry.directory,
67
67
  outdir: destination,
68
68
  external: ["__STATIC_CONTENT_MANIFEST"],
69
- format: "esm",
69
+ format: entry.format === "modules" ? "esm" : "iife",
70
70
  target: "es2020",
71
71
  sourcemap: true,
72
72
  minify,
@@ -112,6 +112,9 @@ function addAuthorizationHeader(
112
112
  * doesn't return json. We inline the implementation and try not to share
113
113
  * any code with the other calls. We should push back on any new APIs that
114
114
  * try to introduce non-"standard" response structures.
115
+ *
116
+ * Note: any calls to fetchKVGetValue must call encodeURIComponent on key
117
+ * before passing it
115
118
  */
116
119
 
117
120
  export async function fetchKVGetValue(
@@ -161,7 +161,7 @@ export interface DevConfig {
161
161
  *
162
162
  * @default `8787`
163
163
  */
164
- port: number;
164
+ port: number | undefined;
165
165
 
166
166
  /**
167
167
  * Protocol that local wrangler dev server listens to requests on.
@@ -352,7 +352,7 @@ function normalizeAndValidateDev(
352
352
  ): DevConfig {
353
353
  const {
354
354
  ip = "localhost",
355
- port = 8787,
355
+ port,
356
356
  local_protocol = "http",
357
357
  upstream_protocol = "https",
358
358
  host,
package/src/dev/dev.tsx CHANGED
@@ -1,4 +1,5 @@
1
1
  import { spawn } from "node:child_process";
2
+ import * as path from "node:path";
2
3
  import { watch } from "chokidar";
3
4
  import clipboardy from "clipboardy";
4
5
  import commandExists from "command-exists";
@@ -242,9 +243,11 @@ function useCustomBuild(
242
243
  persistent: true,
243
244
  ignoreInitial: true,
244
245
  }).on("all", (_event, filePath) => {
246
+ const relativeFile =
247
+ path.relative(expectedEntry.directory, expectedEntry.file) || ".";
245
248
  //TODO: we should buffer requests to the proxy until this completes
246
249
  logger.log(`The file ${filePath} changed, restarting build...`);
247
- runCustomBuild(expectedEntry.file, build).catch((err) => {
250
+ runCustomBuild(expectedEntry.file, relativeFile, build).catch((err) => {
248
251
  logger.error("Custom build failed:", err);
249
252
  });
250
253
  });
@@ -253,7 +256,7 @@ function useCustomBuild(
253
256
  return () => {
254
257
  watcher?.close();
255
258
  };
256
- }, [build, expectedEntry.file]);
259
+ }, [build, expectedEntry]);
257
260
  }
258
261
 
259
262
  function sleep(period: number) {
package/src/entry.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import assert from "node:assert";
2
- import { existsSync } from "node:fs";
2
+ 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";
@@ -45,11 +45,16 @@ export async function getEntry(
45
45
  file = path.resolve(directory, config.main);
46
46
  }
47
47
 
48
- await runCustomBuild(file, config.build);
48
+ const relativeFile = path.relative(directory, file) || ".";
49
+ await runCustomBuild(file, relativeFile, config.build);
49
50
 
50
51
  if (fileExists(file) === false) {
51
52
  throw new Error(
52
- `Could not resolve "${path.relative(process.cwd(), file)}".`
53
+ getMissingEntryPointMessage(
54
+ `The entry-point file at "${relativeFile}" was not found.`,
55
+ file,
56
+ relativeFile
57
+ )
53
58
  );
54
59
  }
55
60
  const format = await guessWorkerFormat(
@@ -90,7 +95,8 @@ export async function getEntry(
90
95
  }
91
96
 
92
97
  export async function runCustomBuild(
93
- expectedEntry: string,
98
+ expectedEntryAbsolute: string,
99
+ expectedEntryRelative: string,
94
100
  build: Config["build"]
95
101
  ) {
96
102
  if (build?.command) {
@@ -105,12 +111,14 @@ export async function runCustomBuild(
105
111
  ...(build.cwd && { cwd: build.cwd }),
106
112
  });
107
113
 
108
- if (fileExists(expectedEntry) === false) {
114
+ if (fileExists(expectedEntryAbsolute) === false) {
109
115
  throw new Error(
110
- `Could not resolve "${path.relative(
111
- process.cwd(),
112
- expectedEntry
113
- )}" after running custom build: ${build.command}`
116
+ getMissingEntryPointMessage(
117
+ `The expected output file at "${expectedEntryRelative}" was not found after running custom build: ${build.command}.\n` +
118
+ "The `main` property in wrangler.toml should point to the file generated by the custom build.",
119
+ expectedEntryAbsolute,
120
+ expectedEntryRelative
121
+ )
114
122
  );
115
123
  }
116
124
  }
@@ -265,3 +273,50 @@ function generateAddScriptNameExamples(
265
273
  })
266
274
  .join("\n");
267
275
  }
276
+
277
+ /**
278
+ * Generate an appropriate message for when the entry-point is missing.
279
+ *
280
+ * To be more helpful to developers, we check whether there is a suitable file
281
+ * nearby to the expected file path.
282
+ */
283
+ function getMissingEntryPointMessage(
284
+ message: string,
285
+ absoluteEntryPointPath: string,
286
+ relativeEntryPointPath: string
287
+ ): string {
288
+ if (
289
+ existsSync(absoluteEntryPointPath) &&
290
+ statSync(absoluteEntryPointPath).isDirectory()
291
+ ) {
292
+ // The expected entry-point is a directory, so offer further guidance.
293
+ message += `\nThe provided entry-point path, "${relativeEntryPointPath}", points to a directory, rather than a file.\n`;
294
+
295
+ // Perhaps we can even guess what the correct path should be...
296
+ const possiblePaths: string[] = [];
297
+ for (const basenamePath of [
298
+ "worker",
299
+ "dist/worker",
300
+ "index",
301
+ "dist/index",
302
+ ]) {
303
+ for (const extension of [".ts", ".tsx", ".js", ".jsx"]) {
304
+ const filePath = basenamePath + extension;
305
+ if (fileExists(path.resolve(absoluteEntryPointPath, filePath))) {
306
+ possiblePaths.push(path.join(relativeEntryPointPath, filePath));
307
+ }
308
+ }
309
+ }
310
+
311
+ if (possiblePaths.length > 0) {
312
+ message +=
313
+ `\nDid you mean to set the main field to${
314
+ possiblePaths.length > 1 ? " one of" : ""
315
+ }:\n` +
316
+ "```\n" +
317
+ possiblePaths.map((filePath) => `main = "./${filePath}"\n`).join("") +
318
+ "```";
319
+ }
320
+ }
321
+ return message;
322
+ }