wrangler 0.0.0-e2a26a0 → 0.0.0-e3a458e
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/package.json +24 -11
- package/pages/functions/filepath-routing.test.ts +212 -36
- package/pages/functions/filepath-routing.ts +69 -119
- package/pages/functions/routes.ts +8 -17
- package/pages/functions/template-worker.ts +3 -9
- package/src/__tests__/configuration.test.ts +2598 -0
- package/src/__tests__/dev.test.tsx +437 -63
- package/src/__tests__/dev2.test.tsx +154 -0
- package/src/__tests__/guess-worker-format.test.ts +58 -0
- package/src/__tests__/helpers/faye-websocket.d.ts +6 -0
- package/src/__tests__/helpers/mock-account-id.ts +26 -8
- package/src/__tests__/helpers/mock-bin.ts +4 -1
- package/src/__tests__/helpers/mock-cfetch.ts +5 -5
- package/src/__tests__/helpers/mock-console.ts +21 -7
- package/src/__tests__/helpers/mock-kv.ts +9 -16
- package/src/__tests__/helpers/mock-stdin.ts +103 -0
- package/src/__tests__/helpers/mock-web-socket.ts +29 -0
- package/src/__tests__/helpers/run-in-tmp.ts +3 -0
- package/src/__tests__/helpers/run-wrangler.ts +5 -3
- package/src/__tests__/helpers/write-wrangler-toml.ts +17 -0
- package/src/__tests__/https-options.test.ts +127 -0
- package/src/__tests__/index.test.ts +468 -20
- package/src/__tests__/jest.setup.ts +37 -5
- package/src/__tests__/kv.test.ts +426 -183
- package/src/__tests__/logout.test.ts +15 -13
- package/src/__tests__/package-manager.test.ts +2 -2
- package/src/__tests__/pages.test.ts +44 -0
- package/src/__tests__/parse.test.ts +322 -0
- package/src/__tests__/publish.test.ts +1733 -344
- package/src/__tests__/r2.test.ts +198 -0
- package/src/__tests__/route.test.ts +45 -0
- package/src/__tests__/secret.test.ts +301 -86
- package/src/__tests__/sentry.test.ts +146 -0
- package/src/__tests__/tail.test.ts +564 -0
- package/src/__tests__/whoami.test.tsx +21 -7
- package/src/bundle.ts +142 -0
- package/src/cfetch/index.ts +8 -6
- package/src/cfetch/internal.ts +60 -22
- package/src/cli.ts +10 -0
- package/src/config/README.md +107 -0
- package/src/config/config.ts +279 -0
- package/src/config/diagnostics.ts +80 -0
- package/src/config/environment.ts +305 -0
- package/src/config/index.ts +52 -0
- package/src/config/validation-helpers.ts +468 -0
- package/src/config/validation.ts +1057 -0
- package/src/{api/preview.ts → create-worker-preview.ts} +59 -21
- package/src/create-worker-upload-form.ts +217 -0
- package/src/dev/dev.tsx +362 -0
- package/src/dev/local.tsx +247 -0
- package/src/dev/remote.tsx +203 -0
- package/src/dev/use-esbuild.ts +100 -0
- package/src/entry.ts +159 -0
- package/src/environment-variables.ts +33 -0
- package/src/https-options.ts +122 -0
- package/src/index.tsx +1030 -766
- package/src/inspect.ts +25 -4
- package/src/{kv.tsx → kv.ts} +110 -55
- package/src/module-collection.ts +212 -22
- package/src/open-in-browser.ts +25 -0
- package/src/package-manager.ts +21 -15
- package/src/pages.tsx +10 -11
- package/src/parse.ts +183 -0
- package/src/proxy.ts +115 -45
- package/src/publish.ts +273 -329
- package/src/r2.ts +50 -0
- package/src/reporting.ts +131 -0
- package/src/selfsigned.d.ts +29 -0
- package/src/sites.tsx +66 -33
- package/src/tail/filters.ts +279 -0
- package/src/tail/index.ts +299 -0
- package/src/tail/printing.ts +62 -0
- package/src/user.tsx +223 -124
- package/src/{api/worker.ts → worker.ts} +44 -36
- package/templates/new-worker.js +1 -1
- package/templates/new-worker.ts +1 -1
- package/templates/tsconfig.json +105 -0
- package/wrangler-dist/cli.js +129900 -113128
- package/wrangler-dist/cli.js.map +3 -3
- package/src/__tests__/helpers/mock-user.ts +0 -27
- package/src/api/form_data.ts +0 -134
- package/src/config.ts +0 -641
- package/src/dev.tsx +0 -834
- package/src/tail.tsx +0 -73
package/src/inspect.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { URL } from "node:url";
|
|
|
5
5
|
import { useEffect, useRef, useState } from "react";
|
|
6
6
|
import WebSocket, { WebSocketServer } from "ws";
|
|
7
7
|
import { version } from "../package.json";
|
|
8
|
+
import { waitForPortToBeAvailable } from "./proxy";
|
|
8
9
|
import type Protocol from "devtools-protocol";
|
|
9
10
|
import type { IncomingMessage, Server, ServerResponse } from "node:http";
|
|
10
11
|
import type { MessageEvent } from "ws";
|
|
@@ -153,7 +154,14 @@ export default function useInspector(props: InspectorProps) {
|
|
|
153
154
|
* of the component lifecycle. Convenient.
|
|
154
155
|
*/
|
|
155
156
|
useEffect(() => {
|
|
156
|
-
|
|
157
|
+
async function startInspectorProxy() {
|
|
158
|
+
await waitForPortToBeAvailable(props.port, {
|
|
159
|
+
retryPeriod: 200,
|
|
160
|
+
timeout: 2000,
|
|
161
|
+
});
|
|
162
|
+
server.listen(props.port);
|
|
163
|
+
}
|
|
164
|
+
startInspectorProxy().catch((err) => console.error(err));
|
|
157
165
|
return () => {
|
|
158
166
|
server.close();
|
|
159
167
|
// Also disconnect any open websockets/devtools connections
|
|
@@ -367,7 +375,10 @@ export default function useInspector(props: InspectorProps) {
|
|
|
367
375
|
);
|
|
368
376
|
remoteWebSocket.send(event.data);
|
|
369
377
|
} catch (e) {
|
|
370
|
-
if (
|
|
378
|
+
if (
|
|
379
|
+
(e as Error).message !==
|
|
380
|
+
"WebSocket is not open: readyState 0 (CONNECTING)"
|
|
381
|
+
) {
|
|
371
382
|
/**
|
|
372
383
|
* ^ this just means we haven't opened a websocket yet
|
|
373
384
|
* usually happens until there's at least one request
|
|
@@ -587,8 +598,18 @@ function logConsoleMessage(evt: Protocol.Runtime.ConsoleAPICalledEvent): void {
|
|
|
587
598
|
const method = mapConsoleAPIMessageTypeToConsoleMethod[evt.type];
|
|
588
599
|
|
|
589
600
|
if (method in console) {
|
|
590
|
-
|
|
591
|
-
|
|
601
|
+
switch (method) {
|
|
602
|
+
case "dir":
|
|
603
|
+
console.dir(args);
|
|
604
|
+
break;
|
|
605
|
+
case "table":
|
|
606
|
+
console.table(args);
|
|
607
|
+
break;
|
|
608
|
+
default:
|
|
609
|
+
// eslint-disable-next-line prefer-spread
|
|
610
|
+
console[method].apply(console, args);
|
|
611
|
+
break;
|
|
612
|
+
}
|
|
592
613
|
} else {
|
|
593
614
|
console.warn(`Unsupported console method: ${method}`);
|
|
594
615
|
console.log("console event:", evt);
|
package/src/{kv.tsx → kv.ts}
RENAMED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { URLSearchParams } from "node:url";
|
|
2
2
|
import { fetchListResult, fetchResult, fetchKVGetValue } from "./cfetch";
|
|
3
|
-
import type { Config } from "./config";
|
|
3
|
+
import type { Config, Environment } from "./config";
|
|
4
|
+
|
|
5
|
+
/** The largest number of kv items we can pass to the API in a single request. */
|
|
6
|
+
const API_MAX = 10000;
|
|
7
|
+
// The const below are halved from the API's true capacity to help avoid
|
|
8
|
+
// hammering it with large requests.
|
|
9
|
+
const BATCH_KEY_MAX = API_MAX / 2;
|
|
4
10
|
|
|
5
11
|
type KvArgs = {
|
|
6
12
|
binding?: string;
|
|
7
13
|
"namespace-id"?: string;
|
|
8
14
|
env?: string;
|
|
9
15
|
preview?: boolean;
|
|
10
|
-
config?: Config;
|
|
11
16
|
};
|
|
12
17
|
|
|
13
18
|
/**
|
|
@@ -91,26 +96,64 @@ export async function listNamespaceKeys(
|
|
|
91
96
|
);
|
|
92
97
|
}
|
|
93
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Information about a key-value pair, including its "metadata" fields.
|
|
101
|
+
*/
|
|
102
|
+
export interface KeyValue {
|
|
103
|
+
key: string;
|
|
104
|
+
value: string;
|
|
105
|
+
expiration?: number;
|
|
106
|
+
expiration_ttl?: number;
|
|
107
|
+
metadata?: object;
|
|
108
|
+
base64?: boolean;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const KeyValueKeys = new Set([
|
|
112
|
+
"key",
|
|
113
|
+
"value",
|
|
114
|
+
"expiration",
|
|
115
|
+
"expiration_ttl",
|
|
116
|
+
"metadata",
|
|
117
|
+
"base64",
|
|
118
|
+
]);
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Is the given object a valid `KeyValue` type?
|
|
122
|
+
*/
|
|
123
|
+
export function isKeyValue(keyValue: object): keyValue is KeyValue {
|
|
124
|
+
const props = Object.keys(keyValue);
|
|
125
|
+
if (!props.includes("key") || !props.includes("value")) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get all the properties on the `keyValue` that are not expected.
|
|
133
|
+
*/
|
|
134
|
+
export function unexpectedKeyValueProps(keyValue: KeyValue): string[] {
|
|
135
|
+
const props = Object.keys(keyValue);
|
|
136
|
+
return props.filter((prop) => !KeyValueKeys.has(prop));
|
|
137
|
+
}
|
|
138
|
+
|
|
94
139
|
export async function putKeyValue(
|
|
95
140
|
accountId: string,
|
|
96
141
|
namespaceId: string,
|
|
97
|
-
|
|
98
|
-
value: string,
|
|
99
|
-
args?: { expiration?: number; expiration_ttl?: number }
|
|
142
|
+
keyValue: KeyValue
|
|
100
143
|
) {
|
|
101
144
|
let searchParams: URLSearchParams | undefined;
|
|
102
|
-
if (
|
|
145
|
+
if (keyValue.expiration || keyValue.expiration_ttl) {
|
|
103
146
|
searchParams = new URLSearchParams();
|
|
104
|
-
if (
|
|
105
|
-
searchParams.set("expiration", `${
|
|
147
|
+
if (keyValue.expiration) {
|
|
148
|
+
searchParams.set("expiration", `${keyValue.expiration}`);
|
|
106
149
|
}
|
|
107
|
-
if (
|
|
108
|
-
searchParams.set("expiration_ttl", `${
|
|
150
|
+
if (keyValue.expiration_ttl) {
|
|
151
|
+
searchParams.set("expiration_ttl", `${keyValue.expiration_ttl}`);
|
|
109
152
|
}
|
|
110
153
|
}
|
|
111
154
|
return await fetchResult(
|
|
112
|
-
`/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/values/${key}`,
|
|
113
|
-
{ method: "PUT", body: value },
|
|
155
|
+
`/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/values/${keyValue.key}`,
|
|
156
|
+
{ method: "PUT", body: keyValue.value },
|
|
114
157
|
searchParams
|
|
115
158
|
);
|
|
116
159
|
}
|
|
@@ -126,40 +169,57 @@ export async function getKeyValue(
|
|
|
126
169
|
export async function putBulkKeyValue(
|
|
127
170
|
accountId: string,
|
|
128
171
|
namespaceId: string,
|
|
129
|
-
|
|
172
|
+
keyValues: KeyValue[],
|
|
173
|
+
progressCallback: (index: number, total: number) => void
|
|
130
174
|
) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
method: "PUT",
|
|
135
|
-
body: keyvalueStr,
|
|
136
|
-
headers: { "Content-Type": "application/json" },
|
|
175
|
+
for (let index = 0; index < keyValues.length; index += BATCH_KEY_MAX) {
|
|
176
|
+
if (progressCallback && keyValues.length > BATCH_KEY_MAX) {
|
|
177
|
+
progressCallback(index, keyValues.length);
|
|
137
178
|
}
|
|
138
|
-
|
|
179
|
+
|
|
180
|
+
await fetchResult(
|
|
181
|
+
`/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/bulk`,
|
|
182
|
+
{
|
|
183
|
+
method: "PUT",
|
|
184
|
+
body: JSON.stringify(keyValues.slice(index, index + BATCH_KEY_MAX)),
|
|
185
|
+
headers: { "Content-Type": "application/json" },
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
if (progressCallback && keyValues.length > BATCH_KEY_MAX) {
|
|
190
|
+
progressCallback(keyValues.length, keyValues.length);
|
|
191
|
+
}
|
|
139
192
|
}
|
|
140
193
|
|
|
141
194
|
export async function deleteBulkKeyValue(
|
|
142
195
|
accountId: string,
|
|
143
196
|
namespaceId: string,
|
|
144
|
-
|
|
197
|
+
keys: string[],
|
|
198
|
+
progressCallback: (index: number, total: number) => void
|
|
145
199
|
) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
method: "DELETE",
|
|
150
|
-
body: keyStr,
|
|
151
|
-
headers: { "Content-Type": "application/json" },
|
|
200
|
+
for (let index = 0; index < keys.length; index += BATCH_KEY_MAX) {
|
|
201
|
+
if (progressCallback && keys.length > BATCH_KEY_MAX) {
|
|
202
|
+
progressCallback(index, keys.length);
|
|
152
203
|
}
|
|
153
|
-
|
|
204
|
+
|
|
205
|
+
await fetchResult(
|
|
206
|
+
`/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/bulk`,
|
|
207
|
+
{
|
|
208
|
+
method: "DELETE",
|
|
209
|
+
body: JSON.stringify(keys.slice(index, index + BATCH_KEY_MAX)),
|
|
210
|
+
headers: { "Content-Type": "application/json" },
|
|
211
|
+
}
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
if (progressCallback && keys.length > BATCH_KEY_MAX) {
|
|
215
|
+
progressCallback(keys.length, keys.length);
|
|
216
|
+
}
|
|
154
217
|
}
|
|
155
218
|
|
|
156
|
-
export function getNamespaceId(
|
|
157
|
-
preview,
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
"namespace-id": namespaceId,
|
|
161
|
-
env,
|
|
162
|
-
}: KvArgs): string {
|
|
219
|
+
export function getNamespaceId(
|
|
220
|
+
{ preview, binding, "namespace-id": namespaceId, env }: KvArgs,
|
|
221
|
+
configOrEnv: Config | Environment | undefined
|
|
222
|
+
): string {
|
|
163
223
|
// nice
|
|
164
224
|
if (namespaceId) {
|
|
165
225
|
return namespaceId;
|
|
@@ -167,13 +227,13 @@ export function getNamespaceId({
|
|
|
167
227
|
|
|
168
228
|
// begin pre-flight checks
|
|
169
229
|
|
|
170
|
-
// `--binding` is only valid if there's a wrangler configuration
|
|
171
|
-
if (binding && !
|
|
230
|
+
// `--binding` is only valid if there's a wrangler configuration.
|
|
231
|
+
if (binding && !configOrEnv) {
|
|
172
232
|
throw new Error("--binding specified, but no config file was found.");
|
|
173
233
|
}
|
|
174
234
|
|
|
175
235
|
// there's no config. abort here
|
|
176
|
-
if (!
|
|
236
|
+
if (!configOrEnv) {
|
|
177
237
|
throw new Error(
|
|
178
238
|
"Failed to find a config file.\n" +
|
|
179
239
|
"Either use --namespace-id to upload directly or create a configuration file with a binding."
|
|
@@ -182,36 +242,31 @@ export function getNamespaceId({
|
|
|
182
242
|
|
|
183
243
|
// they want to use an environment, actually
|
|
184
244
|
if (env) {
|
|
185
|
-
if (!
|
|
245
|
+
if (!("env" in configOrEnv) || !configOrEnv.env[env]) {
|
|
186
246
|
throw new Error(
|
|
187
247
|
`Failed to find environment "${env}" in configuration file!`
|
|
188
248
|
);
|
|
189
249
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
env: undefined,
|
|
196
|
-
preview,
|
|
197
|
-
config: {
|
|
198
|
-
env: undefined,
|
|
199
|
-
build: undefined,
|
|
200
|
-
name: undefined,
|
|
201
|
-
account_id: undefined,
|
|
202
|
-
...config.env[env],
|
|
250
|
+
return getNamespaceId(
|
|
251
|
+
{
|
|
252
|
+
binding,
|
|
253
|
+
"namespace-id": namespaceId,
|
|
254
|
+
preview,
|
|
203
255
|
},
|
|
204
|
-
|
|
256
|
+
configOrEnv.env[env]
|
|
257
|
+
);
|
|
205
258
|
}
|
|
206
259
|
|
|
207
260
|
// there's no KV namespaces
|
|
208
|
-
if (!
|
|
261
|
+
if (!configOrEnv.kv_namespaces || configOrEnv.kv_namespaces.length === 0) {
|
|
209
262
|
throw new Error(
|
|
210
263
|
"No KV Namespaces configured! Either use --namespace-id to upload directly or add a KV namespace to your wrangler config file."
|
|
211
264
|
);
|
|
212
265
|
}
|
|
213
266
|
|
|
214
|
-
const namespace =
|
|
267
|
+
const namespace = configOrEnv.kv_namespaces.find(
|
|
268
|
+
(ns) => ns.binding === binding
|
|
269
|
+
);
|
|
215
270
|
|
|
216
271
|
// we couldn't find a namespace with that binding
|
|
217
272
|
if (!namespace) {
|
package/src/module-collection.ts
CHANGED
|
@@ -1,21 +1,96 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import
|
|
4
|
+
import globToRegExp from "glob-to-regexp";
|
|
5
|
+
import type { Config, ConfigModuleRuleType } from "./config";
|
|
6
|
+
import type { CfModule, CfModuleType, CfScriptFormat } from "./worker";
|
|
5
7
|
import type esbuild from "esbuild";
|
|
6
8
|
|
|
9
|
+
const RuleTypeToModuleType: Record<ConfigModuleRuleType, CfModuleType> = {
|
|
10
|
+
ESModule: "esm",
|
|
11
|
+
CommonJS: "commonjs",
|
|
12
|
+
CompiledWasm: "compiled-wasm",
|
|
13
|
+
Data: "buffer",
|
|
14
|
+
Text: "text",
|
|
15
|
+
};
|
|
16
|
+
|
|
7
17
|
// This is a combination of an esbuild plugin and a mutable array
|
|
8
18
|
// that we use to collect module references from source code.
|
|
9
19
|
// There will be modules that _shouldn't_ be inlined directly into
|
|
10
20
|
// the bundle. (eg. wasm modules, some text files, etc). We can include
|
|
11
|
-
// those files as modules in the multi part
|
|
21
|
+
// those files as modules in the multi part worker form upload. This
|
|
12
22
|
// plugin+array is used to collect references to these modules, reference
|
|
13
23
|
// them correctly in the bundle, and add them to the form upload.
|
|
14
24
|
|
|
15
|
-
export
|
|
25
|
+
export const DEFAULT_MODULE_RULES: Config["rules"] = [
|
|
26
|
+
{ type: "Text", globs: ["**/*.txt", "**/*.html"] },
|
|
27
|
+
{ type: "Data", globs: ["**/*.bin"] },
|
|
28
|
+
{ type: "CompiledWasm", globs: ["**/*.wasm"] },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
export default function createModuleCollector(props: {
|
|
32
|
+
format: CfScriptFormat;
|
|
33
|
+
rules?: Config["rules"];
|
|
34
|
+
// a collection of "legacy" style module references, which are just file names
|
|
35
|
+
// we will eventually deprecate this functionality, hence the verbose greppable name
|
|
36
|
+
wrangler1xlegacyModuleReferences: {
|
|
37
|
+
rootDirectory: string;
|
|
38
|
+
fileNames: Set<string>;
|
|
39
|
+
};
|
|
40
|
+
}): {
|
|
16
41
|
modules: CfModule[];
|
|
17
42
|
plugin: esbuild.Plugin;
|
|
18
43
|
} {
|
|
44
|
+
const rules: Config["rules"] = [
|
|
45
|
+
...(props.rules || []),
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
47
|
+
...DEFAULT_MODULE_RULES!,
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
// First, we want to add some validations to the module rules
|
|
51
|
+
// We want to warn if rules are accidentally configured in such a way that
|
|
52
|
+
// subsequent rules will never match because `fallthrough` hasn't been set
|
|
53
|
+
|
|
54
|
+
const completedRuleLocations: Record<string, number> = {};
|
|
55
|
+
let index = 0;
|
|
56
|
+
const rulesToRemove: Config["rules"] = [];
|
|
57
|
+
for (const rule of rules) {
|
|
58
|
+
if (rule.type in completedRuleLocations) {
|
|
59
|
+
if (rules[completedRuleLocations[rule.type]].fallthrough !== false) {
|
|
60
|
+
if (index < (props.rules || []).length) {
|
|
61
|
+
console.warn(
|
|
62
|
+
`The module rule at position ${index} (${JSON.stringify(
|
|
63
|
+
rule
|
|
64
|
+
)}) has the same type as a previous rule (at position ${
|
|
65
|
+
completedRuleLocations[rule.type]
|
|
66
|
+
}, ${JSON.stringify(
|
|
67
|
+
rules[completedRuleLocations[rule.type]]
|
|
68
|
+
)}). This rule will be ignored. To the previous rule, add \`fallthrough = true\` to allow this one to also be used, or \`fallthrough = false\` to silence this warning.`
|
|
69
|
+
);
|
|
70
|
+
} else {
|
|
71
|
+
console.warn(
|
|
72
|
+
`The default module rule ${JSON.stringify(
|
|
73
|
+
rule
|
|
74
|
+
)} has the same type as a previous rule (at position ${
|
|
75
|
+
completedRuleLocations[rule.type]
|
|
76
|
+
}, ${JSON.stringify(
|
|
77
|
+
rules[completedRuleLocations[rule.type]]
|
|
78
|
+
)}). This rule will be ignored. To the previous rule, add \`fallthrough = true\` to allow the default one to also be used, or \`fallthrough = false\` to silence this warning.`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
rulesToRemove.push(rule);
|
|
84
|
+
}
|
|
85
|
+
if (!(rule.type in completedRuleLocations) && rule.fallthrough !== true) {
|
|
86
|
+
completedRuleLocations[rule.type] = index;
|
|
87
|
+
}
|
|
88
|
+
index++;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
92
|
+
rulesToRemove.forEach((rule) => rules!.splice(rules!.indexOf(rule), 1));
|
|
93
|
+
|
|
19
94
|
const modules: CfModule[] = [];
|
|
20
95
|
return {
|
|
21
96
|
modules,
|
|
@@ -23,40 +98,155 @@ export default function makeModuleCollector(): {
|
|
|
23
98
|
name: "wrangler-module-collector",
|
|
24
99
|
setup(build) {
|
|
25
100
|
build.onStart(() => {
|
|
26
|
-
// reset the
|
|
101
|
+
// reset the module collection array
|
|
27
102
|
modules.splice(0);
|
|
28
103
|
});
|
|
29
104
|
|
|
105
|
+
// ~ start legacy module specifier support ~
|
|
106
|
+
|
|
107
|
+
// This section detects usage of "legacy" 1.x style module specifiers
|
|
108
|
+
// and modifies them so they "work" in wrangler v2, but with a warning
|
|
109
|
+
|
|
110
|
+
const rulesMatchers = rules.flatMap((rule) => {
|
|
111
|
+
return rule.globs.map((glob) => {
|
|
112
|
+
const regex = globToRegExp(glob);
|
|
113
|
+
return {
|
|
114
|
+
regex,
|
|
115
|
+
rule,
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
30
120
|
build.onResolve(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
121
|
+
{
|
|
122
|
+
filter: new RegExp(
|
|
123
|
+
[...props.wrangler1xlegacyModuleReferences.fileNames]
|
|
124
|
+
.map((fileName) => `^${fileName}$`)
|
|
125
|
+
.join("|")
|
|
126
|
+
),
|
|
127
|
+
},
|
|
34
128
|
async (args: esbuild.OnResolveArgs) => {
|
|
129
|
+
if (
|
|
130
|
+
args.kind !== "import-statement" &&
|
|
131
|
+
args.kind !== "require-call"
|
|
132
|
+
) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
// In the future, this will simply throw an error
|
|
136
|
+
console.warn(
|
|
137
|
+
`Deprecation warning: detected a legacy module import in "./${path.relative(
|
|
138
|
+
process.cwd(),
|
|
139
|
+
args.importer
|
|
140
|
+
)}". This will stop working in the future. Replace references to "${
|
|
141
|
+
args.path
|
|
142
|
+
}" with "./${args.path}";`
|
|
143
|
+
);
|
|
144
|
+
|
|
35
145
|
// take the file and massage it to a
|
|
36
146
|
// transportable/manageable format
|
|
37
|
-
const filePath = path.join(
|
|
147
|
+
const filePath = path.join(
|
|
148
|
+
props.wrangler1xlegacyModuleReferences.rootDirectory,
|
|
149
|
+
args.path
|
|
150
|
+
);
|
|
38
151
|
const fileContent = await readFile(filePath);
|
|
39
152
|
const fileHash = crypto
|
|
40
153
|
.createHash("sha1")
|
|
41
154
|
.update(fileContent)
|
|
42
155
|
.digest("hex");
|
|
43
|
-
const fileName =
|
|
44
|
-
|
|
45
|
-
// add the module to the array
|
|
46
|
-
modules.push({
|
|
47
|
-
name: fileName,
|
|
48
|
-
content: fileContent,
|
|
49
|
-
type: "compiled-wasm",
|
|
50
|
-
});
|
|
156
|
+
const fileName = `./${fileHash}-${path.basename(args.path)}`;
|
|
51
157
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
158
|
+
const { rule } =
|
|
159
|
+
rulesMatchers.find(({ regex }) => regex.test(fileName)) || {};
|
|
160
|
+
if (rule) {
|
|
161
|
+
// add the module to the array
|
|
162
|
+
modules.push({
|
|
163
|
+
name: fileName,
|
|
164
|
+
content: fileContent,
|
|
165
|
+
type: RuleTypeToModuleType[rule.type],
|
|
166
|
+
});
|
|
167
|
+
return {
|
|
168
|
+
path: fileName, // change the reference to the changed module
|
|
169
|
+
external: props.format === "modules", // mark it as external in the bundle
|
|
170
|
+
namespace: `wrangler-module-${rule.type}`, // just a tag, this isn't strictly necessary
|
|
171
|
+
watchFiles: [filePath], // we also add the file to esbuild's watch list
|
|
172
|
+
};
|
|
173
|
+
}
|
|
58
174
|
}
|
|
59
175
|
);
|
|
176
|
+
// ~ end legacy module specifier support ~
|
|
177
|
+
|
|
178
|
+
rules?.forEach((rule) => {
|
|
179
|
+
if (rule.type === "ESModule" || rule.type === "CommonJS") return; // TODO: we should treat these as js files, and use the jsx loader
|
|
180
|
+
|
|
181
|
+
rule.globs.forEach((glob) => {
|
|
182
|
+
build.onResolve(
|
|
183
|
+
{ filter: globToRegExp(glob) },
|
|
184
|
+
async (args: esbuild.OnResolveArgs) => {
|
|
185
|
+
// take the file and massage it to a
|
|
186
|
+
// transportable/manageable format
|
|
187
|
+
|
|
188
|
+
const filePath = path.join(args.resolveDir, args.path);
|
|
189
|
+
const fileContent = await readFile(filePath);
|
|
190
|
+
const fileHash = crypto
|
|
191
|
+
.createHash("sha1")
|
|
192
|
+
.update(fileContent)
|
|
193
|
+
.digest("hex");
|
|
194
|
+
const fileName = `./${fileHash}-${path.basename(args.path)}`;
|
|
195
|
+
|
|
196
|
+
// add the module to the array
|
|
197
|
+
modules.push({
|
|
198
|
+
name: fileName,
|
|
199
|
+
content: fileContent,
|
|
200
|
+
type: RuleTypeToModuleType[rule.type],
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
path: fileName, // change the reference to the changed module
|
|
205
|
+
external: props.format === "modules", // mark it as external in the bundle
|
|
206
|
+
namespace: `wrangler-module-${rule.type}`, // just a tag, this isn't strictly necessary
|
|
207
|
+
watchFiles: [filePath], // we also add the file to esbuild's watch list
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
if (props.format === "service-worker") {
|
|
213
|
+
build.onLoad(
|
|
214
|
+
{ filter: globToRegExp(glob) },
|
|
215
|
+
async (args: esbuild.OnLoadArgs) => {
|
|
216
|
+
return {
|
|
217
|
+
// We replace the the module with an identifier
|
|
218
|
+
// that we'll separately add to the form upload
|
|
219
|
+
// as part of [wasm_modules]/[text_blobs]. This identifier has to be a valid
|
|
220
|
+
// JS identifier, so we replace all non alphanumeric characters
|
|
221
|
+
// with an underscore.
|
|
222
|
+
// TODO: what of "Data"?
|
|
223
|
+
contents: `export default ${args.path.replace(
|
|
224
|
+
/[^a-zA-Z0-9_$]/g,
|
|
225
|
+
"_"
|
|
226
|
+
)};`,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
rulesToRemove.forEach((rule) => {
|
|
235
|
+
rule.globs.forEach((glob) => {
|
|
236
|
+
build.onResolve(
|
|
237
|
+
{ filter: globToRegExp(glob) },
|
|
238
|
+
async (args: esbuild.OnResolveArgs) => {
|
|
239
|
+
throw new Error(
|
|
240
|
+
`The file ${
|
|
241
|
+
args.path
|
|
242
|
+
} matched a module rule in your configuration (${JSON.stringify(
|
|
243
|
+
rule
|
|
244
|
+
)}), but was ignored because a previous rule with the same type was not marked as \`fallthrough = true\`.`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
});
|
|
249
|
+
});
|
|
60
250
|
},
|
|
61
251
|
},
|
|
62
252
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import open from "open";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* An extremely simple wrapper around the open command.
|
|
5
|
+
* Specifically, it adds an 'error' event handler so that when this function
|
|
6
|
+
* is called in environments where we can't open the browser (e.g. github codespaces,
|
|
7
|
+
* stackblitz, remote servers), it doesn't just crash the process.
|
|
8
|
+
*
|
|
9
|
+
* @param url the URL to point the browser at
|
|
10
|
+
* @param options open a chromium-based browser instead of the default
|
|
11
|
+
*/
|
|
12
|
+
export default async function openInBrowser(
|
|
13
|
+
url: string,
|
|
14
|
+
{ forceChromium }: { forceChromium: boolean } = { forceChromium: false }
|
|
15
|
+
): Promise<void> {
|
|
16
|
+
const options: open.Options | undefined = forceChromium
|
|
17
|
+
? {
|
|
18
|
+
app: [{ name: open.apps.chrome }, { name: open.apps.edge }],
|
|
19
|
+
}
|
|
20
|
+
: undefined;
|
|
21
|
+
const childProcess = await open(url, options);
|
|
22
|
+
childProcess.on("error", () => {
|
|
23
|
+
console.warn(`Failed to open ${url} in a browser`);
|
|
24
|
+
});
|
|
25
|
+
}
|