wrangler 0.0.0-e1c615f → 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/bin/wrangler.js +2 -2
- package/package.json +34 -15
- package/pages/functions/buildWorker.ts +6 -1
- package/pages/functions/filepath-routing.test.ts +212 -28
- package/pages/functions/filepath-routing.ts +91 -131
- package/pages/functions/routes.ts +11 -18
- package/pages/functions/template-worker.ts +21 -28
- package/src/__tests__/configuration.test.ts +2598 -0
- package/src/__tests__/dev.test.tsx +437 -58
- package/src/__tests__/dev2.test.tsx +154 -0
- package/src/__tests__/guess-worker-format.test.ts +58 -0
- package/src/__tests__/{clipboardy-mock.js → helpers/clipboardy-mock.js} +0 -0
- package/src/__tests__/helpers/cmd-shim.d.ts +11 -0
- package/src/__tests__/helpers/faye-websocket.d.ts +6 -0
- package/src/__tests__/helpers/mock-account-id.ts +48 -0
- package/src/__tests__/helpers/mock-bin.ts +36 -0
- package/src/__tests__/{mock-cfetch.ts → helpers/mock-cfetch.ts} +55 -19
- package/src/__tests__/helpers/mock-console.ts +70 -0
- package/src/__tests__/{mock-dialogs.ts → helpers/mock-dialogs.ts} +1 -1
- package/src/__tests__/helpers/mock-kv.ts +33 -0
- 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 +32 -0
- package/src/__tests__/helpers/run-wrangler.ts +16 -0
- 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 +779 -75
- package/src/__tests__/jest.setup.ts +53 -6
- package/src/__tests__/kv.test.ts +726 -442
- package/src/__tests__/logout.test.ts +52 -0
- package/src/__tests__/package-manager.test.ts +206 -0
- package/src/__tests__/pages.test.ts +44 -0
- package/src/__tests__/parse.test.ts +322 -0
- package/src/__tests__/publish.test.ts +2611 -0
- package/src/__tests__/r2.test.ts +198 -0
- package/src/__tests__/route.test.ts +45 -0
- package/src/__tests__/secret.test.ts +425 -0
- package/src/__tests__/sentry.test.ts +146 -0
- package/src/__tests__/tail.test.ts +564 -0
- package/src/__tests__/whoami.test.tsx +100 -0
- package/src/bundle.ts +142 -0
- package/src/cfetch/index.ts +21 -19
- package/src/cfetch/internal.ts +94 -24
- 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} +61 -23
- 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/dialogs.tsx +2 -2
- package/src/entry.ts +159 -0
- package/src/environment-variables.ts +33 -0
- package/src/https-options.ts +122 -0
- package/src/index.tsx +1231 -795
- package/src/inspect.ts +617 -0
- package/src/{kv.tsx → kv.ts} +132 -60
- package/src/module-collection.ts +215 -26
- package/src/open-in-browser.ts +25 -0
- package/src/package-manager.ts +126 -0
- package/src/pages.tsx +140 -63
- package/src/parse.ts +183 -0
- package/src/paths.ts +26 -0
- package/src/proxy.ts +414 -77
- package/src/publish.ts +296 -292
- package/src/r2.ts +50 -0
- package/src/reporting.ts +131 -0
- package/src/selfsigned.d.ts +29 -0
- package/src/sites.tsx +217 -58
- 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 +284 -188
- package/src/whoami.tsx +69 -0
- package/src/{api/worker.ts → worker.ts} +51 -43
- package/templates/new-worker.js +15 -0
- package/templates/new-worker.ts +15 -0
- package/{static-asset-facade.js → templates/static-asset-facade.js} +0 -0
- package/templates/tsconfig.json +105 -0
- package/wrangler-dist/cli.js +130585 -112306
- package/wrangler-dist/cli.js.map +3 -3
- package/src/__tests__/run-in-tmp.ts +0 -19
- package/src/__tests__/run-wrangler.ts +0 -32
- package/src/api/form_data.ts +0 -131
- package/src/api/inspect.ts +0 -430
- package/src/config.ts +0 -131
- package/src/dev.tsx +0 -874
- package/src/tail.tsx +0 -73
package/src/{kv.tsx → kv.ts}
RENAMED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { URLSearchParams } from "node:url";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import { fetchListResult, fetchResult, fetchKVGetValue } from "./cfetch";
|
|
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
|
/**
|
|
@@ -82,7 +87,7 @@ export interface NamespaceKeyInfo {
|
|
|
82
87
|
export async function listNamespaceKeys(
|
|
83
88
|
accountId: string,
|
|
84
89
|
namespaceId: string,
|
|
85
|
-
prefix
|
|
90
|
+
prefix = ""
|
|
86
91
|
) {
|
|
87
92
|
return await fetchListResult<NamespaceKeyInfo>(
|
|
88
93
|
`/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/keys`,
|
|
@@ -91,62 +96,130 @@ 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
|
) {
|
|
144
|
+
let searchParams: URLSearchParams | undefined;
|
|
145
|
+
if (keyValue.expiration || keyValue.expiration_ttl) {
|
|
146
|
+
searchParams = new URLSearchParams();
|
|
147
|
+
if (keyValue.expiration) {
|
|
148
|
+
searchParams.set("expiration", `${keyValue.expiration}`);
|
|
149
|
+
}
|
|
150
|
+
if (keyValue.expiration_ttl) {
|
|
151
|
+
searchParams.set("expiration_ttl", `${keyValue.expiration_ttl}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
101
154
|
return await fetchResult(
|
|
102
|
-
`/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/values/${key}`,
|
|
103
|
-
{ method: "PUT", body: value },
|
|
104
|
-
|
|
105
|
-
? new URLSearchParams({
|
|
106
|
-
expiration: args.expiration?.toString(),
|
|
107
|
-
expiration_ttl: args.expiration_ttl?.toString(),
|
|
108
|
-
})
|
|
109
|
-
: undefined
|
|
155
|
+
`/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/values/${keyValue.key}`,
|
|
156
|
+
{ method: "PUT", body: keyValue.value },
|
|
157
|
+
searchParams
|
|
110
158
|
);
|
|
111
159
|
}
|
|
112
160
|
|
|
161
|
+
export async function getKeyValue(
|
|
162
|
+
accountId: string,
|
|
163
|
+
namespaceId: string,
|
|
164
|
+
key: string
|
|
165
|
+
): Promise<string> {
|
|
166
|
+
return await fetchKVGetValue(accountId, namespaceId, key);
|
|
167
|
+
}
|
|
168
|
+
|
|
113
169
|
export async function putBulkKeyValue(
|
|
114
170
|
accountId: string,
|
|
115
171
|
namespaceId: string,
|
|
116
|
-
|
|
172
|
+
keyValues: KeyValue[],
|
|
173
|
+
progressCallback: (index: number, total: number) => void
|
|
117
174
|
) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
method: "PUT",
|
|
122
|
-
body: keyvalueStr,
|
|
123
|
-
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);
|
|
124
178
|
}
|
|
125
|
-
|
|
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
|
+
}
|
|
126
192
|
}
|
|
127
193
|
|
|
128
194
|
export async function deleteBulkKeyValue(
|
|
129
195
|
accountId: string,
|
|
130
196
|
namespaceId: string,
|
|
131
|
-
|
|
197
|
+
keys: string[],
|
|
198
|
+
progressCallback: (index: number, total: number) => void
|
|
132
199
|
) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
method: "DELETE",
|
|
137
|
-
body: keyStr,
|
|
138
|
-
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);
|
|
139
203
|
}
|
|
140
|
-
|
|
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
|
+
}
|
|
141
217
|
}
|
|
142
218
|
|
|
143
|
-
export function getNamespaceId(
|
|
144
|
-
preview,
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
"namespace-id": namespaceId,
|
|
148
|
-
env,
|
|
149
|
-
}: KvArgs): string {
|
|
219
|
+
export function getNamespaceId(
|
|
220
|
+
{ preview, binding, "namespace-id": namespaceId, env }: KvArgs,
|
|
221
|
+
configOrEnv: Config | Environment | undefined
|
|
222
|
+
): string {
|
|
150
223
|
// nice
|
|
151
224
|
if (namespaceId) {
|
|
152
225
|
return namespaceId;
|
|
@@ -154,13 +227,13 @@ export function getNamespaceId({
|
|
|
154
227
|
|
|
155
228
|
// begin pre-flight checks
|
|
156
229
|
|
|
157
|
-
// `--binding` is only valid if there's a wrangler configuration
|
|
158
|
-
if (binding && !
|
|
230
|
+
// `--binding` is only valid if there's a wrangler configuration.
|
|
231
|
+
if (binding && !configOrEnv) {
|
|
159
232
|
throw new Error("--binding specified, but no config file was found.");
|
|
160
233
|
}
|
|
161
234
|
|
|
162
235
|
// there's no config. abort here
|
|
163
|
-
if (!
|
|
236
|
+
if (!configOrEnv) {
|
|
164
237
|
throw new Error(
|
|
165
238
|
"Failed to find a config file.\n" +
|
|
166
239
|
"Either use --namespace-id to upload directly or create a configuration file with a binding."
|
|
@@ -169,36 +242,31 @@ export function getNamespaceId({
|
|
|
169
242
|
|
|
170
243
|
// they want to use an environment, actually
|
|
171
244
|
if (env) {
|
|
172
|
-
if (!
|
|
245
|
+
if (!("env" in configOrEnv) || !configOrEnv.env[env]) {
|
|
173
246
|
throw new Error(
|
|
174
247
|
`Failed to find environment "${env}" in configuration file!`
|
|
175
248
|
);
|
|
176
249
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
env: undefined,
|
|
183
|
-
preview,
|
|
184
|
-
config: {
|
|
185
|
-
env: undefined,
|
|
186
|
-
build: undefined,
|
|
187
|
-
name: undefined,
|
|
188
|
-
account_id: undefined,
|
|
189
|
-
...config.env[env],
|
|
250
|
+
return getNamespaceId(
|
|
251
|
+
{
|
|
252
|
+
binding,
|
|
253
|
+
"namespace-id": namespaceId,
|
|
254
|
+
preview,
|
|
190
255
|
},
|
|
191
|
-
|
|
256
|
+
configOrEnv.env[env]
|
|
257
|
+
);
|
|
192
258
|
}
|
|
193
259
|
|
|
194
260
|
// there's no KV namespaces
|
|
195
|
-
if (!
|
|
261
|
+
if (!configOrEnv.kv_namespaces || configOrEnv.kv_namespaces.length === 0) {
|
|
196
262
|
throw new Error(
|
|
197
263
|
"No KV Namespaces configured! Either use --namespace-id to upload directly or add a KV namespace to your wrangler config file."
|
|
198
264
|
);
|
|
199
265
|
}
|
|
200
266
|
|
|
201
|
-
const namespace =
|
|
267
|
+
const namespace = configOrEnv.kv_namespaces.find(
|
|
268
|
+
(ns) => ns.binding === binding
|
|
269
|
+
);
|
|
202
270
|
|
|
203
271
|
// we couldn't find a namespace with that binding
|
|
204
272
|
if (!namespace) {
|
|
@@ -262,6 +330,10 @@ export function getNamespaceId({
|
|
|
262
330
|
/**
|
|
263
331
|
* KV namespace binding names must be valid JS identifiers.
|
|
264
332
|
*/
|
|
265
|
-
export function isValidNamespaceBinding(
|
|
266
|
-
|
|
333
|
+
export function isValidNamespaceBinding(
|
|
334
|
+
binding: string | undefined
|
|
335
|
+
): binding is string {
|
|
336
|
+
return (
|
|
337
|
+
typeof binding === "string" && /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(binding)
|
|
338
|
+
);
|
|
267
339
|
}
|
package/src/module-collection.ts
CHANGED
|
@@ -1,21 +1,96 @@
|
|
|
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
1
|
import crypto from "node:crypto";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import globToRegExp from "glob-to-regexp";
|
|
5
|
+
import type { Config, ConfigModuleRuleType } from "./config";
|
|
6
|
+
import type { CfModule, CfModuleType, CfScriptFormat } from "./worker";
|
|
7
|
+
import type esbuild from "esbuild";
|
|
8
|
+
|
|
9
|
+
const RuleTypeToModuleType: Record<ConfigModuleRuleType, CfModuleType> = {
|
|
10
|
+
ESModule: "esm",
|
|
11
|
+
CommonJS: "commonjs",
|
|
12
|
+
CompiledWasm: "compiled-wasm",
|
|
13
|
+
Data: "buffer",
|
|
14
|
+
Text: "text",
|
|
15
|
+
};
|
|
6
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,41 +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
|
|
38
|
-
|
|
147
|
+
const filePath = path.join(
|
|
148
|
+
props.wrangler1xlegacyModuleReferences.rootDirectory,
|
|
149
|
+
args.path
|
|
150
|
+
);
|
|
39
151
|
const fileContent = await readFile(filePath);
|
|
40
152
|
const fileHash = crypto
|
|
41
153
|
.createHash("sha1")
|
|
42
154
|
.update(fileContent)
|
|
43
155
|
.digest("hex");
|
|
44
|
-
const fileName =
|
|
156
|
+
const fileName = `./${fileHash}-${path.basename(args.path)}`;
|
|
45
157
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
+
}
|
|
59
174
|
}
|
|
60
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
|
+
});
|
|
61
250
|
},
|
|
62
251
|
},
|
|
63
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
|
+
}
|