wrangler 2.12.0 → 2.12.2

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.
@@ -1,6 +1,5 @@
1
- import { existsSync, writeFileSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { basename, dirname, join, resolve as resolvePath } from "node:path";
1
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { basename, dirname, relative, resolve as resolvePath } from "node:path";
4
3
  import { createUploadWorkerBundleContents } from "../api/pages/create-worker-bundle-contents";
5
4
  import { FatalError } from "../errors";
6
5
  import { logger } from "../logger";
@@ -8,6 +7,7 @@ import * as metrics from "../metrics";
8
7
  import { buildFunctions } from "./buildFunctions";
9
8
  import { isInPagesCI } from "./constants";
10
9
  import {
10
+ EXIT_CODE_FUNCTIONS_NOTHING_TO_BUILD_ERROR,
11
11
  EXIT_CODE_FUNCTIONS_NO_ROUTES_ERROR,
12
12
  FunctionsNoRoutesError,
13
13
  getFunctionsNoRoutesWarning,
@@ -32,9 +32,12 @@ export function Options(yargs: CommonYargsArgv) {
32
32
  .options({
33
33
  outfile: {
34
34
  type: "string",
35
- default: "_worker.js",
36
35
  description: "The location of the output Worker script",
37
36
  },
37
+ outdir: {
38
+ type: "string",
39
+ description: "Output directory for the bundled Worker",
40
+ },
38
41
  "output-config-path": {
39
42
  type: "string",
40
43
  description: "The location for the output config file",
@@ -99,104 +102,36 @@ export function Options(yargs: CommonYargsArgv) {
99
102
  deprecated: true,
100
103
  hidden: true,
101
104
  },
102
- "experimental-worker-bundle": {
103
- type: "boolean",
104
- default: false,
105
- hidden: true,
106
- description:
107
- "Whether to process non-JS module imports or not, such as wasm/text/binary, when we run bundling on `functions` or `_worker.js`",
108
- },
109
105
  })
110
106
  .epilogue(pagesBetaWarning);
111
107
  }
112
108
 
113
- export const Handler = async ({
114
- directory,
115
- outfile,
116
- outputConfigPath,
117
- outputRoutesPath: routesOutputPath,
118
- minify,
119
- sourcemap,
120
- fallbackService,
121
- watch,
122
- plugin,
123
- buildOutputDirectory,
124
- nodeCompat: legacyNodeCompat,
125
- compatibilityFlags,
126
- bindings,
127
- experimentalWorkerBundle,
128
- }: PagesBuildArgs) => {
109
+ export const Handler = async (args: PagesBuildArgs) => {
129
110
  if (!isInPagesCI) {
130
111
  // Beta message for `wrangler pages <commands>` usage
131
112
  logger.log(pagesBetaWarning);
132
113
  }
133
114
 
134
- if (legacyNodeCompat) {
135
- console.warn(
136
- "Enabling Node.js compatibility mode for builtins and globals. This is experimental and has serious tradeoffs. Please see https://github.com/ionic-team/rollup-plugin-node-polyfills/ for more details."
137
- );
138
- }
139
- const nodejsCompat = compatibilityFlags?.includes("nodejs_compat");
140
- if (legacyNodeCompat && nodejsCompat) {
141
- throw new Error(
142
- "The `nodejs_compat` compatibility flag cannot be used in conjunction with the legacy `--node-compat` flag. If you want to use the Workers runtime Node.js compatibility features, please remove the `--node-compat` argument from your CLI command."
143
- );
144
- }
145
-
146
- let d1Databases: string[] | undefined = undefined;
147
- if (bindings) {
148
- try {
149
- const decodedBindings = JSON.parse(bindings);
150
- d1Databases = Object.keys(decodedBindings?.d1_databases || {});
151
- } catch {
152
- throw new FatalError("Could not parse a valid set of 'bindings'.", 1);
153
- }
154
- }
155
-
156
- buildOutputDirectory ??= dirname(outfile);
115
+ const validatedArgs = validateArgs(args);
157
116
 
158
- const workerScriptPath = resolvePath(buildOutputDirectory, "_worker.js");
159
- const foundWorkerScript = existsSync(workerScriptPath);
160
117
  let bundle: BundleResult | undefined = undefined;
161
118
 
162
- if (!foundWorkerScript && !existsSync(directory)) {
163
- throw new FatalError(`Could not find anything to build.
164
- We first looked inside the build output directory (${basename(
165
- resolvePath(buildOutputDirectory)
166
- )}), then looked for the Functions directory (${basename(
167
- directory
168
- )}) but couldn't find anything to build.
169
- ➤ If you are trying to build _worker.js, please make sure you provide the [--build-output-directory] containing your static files.
170
- ➤ If you are trying to build Pages Functions, please make sure [--directory] points to the location of your Functions files.`);
171
- }
172
-
173
- /**
174
- * prioritize building `_worker.js` over Pages Functions, if both exist
175
- * and if we were able to resolve _worker.js
176
- */
177
- if (experimentalWorkerBundle && foundWorkerScript) {
178
- /**
179
- * `buildRawWorker` builds `_worker.js`, but doesn't give us the bundle
180
- * we want to return, which includes the external dependencies (like wasm,
181
- * binary, text). Let's output that build result to memory and only write
182
- * to disk once we have the final bundle
183
- */
184
- const workerOutfile = experimentalWorkerBundle
185
- ? join(tmpdir(), `./bundledWorker-${Math.random()}.mjs`)
186
- : outfile;
119
+ if (validatedArgs.plugin) {
120
+ const {
121
+ directory,
122
+ outfile,
123
+ outdir,
124
+ outputConfigPath,
125
+ outputRoutesPath: routesOutputPath,
126
+ minify,
127
+ sourcemap,
128
+ fallbackService,
129
+ watch,
130
+ plugin,
131
+ nodejsCompat,
132
+ legacyNodeCompat,
133
+ } = validatedArgs;
187
134
 
188
- bundle = await buildRawWorker({
189
- workerScriptPath,
190
- outfile: workerOutfile,
191
- directory: buildOutputDirectory,
192
- local: false,
193
- sourcemap: true,
194
- watch: false,
195
- onEnd: () => {},
196
- betaD1Shims: d1Databases,
197
- experimentalWorkerBundle,
198
- });
199
- } else {
200
135
  try {
201
136
  /**
202
137
  * `buildFunctions` builds `/functions`, but doesn't give us the bundle
@@ -204,12 +139,9 @@ We first looked inside the build output directory (${basename(
204
139
  * binary, text). Let's output that build result to memory and only write
205
140
  * to disk once we have the final bundle
206
141
  */
207
- const functionsOutfile = experimentalWorkerBundle
208
- ? join(tmpdir(), `./functionsWorker-${Math.random()}.js`)
209
- : outfile;
210
-
211
142
  bundle = await buildFunctions({
212
- outfile: functionsOutfile,
143
+ outfile,
144
+ outdir,
213
145
  outputConfigPath,
214
146
  functionsDirectory: directory,
215
147
  minify,
@@ -217,13 +149,10 @@ We first looked inside the build output directory (${basename(
217
149
  fallbackService,
218
150
  watch,
219
151
  plugin,
220
- buildOutputDirectory,
221
152
  legacyNodeCompat,
222
153
  nodejsCompat,
223
154
  routesOutputPath,
224
155
  local: false,
225
- d1Databases,
226
- experimentalWorkerBundle,
227
156
  });
228
157
  } catch (e) {
229
158
  if (e instanceof FunctionsNoRoutesError) {
@@ -235,18 +164,247 @@ We first looked inside the build output directory (${basename(
235
164
  throw e;
236
165
  }
237
166
  }
167
+
168
+ if (outfile && outfile !== bundle.resolvedEntryPointPath) {
169
+ writeFileSync(
170
+ outfile,
171
+ `export { default } from './${relative(
172
+ dirname(outfile),
173
+ bundle.resolvedEntryPointPath
174
+ )}'`
175
+ );
176
+ }
177
+ } else {
178
+ const {
179
+ directory,
180
+ outfile,
181
+ outdir,
182
+ outputConfigPath,
183
+ outputRoutesPath: routesOutputPath,
184
+ minify,
185
+ sourcemap,
186
+ fallbackService,
187
+ watch,
188
+ plugin,
189
+ buildOutputDirectory,
190
+ nodejsCompat,
191
+ legacyNodeCompat,
192
+ bindings,
193
+ workerScriptPath,
194
+ } = validatedArgs;
195
+
196
+ let d1Databases: string[] | undefined = undefined;
197
+ if (bindings) {
198
+ try {
199
+ const decodedBindings = JSON.parse(bindings);
200
+ d1Databases = Object.keys(decodedBindings?.d1_databases || {});
201
+ } catch {
202
+ throw new FatalError("Could not parse a valid set of 'bindings'.", 1);
203
+ }
204
+ }
205
+
206
+ /**
207
+ * prioritize building `_worker.js` over Pages Functions, if both exist
208
+ * and if we were able to resolve _worker.js
209
+ */
210
+ if (workerScriptPath) {
211
+ /**
212
+ * `buildRawWorker` builds `_worker.js`, but doesn't give us the bundle
213
+ * we want to return, which includes the external dependencies (like wasm,
214
+ * binary, text). Let's output that build result to memory and only write
215
+ * to disk once we have the final bundle
216
+ */
217
+ bundle = await buildRawWorker({
218
+ workerScriptPath,
219
+ outdir,
220
+ directory: buildOutputDirectory,
221
+ local: false,
222
+ sourcemap,
223
+ watch,
224
+ betaD1Shims: d1Databases,
225
+ });
226
+ } else {
227
+ try {
228
+ /**
229
+ * `buildFunctions` builds `/functions`, but doesn't give us the bundle
230
+ * we want to return, which includes the external dependencies (like wasm,
231
+ * binary, text). Let's output that build result to memory and only write
232
+ * to disk once we have the final bundle
233
+ */
234
+ bundle = await buildFunctions({
235
+ outdir,
236
+ outputConfigPath,
237
+ functionsDirectory: directory,
238
+ minify,
239
+ sourcemap,
240
+ fallbackService,
241
+ watch,
242
+ plugin,
243
+ buildOutputDirectory,
244
+ legacyNodeCompat,
245
+ nodejsCompat,
246
+ routesOutputPath,
247
+ local: false,
248
+ d1Databases,
249
+ });
250
+ } catch (e) {
251
+ if (e instanceof FunctionsNoRoutesError) {
252
+ throw new FatalError(
253
+ getFunctionsNoRoutesWarning(directory),
254
+ EXIT_CODE_FUNCTIONS_NO_ROUTES_ERROR
255
+ );
256
+ } else {
257
+ throw e;
258
+ }
259
+ }
260
+ }
261
+
262
+ if (outfile) {
263
+ const workerBundleContents = await createUploadWorkerBundleContents(
264
+ bundle as BundleResult
265
+ );
266
+
267
+ mkdirSync(dirname(outfile), { recursive: true });
268
+ writeFileSync(
269
+ outfile,
270
+ Buffer.from(await workerBundleContents.arrayBuffer())
271
+ );
272
+ }
238
273
  }
239
274
 
240
- if (experimentalWorkerBundle) {
241
- const workerBundleContents = await createUploadWorkerBundleContents(
242
- bundle as BundleResult
275
+ await metrics.sendMetricsEvent("build pages functions");
276
+ };
277
+
278
+ type WorkerBundleArgs = Omit<PagesBuildArgs, "nodeCompat"> & {
279
+ plugin: false;
280
+ buildOutputDirectory: string;
281
+ legacyNodeCompat: boolean;
282
+ nodejsCompat: boolean;
283
+
284
+ workerScriptPath: string;
285
+ };
286
+ type PluginArgs = Omit<
287
+ PagesBuildArgs,
288
+ "buildOutputDirectory" | "bindings" | "nodeCompat"
289
+ > & {
290
+ plugin: true;
291
+ outdir: string;
292
+ legacyNodeCompat: boolean;
293
+ nodejsCompat: boolean;
294
+ };
295
+
296
+ type ValidatedArgs = WorkerBundleArgs | PluginArgs;
297
+
298
+ const validateArgs = (args: PagesBuildArgs): ValidatedArgs => {
299
+ if (args.outdir && args.outfile) {
300
+ throw new FatalError(
301
+ "Cannot specify both an `--outdir` and an `--outfile`.",
302
+ 1
243
303
  );
304
+ }
244
305
 
245
- writeFileSync(
246
- outfile,
247
- Buffer.from(await workerBundleContents.arrayBuffer())
306
+ if (args.plugin) {
307
+ if (args.outfile) {
308
+ // Explicit old behavior. Encourage to migrate to `--outdir` instead.
309
+ logger.warn(
310
+ "Creating a Pages Plugin with `--outfile` is now deprecated. Please use `--outdir` instead."
311
+ );
312
+
313
+ args.outdir = dirname(resolvePath(args.outfile));
314
+ } else if (!args.outfile && !args.outdir) {
315
+ // Didn't specify `--outfile`, but didn't specify `--outdir` either. Implicit old behavior defaults. Encourage to migrate to `--outdir`.
316
+ args.outfile ??= "_worker.js";
317
+ args.outdir = ".";
318
+
319
+ logger.warn(
320
+ "Creating a Pages Plugin without `--outdir` is now deprecated. Please add an `--outdir` argument."
321
+ );
322
+ }
323
+
324
+ if (args.bindings) {
325
+ throw new FatalError(
326
+ "The `--bindings` flag cannot be used when creating a Pages Plugin with `--plugin`.",
327
+ 1
328
+ );
329
+ }
330
+
331
+ if (args.buildOutputDirectory) {
332
+ throw new FatalError(
333
+ "The `--build-output-directory` flag cannot be used when creating a Pages Plugin with `--plugin`.",
334
+ 1
335
+ );
336
+ }
337
+ } else {
338
+ if (!args.outdir) {
339
+ args.outfile ??= "_worker.bundle";
340
+ }
341
+
342
+ args.buildOutputDirectory ??= args.outfile ? dirname(args.outfile) : ".";
343
+ }
344
+
345
+ if (args.buildOutputDirectory) {
346
+ args.buildOutputDirectory = resolvePath(args.buildOutputDirectory);
347
+ }
348
+ if (args.outdir) {
349
+ args.outdir = resolvePath(args.outdir);
350
+ }
351
+ if (args.outfile) {
352
+ args.outfile = resolvePath(args.outfile);
353
+ }
354
+
355
+ const { nodeCompat: legacyNodeCompat, ...argsExceptNodeCompat } = args;
356
+ if (legacyNodeCompat) {
357
+ console.warn(
358
+ "Enabling Node.js compatibility mode for builtins and globals. This is experimental and has serious tradeoffs. Please see https://github.com/ionic-team/rollup-plugin-node-polyfills/ for more details."
359
+ );
360
+ }
361
+ const nodejsCompat = !!args.compatibilityFlags?.includes("nodejs_compat");
362
+ if (legacyNodeCompat && nodejsCompat) {
363
+ throw new Error(
364
+ "The `nodejs_compat` compatibility flag cannot be used in conjunction with the legacy `--node-compat` flag. If you want to use the Workers runtime Node.js compatibility features, please remove the `--node-compat` argument from your CLI command."
248
365
  );
249
366
  }
250
367
 
251
- await metrics.sendMetricsEvent("build pages functions");
368
+ let workerScriptPath: string | undefined;
369
+
370
+ if (args.buildOutputDirectory) {
371
+ const prospectiveWorkerScriptPath = resolvePath(
372
+ args.buildOutputDirectory,
373
+ "_worker.js"
374
+ );
375
+
376
+ const foundWorkerScript = existsSync(prospectiveWorkerScriptPath);
377
+
378
+ if (foundWorkerScript) {
379
+ workerScriptPath = prospectiveWorkerScriptPath;
380
+ } else if (!foundWorkerScript && !existsSync(args.directory)) {
381
+ throw new FatalError(
382
+ `Could not find anything to build.
383
+ We first looked inside the build output directory (${basename(
384
+ resolvePath(args.buildOutputDirectory)
385
+ )}), then looked for the Functions directory (${basename(
386
+ args.directory
387
+ )}) but couldn't find anything to build.
388
+ ➤ If you are trying to build _worker.js, please make sure you provide the [--build-output-directory] containing your static files.
389
+ ➤ If you are trying to build Pages Functions, please make sure [directory] points to the location of your Functions files.`,
390
+ EXIT_CODE_FUNCTIONS_NOTHING_TO_BUILD_ERROR
391
+ );
392
+ }
393
+ } else if (!existsSync(args.directory)) {
394
+ throw new FatalError(
395
+ `Could not find anything to build.
396
+ We looked for the Functions directory (${basename(
397
+ args.directory
398
+ )}) but couldn't find anything to build.
399
+ ➤ Please make sure [directory] points to the location of your Functions files.`,
400
+ EXIT_CODE_FUNCTIONS_NOTHING_TO_BUILD_ERROR
401
+ );
402
+ }
403
+
404
+ return {
405
+ ...argsExceptNodeCompat,
406
+ workerScriptPath,
407
+ nodejsCompat,
408
+ legacyNodeCompat,
409
+ } as ValidatedArgs;
252
410
  };
@@ -1,6 +1,7 @@
1
1
  import { writeFileSync } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join, resolve } from "node:path";
4
+ import { FatalError } from "../errors";
4
5
  import { toUrlPath } from "../paths";
5
6
  import { FunctionsNoRoutesError } from "./errors";
6
7
  import { buildPlugin } from "./functions/buildPlugin";
@@ -20,6 +21,7 @@ import type { Config } from "./functions/routes";
20
21
 
21
22
  export async function buildFunctions({
22
23
  outfile,
24
+ outdir,
23
25
  outputConfigPath,
24
26
  functionsDirectory,
25
27
  minify = false,
@@ -34,10 +36,11 @@ export async function buildFunctions({
34
36
  nodejsCompat,
35
37
  local,
36
38
  d1Databases,
37
- experimentalWorkerBundle = false,
38
39
  }: Partial<
39
40
  Pick<
40
41
  PagesBuildArgs,
42
+ | "outfile"
43
+ | "outdir"
41
44
  | "outputConfigPath"
42
45
  | "minify"
43
46
  | "sourcemap"
@@ -49,11 +52,9 @@ export async function buildFunctions({
49
52
  > & {
50
53
  functionsDirectory: string;
51
54
  onEnd?: () => void;
52
- outfile: Required<PagesBuildArgs>["outfile"];
53
55
  routesOutputPath?: PagesBuildArgs["outputRoutesPath"];
54
56
  local: boolean;
55
57
  d1Databases?: string[];
56
- experimentalWorkerBundle?: boolean;
57
58
  legacyNodeCompat?: boolean;
58
59
  nodejsCompat?: boolean;
59
60
  }) {
@@ -97,9 +98,16 @@ export async function buildFunctions({
97
98
  let bundle: BundleResult;
98
99
 
99
100
  if (plugin) {
101
+ if (outdir === undefined) {
102
+ throw new FatalError(
103
+ "Must specify an output directory when building a Plugin.",
104
+ 1
105
+ );
106
+ }
107
+
100
108
  bundle = await buildPlugin({
101
109
  routesModule,
102
- outfile,
110
+ outdir,
103
111
  minify,
104
112
  sourcemap,
105
113
  watch,
@@ -107,12 +115,12 @@ export async function buildFunctions({
107
115
  functionsDirectory: absoluteFunctionsDirectory,
108
116
  local,
109
117
  betaD1Shims: d1Databases,
110
- onEnd,
111
118
  });
112
119
  } else {
113
120
  bundle = await buildWorker({
114
121
  routesModule,
115
122
  outfile,
123
+ outdir,
116
124
  minify,
117
125
  sourcemap,
118
126
  fallbackService,
@@ -124,7 +132,6 @@ export async function buildFunctions({
124
132
  buildOutputDirectory,
125
133
  legacyNodeCompat,
126
134
  nodejsCompat,
127
- experimentalWorkerBundle,
128
135
  });
129
136
  }
130
137
 
package/src/pages/dev.ts CHANGED
@@ -85,16 +85,9 @@ export function Options(yargs: CommonYargsArgv) {
85
85
  hidden: true,
86
86
  },
87
87
  "no-bundle": {
88
- type: "boolean",
89
- default: true,
90
- description: "Whether to run bundling on `_worker.js`",
91
- },
92
- "experimental-worker-bundle": {
93
88
  type: "boolean",
94
89
  default: false,
95
- hidden: true,
96
- description:
97
- "Whether to process non-JS module imports or not, such as wasm/text/binary, when we run bundling on `functions` or `_worker.js`",
90
+ description: "Whether to run bundling on `_worker.js`",
98
91
  },
99
92
  binding: {
100
93
  type: "array",
@@ -181,7 +174,6 @@ export const Handler = async ({
181
174
  proxy: requestedProxyPort,
182
175
  bundle,
183
176
  noBundle,
184
- experimentalWorkerBundle,
185
177
  scriptPath: singleWorkerScriptPath,
186
178
  binding: bindings = [],
187
179
  kv: kvs = [],
@@ -280,7 +272,7 @@ export const Handler = async ({
280
272
 
281
273
  // TODO: Here lies a known bug. If you specify both `--bundle` and `--no-bundle`, this behavior is undefined and you will get unexpected results.
282
274
  // There is no sane way to get the true value out of yargs, so here we are.
283
- const enableBundling = (bundle ?? !noBundle) || experimentalWorkerBundle;
275
+ const enableBundling = bundle ?? !noBundle;
284
276
  if (enableBundling) {
285
277
  // We want to actually run the `_worker.js` script through the bundler
286
278
  // So update the final path to the script that will be uploaded and
@@ -297,7 +289,6 @@ export const Handler = async ({
297
289
  sourcemap: true,
298
290
  watch: true,
299
291
  onEnd: () => scriptReadyResolve(),
300
- experimentalWorkerBundle,
301
292
  });
302
293
  } catch (e: unknown) {
303
294
  logger.warn("Failed to bundle _worker.js.", e);
@@ -306,7 +297,7 @@ export const Handler = async ({
306
297
  }
307
298
 
308
299
  await runBuild();
309
- watch([scriptPath], {
300
+ watch([workerScriptPath], {
310
301
  persistent: true,
311
302
  ignoreInitial: true,
312
303
  }).on("all", async () => {
@@ -343,7 +334,6 @@ export const Handler = async ({
343
334
  legacyNodeCompat,
344
335
  nodejsCompat,
345
336
  local: true,
346
- experimentalWorkerBundle,
347
337
  });
348
338
  await metrics.sendMetricsEvent("build pages functions");
349
339
  };
@@ -551,8 +541,7 @@ export const Handler = async ({
551
541
  persist,
552
542
  persistTo,
553
543
  inspect: undefined,
554
- logPrefix: "pages",
555
- logLevel: logLevel ?? "warn",
544
+ logLevel,
556
545
  experimental: {
557
546
  d1Databases: d1s.map((binding) => ({
558
547
  binding: binding.toString(),
@@ -9,6 +9,7 @@ import { RoutesValidationError } from "./functions/routes-validation";
9
9
  * Exit code for `pages functions build` when no routes are found.
10
10
  */
11
11
  export const EXIT_CODE_FUNCTIONS_NO_ROUTES_ERROR = 156;
12
+ export const EXIT_CODE_FUNCTIONS_NOTHING_TO_BUILD_ERROR = 157;
12
13
 
13
14
  /**
14
15
  * Pages error when no routes are found in the functions directory