wrangler 2.0.6 → 2.0.9
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/README.md +1 -1
- package/bin/wrangler.js +16 -4
- package/package.json +6 -4
- package/pages/functions/buildPlugin.ts +13 -0
- package/pages/functions/buildWorker.ts +13 -0
- package/src/__tests__/configuration.test.ts +132 -60
- package/src/__tests__/dev.test.tsx +168 -67
- package/src/__tests__/helpers/mock-dialogs.ts +41 -1
- package/src/__tests__/index.test.ts +25 -10
- package/src/__tests__/init.test.ts +252 -131
- package/src/__tests__/kv.test.ts +16 -16
- package/src/__tests__/package-manager.test.ts +154 -7
- package/src/__tests__/pages.test.ts +442 -38
- package/src/__tests__/parse.test.ts +5 -1
- package/src/__tests__/publish.test.ts +377 -84
- package/src/__tests__/secret.test.ts +4 -4
- package/src/__tests__/whoami.test.tsx +34 -0
- package/src/abort.d.ts +3 -0
- package/src/cfetch/index.ts +21 -4
- package/src/cfetch/internal.ts +20 -18
- package/src/config/config.ts +1 -1
- package/src/config/index.ts +162 -0
- package/src/config/validation.ts +77 -29
- package/src/create-worker-preview.ts +32 -22
- package/src/dev/dev.tsx +6 -16
- package/src/dev/remote.tsx +40 -16
- package/src/dialogs.tsx +48 -0
- package/src/durable.ts +102 -0
- package/src/index.tsx +291 -207
- package/src/inspect.ts +39 -0
- package/src/kv.ts +74 -25
- package/src/open-in-browser.ts +5 -12
- package/src/package-manager.ts +50 -3
- package/src/pages.tsx +218 -61
- package/src/parse.ts +21 -4
- package/src/proxy.ts +38 -22
- package/src/publish.ts +166 -108
- package/src/sites.tsx +8 -8
- package/src/user.tsx +12 -1
- package/src/whoami.tsx +3 -2
- package/src/worker.ts +2 -1
- package/src/zones.ts +73 -0
- package/templates/new-worker-scheduled.js +17 -0
- package/templates/new-worker-scheduled.ts +32 -0
- package/templates/new-worker.ts +16 -1
- package/wrangler-dist/cli.js +33066 -20052
package/src/pages.tsx
CHANGED
|
@@ -14,6 +14,7 @@ import SelectInput from "ink-select-input";
|
|
|
14
14
|
import Spinner from "ink-spinner";
|
|
15
15
|
import Table from "ink-table";
|
|
16
16
|
import { getType } from "mime";
|
|
17
|
+
import PQueue from "p-queue";
|
|
17
18
|
import prettyBytes from "pretty-bytes";
|
|
18
19
|
import React from "react";
|
|
19
20
|
import { format as timeagoFormat } from "timeago.js";
|
|
@@ -32,7 +33,11 @@ import openInBrowser from "./open-in-browser";
|
|
|
32
33
|
import { toUrlPath } from "./paths";
|
|
33
34
|
import { requireAuth } from "./user";
|
|
34
35
|
import type { Config } from "../pages/functions/routes";
|
|
35
|
-
import type {
|
|
36
|
+
import type {
|
|
37
|
+
Headers as MiniflareHeaders,
|
|
38
|
+
Request as MiniflareRequest,
|
|
39
|
+
fetch as miniflareFetch,
|
|
40
|
+
} from "@miniflare/core";
|
|
36
41
|
import type { BuildResult } from "esbuild";
|
|
37
42
|
import type { MiniflareOptions } from "miniflare";
|
|
38
43
|
import type { BuilderCallback, CommandModule } from "yargs";
|
|
@@ -68,12 +73,23 @@ export type Deployment = {
|
|
|
68
73
|
project_name: string;
|
|
69
74
|
};
|
|
70
75
|
|
|
76
|
+
export type UploadPayloadFile = {
|
|
77
|
+
key: string;
|
|
78
|
+
value: string;
|
|
79
|
+
metadata: { contentType: string };
|
|
80
|
+
base64: boolean;
|
|
81
|
+
};
|
|
82
|
+
|
|
71
83
|
interface PagesConfigCache {
|
|
72
84
|
account_id?: string;
|
|
73
85
|
project_name?: string;
|
|
74
86
|
}
|
|
75
87
|
|
|
76
88
|
const PAGES_CONFIG_CACHE_FILENAME = "pages.json";
|
|
89
|
+
const MAX_BUCKET_SIZE = 50 * 1024 * 1024;
|
|
90
|
+
const MAX_BUCKET_FILE_COUNT = 5000;
|
|
91
|
+
const BULK_UPLOAD_CONCURRENCY = 3;
|
|
92
|
+
const MAX_UPLOAD_ATTEMPTS = 5;
|
|
77
93
|
|
|
78
94
|
// Defer importing miniflare until we really need it. This takes ~0.5s
|
|
79
95
|
// and also modifies some `stream/web` and `undici` prototypes, so we
|
|
@@ -284,7 +300,7 @@ function generateRulesMatcher<T>(
|
|
|
284
300
|
T
|
|
285
301
|
][];
|
|
286
302
|
|
|
287
|
-
return ({ request }: { request:
|
|
303
|
+
return ({ request }: { request: MiniflareRequest }) => {
|
|
288
304
|
const { pathname, host } = new URL(request.url);
|
|
289
305
|
|
|
290
306
|
return compiledRules
|
|
@@ -357,7 +373,7 @@ function generateHeadersMatcher(headersFile: string) {
|
|
|
357
373
|
)
|
|
358
374
|
);
|
|
359
375
|
|
|
360
|
-
return (request:
|
|
376
|
+
return (request: MiniflareRequest) => {
|
|
361
377
|
const matches = rulesMatcher({
|
|
362
378
|
request,
|
|
363
379
|
});
|
|
@@ -406,7 +422,7 @@ function generateRedirectsMatcher(redirectsFile: string) {
|
|
|
406
422
|
})
|
|
407
423
|
);
|
|
408
424
|
|
|
409
|
-
return (request:
|
|
425
|
+
return (request: MiniflareRequest) => {
|
|
410
426
|
const match = rulesMatcher({
|
|
411
427
|
request,
|
|
412
428
|
})[0];
|
|
@@ -461,7 +477,9 @@ function hasFileExtension(pathname: string) {
|
|
|
461
477
|
return /\/.+\.[a-z0-9]+$/i.test(pathname);
|
|
462
478
|
}
|
|
463
479
|
|
|
464
|
-
async function generateAssetsFetch(
|
|
480
|
+
async function generateAssetsFetch(
|
|
481
|
+
directory: string
|
|
482
|
+
): Promise<typeof miniflareFetch> {
|
|
465
483
|
// Defer importing miniflare until we really need it
|
|
466
484
|
const { Headers, Request, Response } = await import("@miniflare/core");
|
|
467
485
|
|
|
@@ -510,12 +528,12 @@ async function generateAssetsFetch(directory: string): Promise<typeof fetch> {
|
|
|
510
528
|
return readFileSync(file);
|
|
511
529
|
};
|
|
512
530
|
|
|
513
|
-
const generateResponse = (request:
|
|
531
|
+
const generateResponse = (request: MiniflareRequest) => {
|
|
514
532
|
const url = new URL(request.url);
|
|
515
533
|
|
|
516
534
|
const deconstructedResponse: {
|
|
517
535
|
status: number;
|
|
518
|
-
headers:
|
|
536
|
+
headers: MiniflareHeaders;
|
|
519
537
|
body?: Buffer;
|
|
520
538
|
} = {
|
|
521
539
|
status: 200,
|
|
@@ -667,8 +685,12 @@ async function generateAssetsFetch(directory: string): Promise<typeof fetch> {
|
|
|
667
685
|
};
|
|
668
686
|
|
|
669
687
|
const attachHeaders = (
|
|
670
|
-
request:
|
|
671
|
-
deconstructedResponse: {
|
|
688
|
+
request: MiniflareRequest,
|
|
689
|
+
deconstructedResponse: {
|
|
690
|
+
status: number;
|
|
691
|
+
headers: MiniflareHeaders;
|
|
692
|
+
body?: Buffer;
|
|
693
|
+
}
|
|
672
694
|
) => {
|
|
673
695
|
const headers = deconstructedResponse.headers;
|
|
674
696
|
const newHeaders = new Headers({});
|
|
@@ -722,6 +744,7 @@ async function buildFunctions({
|
|
|
722
744
|
onEnd,
|
|
723
745
|
plugin = false,
|
|
724
746
|
buildOutputDirectory,
|
|
747
|
+
nodeCompat,
|
|
725
748
|
}: {
|
|
726
749
|
outfile: string;
|
|
727
750
|
outputConfigPath?: string;
|
|
@@ -733,12 +756,13 @@ async function buildFunctions({
|
|
|
733
756
|
onEnd?: () => void;
|
|
734
757
|
plugin?: boolean;
|
|
735
758
|
buildOutputDirectory?: string;
|
|
759
|
+
nodeCompat?: boolean;
|
|
736
760
|
}) {
|
|
737
761
|
RUNNING_BUILDERS.forEach(
|
|
738
762
|
(runningBuilder) => runningBuilder.stop && runningBuilder.stop()
|
|
739
763
|
);
|
|
740
764
|
|
|
741
|
-
const routesModule = join(tmpdir(),
|
|
765
|
+
const routesModule = join(tmpdir(), `./functionsRoutes-${Math.random()}.mjs`);
|
|
742
766
|
const baseURL = toUrlPath("/");
|
|
743
767
|
|
|
744
768
|
const config: Config = await generateConfigFromFileTree({
|
|
@@ -767,6 +791,7 @@ async function buildFunctions({
|
|
|
767
791
|
minify,
|
|
768
792
|
sourcemap,
|
|
769
793
|
watch,
|
|
794
|
+
nodeCompat,
|
|
770
795
|
onEnd,
|
|
771
796
|
})
|
|
772
797
|
);
|
|
@@ -781,6 +806,7 @@ async function buildFunctions({
|
|
|
781
806
|
watch,
|
|
782
807
|
onEnd,
|
|
783
808
|
buildOutputDirectory,
|
|
809
|
+
nodeCompat,
|
|
784
810
|
})
|
|
785
811
|
);
|
|
786
812
|
}
|
|
@@ -1001,7 +1027,7 @@ const createDeployment: CommandModule<
|
|
|
1001
1027
|
|
|
1002
1028
|
if (isGitDirty && !commitDirty) {
|
|
1003
1029
|
logger.warn(
|
|
1004
|
-
`Warning: Your working directory is a git repo and has uncommitted changes\nTo
|
|
1030
|
+
`Warning: Your working directory is a git repo and has uncommitted changes\nTo silence this warning, pass in --commit-dirty=true`
|
|
1005
1031
|
);
|
|
1006
1032
|
}
|
|
1007
1033
|
|
|
@@ -1013,7 +1039,7 @@ const createDeployment: CommandModule<
|
|
|
1013
1039
|
let builtFunctions: string | undefined = undefined;
|
|
1014
1040
|
const functionsDirectory = join(cwd(), "functions");
|
|
1015
1041
|
if (existsSync(functionsDirectory)) {
|
|
1016
|
-
const outfile = join(tmpdir(),
|
|
1042
|
+
const outfile = join(tmpdir(), `./functionsWorker-${Math.random()}.js`);
|
|
1017
1043
|
|
|
1018
1044
|
await new Promise((resolve) =>
|
|
1019
1045
|
buildFunctions({
|
|
@@ -1027,12 +1053,9 @@ const createDeployment: CommandModule<
|
|
|
1027
1053
|
builtFunctions = readFileSync(outfile, "utf-8");
|
|
1028
1054
|
}
|
|
1029
1055
|
|
|
1030
|
-
type
|
|
1031
|
-
content:
|
|
1032
|
-
|
|
1033
|
-
};
|
|
1034
|
-
|
|
1035
|
-
type Metadata = {
|
|
1056
|
+
type FileContainer = {
|
|
1057
|
+
content: string;
|
|
1058
|
+
contentType: string;
|
|
1036
1059
|
sizeInBytes: number;
|
|
1037
1060
|
hash: string;
|
|
1038
1061
|
};
|
|
@@ -1043,11 +1066,12 @@ const createDeployment: CommandModule<
|
|
|
1043
1066
|
"_headers",
|
|
1044
1067
|
".DS_Store",
|
|
1045
1068
|
"node_modules",
|
|
1069
|
+
".git",
|
|
1046
1070
|
];
|
|
1047
1071
|
|
|
1048
1072
|
const walk = async (
|
|
1049
1073
|
dir: string,
|
|
1050
|
-
fileMap: Map<string,
|
|
1074
|
+
fileMap: Map<string, FileContainer> = new Map(),
|
|
1051
1075
|
depth = 0
|
|
1052
1076
|
) => {
|
|
1053
1077
|
const files = await readdir(dir);
|
|
@@ -1081,8 +1105,6 @@ const createDeployment: CommandModule<
|
|
|
1081
1105
|
const base64Content = fileContent.toString("base64");
|
|
1082
1106
|
const extension = extname(basename(name)).substring(1);
|
|
1083
1107
|
|
|
1084
|
-
const content = base64Content + extension;
|
|
1085
|
-
|
|
1086
1108
|
if (filestat.size > 25 * 1024 * 1024) {
|
|
1087
1109
|
throw new Error(
|
|
1088
1110
|
`Error: Pages only supports files up to ${prettyBytes(
|
|
@@ -1092,11 +1114,12 @@ const createDeployment: CommandModule<
|
|
|
1092
1114
|
}
|
|
1093
1115
|
|
|
1094
1116
|
fileMap.set(name, {
|
|
1095
|
-
content:
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1117
|
+
content: base64Content,
|
|
1118
|
+
contentType: getType(name) || "application/octet-stream",
|
|
1119
|
+
sizeInBytes: filestat.size,
|
|
1120
|
+
hash: hash(base64Content + extension)
|
|
1121
|
+
.toString("hex")
|
|
1122
|
+
.slice(0, 32),
|
|
1100
1123
|
});
|
|
1101
1124
|
}
|
|
1102
1125
|
})
|
|
@@ -1107,51 +1130,150 @@ const createDeployment: CommandModule<
|
|
|
1107
1130
|
|
|
1108
1131
|
const fileMap = await walk(directory);
|
|
1109
1132
|
|
|
1110
|
-
|
|
1133
|
+
if (fileMap.size > 20000) {
|
|
1134
|
+
throw new FatalError(
|
|
1135
|
+
`Error: Pages only supports up to 20,000 files in a deployment. Ensure you have specified your build output directory correctly.`,
|
|
1136
|
+
1
|
|
1137
|
+
);
|
|
1138
|
+
}
|
|
1111
1139
|
|
|
1112
|
-
const files
|
|
1140
|
+
const files = [...fileMap.values()];
|
|
1113
1141
|
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1142
|
+
async function fetchJwt(): Promise<string> {
|
|
1143
|
+
return (
|
|
1144
|
+
await fetchResult<{ jwt: string }>(
|
|
1145
|
+
`/accounts/${accountId}/pages/projects/${projectName}/upload-token`
|
|
1146
|
+
)
|
|
1147
|
+
).jwt;
|
|
1118
1148
|
}
|
|
1119
1149
|
|
|
1120
|
-
let
|
|
1150
|
+
let jwt = await fetchJwt();
|
|
1151
|
+
|
|
1152
|
+
const start = Date.now();
|
|
1121
1153
|
|
|
1154
|
+
const missingHashes = await fetchResult<string[]>(
|
|
1155
|
+
`/pages/assets/check-missing`,
|
|
1156
|
+
{
|
|
1157
|
+
method: "POST",
|
|
1158
|
+
headers: {
|
|
1159
|
+
"Content-Type": "application/json",
|
|
1160
|
+
Authorization: `Bearer ${jwt}`,
|
|
1161
|
+
},
|
|
1162
|
+
body: JSON.stringify({
|
|
1163
|
+
hashes: files.map(({ hash }) => hash),
|
|
1164
|
+
}),
|
|
1165
|
+
}
|
|
1166
|
+
);
|
|
1167
|
+
|
|
1168
|
+
const sortedFiles = files
|
|
1169
|
+
.filter((file) => missingHashes.includes(file.hash))
|
|
1170
|
+
.sort((a, b) => b.sizeInBytes - a.sizeInBytes);
|
|
1171
|
+
|
|
1172
|
+
// Start with a few buckets so small projects still get
|
|
1173
|
+
// the benefit of multiple upload streams
|
|
1174
|
+
const buckets: {
|
|
1175
|
+
files: FileContainer[];
|
|
1176
|
+
remainingSize: number;
|
|
1177
|
+
}[] = new Array(BULK_UPLOAD_CONCURRENCY).fill(null).map(() => ({
|
|
1178
|
+
files: [],
|
|
1179
|
+
remainingSize: MAX_BUCKET_SIZE,
|
|
1180
|
+
}));
|
|
1181
|
+
|
|
1182
|
+
let bucketOffset = 0;
|
|
1183
|
+
for (const file of sortedFiles) {
|
|
1184
|
+
let inserted = false;
|
|
1185
|
+
|
|
1186
|
+
for (let i = 0; i < buckets.length; i++) {
|
|
1187
|
+
// Start at a different bucket for each new file
|
|
1188
|
+
const bucket = buckets[(i + bucketOffset) % buckets.length];
|
|
1189
|
+
if (
|
|
1190
|
+
bucket.remainingSize >= file.sizeInBytes &&
|
|
1191
|
+
bucket.files.length < MAX_BUCKET_FILE_COUNT
|
|
1192
|
+
) {
|
|
1193
|
+
bucket.files.push(file);
|
|
1194
|
+
bucket.remainingSize -= file.sizeInBytes;
|
|
1195
|
+
inserted = true;
|
|
1196
|
+
break;
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
if (!inserted) {
|
|
1201
|
+
buckets.push({
|
|
1202
|
+
files: [file],
|
|
1203
|
+
remainingSize: MAX_BUCKET_SIZE - file.sizeInBytes,
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1206
|
+
bucketOffset++;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
let counter = fileMap.size - sortedFiles.length;
|
|
1122
1210
|
const { rerender, unmount } = render(
|
|
1123
1211
|
<Progress done={counter} total={fileMap.size} />
|
|
1124
1212
|
);
|
|
1125
1213
|
|
|
1126
|
-
|
|
1127
|
-
const form = new FormData();
|
|
1128
|
-
form.append(
|
|
1129
|
-
"file",
|
|
1130
|
-
new File([new Uint8Array(file.content.buffer)], name)
|
|
1131
|
-
);
|
|
1214
|
+
const queue = new PQueue({ concurrency: BULK_UPLOAD_CONCURRENCY });
|
|
1132
1215
|
|
|
1133
|
-
|
|
1216
|
+
for (const bucket of buckets) {
|
|
1217
|
+
// Don't upload empty buckets (can happen for tiny projects)
|
|
1218
|
+
if (bucket.files.length === 0) continue;
|
|
1134
1219
|
|
|
1135
|
-
const
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1220
|
+
const payload: UploadPayloadFile[] = bucket.files.map((file) => ({
|
|
1221
|
+
key: file.hash,
|
|
1222
|
+
value: file.content,
|
|
1223
|
+
metadata: {
|
|
1224
|
+
contentType: file.contentType,
|
|
1225
|
+
},
|
|
1226
|
+
base64: true,
|
|
1227
|
+
}));
|
|
1228
|
+
|
|
1229
|
+
let attempts = 0;
|
|
1230
|
+
const doUpload = async (): Promise<void> => {
|
|
1231
|
+
try {
|
|
1232
|
+
return await fetchResult(`/pages/assets/upload`, {
|
|
1233
|
+
method: "POST",
|
|
1234
|
+
headers: {
|
|
1235
|
+
"Content-Type": "application/json",
|
|
1236
|
+
Authorization: `Bearer ${jwt}`,
|
|
1237
|
+
},
|
|
1238
|
+
body: JSON.stringify(payload),
|
|
1239
|
+
});
|
|
1240
|
+
} catch (e) {
|
|
1241
|
+
if (attempts < MAX_UPLOAD_ATTEMPTS) {
|
|
1242
|
+
// Linear backoff, 0 second first time, then 1 second etc.
|
|
1243
|
+
await new Promise((resolve) =>
|
|
1244
|
+
setTimeout(resolve, attempts++ * 1000)
|
|
1245
|
+
);
|
|
1246
|
+
|
|
1247
|
+
if ((e as { code: number }).code === 8000013) {
|
|
1248
|
+
// Looks like the JWT expired, fetch another one
|
|
1249
|
+
jwt = await fetchJwt();
|
|
1250
|
+
}
|
|
1251
|
+
return doUpload();
|
|
1252
|
+
} else {
|
|
1253
|
+
throw e;
|
|
1254
|
+
}
|
|
1148
1255
|
}
|
|
1149
|
-
}
|
|
1256
|
+
};
|
|
1150
1257
|
|
|
1151
|
-
|
|
1152
|
-
|
|
1258
|
+
queue.add(() =>
|
|
1259
|
+
doUpload().then(
|
|
1260
|
+
() => {
|
|
1261
|
+
counter += bucket.files.length;
|
|
1262
|
+
rerender(<Progress done={counter} total={fileMap.size} />);
|
|
1263
|
+
},
|
|
1264
|
+
(error) => {
|
|
1265
|
+
return Promise.reject(
|
|
1266
|
+
new FatalError(
|
|
1267
|
+
"Failed to upload files. Please try again.",
|
|
1268
|
+
error.code || 1
|
|
1269
|
+
)
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
)
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1153
1275
|
|
|
1154
|
-
await
|
|
1276
|
+
await queue.onIdle();
|
|
1155
1277
|
|
|
1156
1278
|
unmount();
|
|
1157
1279
|
|
|
@@ -1169,7 +1291,7 @@ const createDeployment: CommandModule<
|
|
|
1169
1291
|
Object.fromEntries(
|
|
1170
1292
|
[...fileMap.entries()].map(([fileName, file]) => [
|
|
1171
1293
|
`/${fileName}`,
|
|
1172
|
-
file.
|
|
1294
|
+
file.hash,
|
|
1173
1295
|
])
|
|
1174
1296
|
)
|
|
1175
1297
|
)
|
|
@@ -1299,6 +1421,12 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
|
1299
1421
|
default: false,
|
|
1300
1422
|
description: "Auto reload HTML pages when change is detected",
|
|
1301
1423
|
},
|
|
1424
|
+
"node-compat": {
|
|
1425
|
+
describe: "Enable node.js compatibility",
|
|
1426
|
+
default: false,
|
|
1427
|
+
type: "boolean",
|
|
1428
|
+
hidden: true,
|
|
1429
|
+
},
|
|
1302
1430
|
// TODO: Miniflare user options
|
|
1303
1431
|
})
|
|
1304
1432
|
.epilogue(pagesBetaWarning);
|
|
@@ -1313,6 +1441,7 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
|
1313
1441
|
kv: kvs = [],
|
|
1314
1442
|
do: durableObjects = [],
|
|
1315
1443
|
"live-reload": liveReload,
|
|
1444
|
+
"node-compat": nodeCompat,
|
|
1316
1445
|
_: [_pages, _dev, ...remaining],
|
|
1317
1446
|
}) => {
|
|
1318
1447
|
// Beta message for `wrangler pages <commands>` usage
|
|
@@ -1346,7 +1475,16 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
|
1346
1475
|
);
|
|
1347
1476
|
|
|
1348
1477
|
if (usingFunctions) {
|
|
1349
|
-
const outfile = join(
|
|
1478
|
+
const outfile = join(
|
|
1479
|
+
tmpdir(),
|
|
1480
|
+
`./functionsWorker-${Math.random()}.js`
|
|
1481
|
+
);
|
|
1482
|
+
|
|
1483
|
+
if (nodeCompat) {
|
|
1484
|
+
console.warn(
|
|
1485
|
+
"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."
|
|
1486
|
+
);
|
|
1487
|
+
}
|
|
1350
1488
|
|
|
1351
1489
|
logger.log(`Compiling worker to "${outfile}"...`);
|
|
1352
1490
|
|
|
@@ -1358,6 +1496,7 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
|
1358
1496
|
watch: true,
|
|
1359
1497
|
onEnd: () => scriptReadyResolve(),
|
|
1360
1498
|
buildOutputDirectory: directory,
|
|
1499
|
+
nodeCompat,
|
|
1361
1500
|
});
|
|
1362
1501
|
} catch {}
|
|
1363
1502
|
|
|
@@ -1372,6 +1511,7 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
|
1372
1511
|
watch: true,
|
|
1373
1512
|
onEnd: () => scriptReadyResolve(),
|
|
1374
1513
|
buildOutputDirectory: directory,
|
|
1514
|
+
nodeCompat,
|
|
1375
1515
|
});
|
|
1376
1516
|
});
|
|
1377
1517
|
|
|
@@ -1394,6 +1534,9 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
|
1394
1534
|
} else {
|
|
1395
1535
|
logger.log("No functions. Shimming...");
|
|
1396
1536
|
miniflareArgs = {
|
|
1537
|
+
// cfFetch sets the `cf` object that a function could expect
|
|
1538
|
+
// If there are no functions, there's no reason to set this up (and not make that network call)
|
|
1539
|
+
cfFetch: false,
|
|
1397
1540
|
// TODO: The fact that these request/response hacks are necessary is ridiculous.
|
|
1398
1541
|
// We need to eliminate them from env.ASSETS.fetch (not sure if just local or prod as well)
|
|
1399
1542
|
script: `
|
|
@@ -1455,7 +1598,7 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
|
1455
1598
|
|
|
1456
1599
|
// env.ASSETS.fetch
|
|
1457
1600
|
serviceBindings: {
|
|
1458
|
-
async ASSETS(request:
|
|
1601
|
+
async ASSETS(request: MiniflareRequest) {
|
|
1459
1602
|
if (proxyPort) {
|
|
1460
1603
|
try {
|
|
1461
1604
|
const url = new URL(request.url);
|
|
@@ -1579,6 +1722,12 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
|
1579
1722
|
type: "string",
|
|
1580
1723
|
description: "The directory to output static assets to",
|
|
1581
1724
|
},
|
|
1725
|
+
"node-compat": {
|
|
1726
|
+
describe: "Enable node.js compatibility",
|
|
1727
|
+
default: false,
|
|
1728
|
+
type: "boolean",
|
|
1729
|
+
hidden: true,
|
|
1730
|
+
},
|
|
1582
1731
|
})
|
|
1583
1732
|
.epilogue(pagesBetaWarning),
|
|
1584
1733
|
async ({
|
|
@@ -1591,12 +1740,19 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
|
1591
1740
|
watch,
|
|
1592
1741
|
plugin,
|
|
1593
1742
|
"build-output-directory": buildOutputDirectory,
|
|
1743
|
+
"node-compat": nodeCompat,
|
|
1594
1744
|
}) => {
|
|
1595
1745
|
if (!isInPagesCI) {
|
|
1596
1746
|
// Beta message for `wrangler pages <commands>` usage
|
|
1597
1747
|
logger.log(pagesBetaWarning);
|
|
1598
1748
|
}
|
|
1599
1749
|
|
|
1750
|
+
if (nodeCompat) {
|
|
1751
|
+
console.warn(
|
|
1752
|
+
"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."
|
|
1753
|
+
);
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1600
1756
|
buildOutputDirectory ??= dirname(outfile);
|
|
1601
1757
|
|
|
1602
1758
|
await buildFunctions({
|
|
@@ -1609,6 +1765,7 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
|
1609
1765
|
watch,
|
|
1610
1766
|
plugin,
|
|
1611
1767
|
buildOutputDirectory,
|
|
1768
|
+
nodeCompat,
|
|
1612
1769
|
});
|
|
1613
1770
|
}
|
|
1614
1771
|
)
|
|
@@ -1833,7 +1990,7 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
|
1833
1990
|
} as CommandModule);
|
|
1834
1991
|
};
|
|
1835
1992
|
|
|
1836
|
-
const invalidAssetsFetch: typeof
|
|
1993
|
+
const invalidAssetsFetch: typeof miniflareFetch = () => {
|
|
1837
1994
|
throw new Error(
|
|
1838
1995
|
"Trying to fetch assets directly when there is no `directory` option specified, and not in `local` mode."
|
|
1839
1996
|
);
|
package/src/parse.ts
CHANGED
|
@@ -62,8 +62,6 @@ export class ParseError extends Error implements Message {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
66
|
-
|
|
67
65
|
const TOML_ERROR_NAME = "TomlError";
|
|
68
66
|
const TOML_ERROR_SUFFIX = " at row ";
|
|
69
67
|
|
|
@@ -78,7 +76,7 @@ type TomlError = Error & {
|
|
|
78
76
|
export function parseTOML(input: string, file?: string): TOML.JsonMap | never {
|
|
79
77
|
try {
|
|
80
78
|
// Normalize CRLF to LF to avoid hitting https://github.com/iarna/iarna-toml/issues/33.
|
|
81
|
-
const normalizedInput = input.replace(/\r\n
|
|
79
|
+
const normalizedInput = input.replace(/\r\n/g, "\n");
|
|
82
80
|
return TOML.parse(normalizedInput);
|
|
83
81
|
} catch (err) {
|
|
84
82
|
const { name, message, line, col } = err as TomlError;
|
|
@@ -100,10 +98,29 @@ export function parseTOML(input: string, file?: string): TOML.JsonMap | never {
|
|
|
100
98
|
|
|
101
99
|
const JSON_ERROR_SUFFIX = " in JSON at position ";
|
|
102
100
|
|
|
101
|
+
/**
|
|
102
|
+
* A minimal type describing a package.json file.
|
|
103
|
+
*/
|
|
104
|
+
export type PackageJSON = {
|
|
105
|
+
devDependencies?: Record<string, unknown>;
|
|
106
|
+
dependencies?: Record<string, unknown>;
|
|
107
|
+
scripts?: Record<string, unknown>;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* A typed version of `parseJSON()`.
|
|
112
|
+
*/
|
|
113
|
+
export function parsePackageJSON<T extends PackageJSON = PackageJSON>(
|
|
114
|
+
input: string,
|
|
115
|
+
file?: string
|
|
116
|
+
): T {
|
|
117
|
+
return parseJSON<T>(input, file);
|
|
118
|
+
}
|
|
119
|
+
|
|
103
120
|
/**
|
|
104
121
|
* A wrapper around `JSON.parse` that throws a `ParseError`.
|
|
105
122
|
*/
|
|
106
|
-
export function parseJSON(input: string, file?: string):
|
|
123
|
+
export function parseJSON<T>(input: string, file?: string): T {
|
|
107
124
|
try {
|
|
108
125
|
return JSON.parse(input);
|
|
109
126
|
} catch (err) {
|