wrangler 2.0.5 → 2.0.6

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.
@@ -12,6 +12,7 @@ import {
12
12
  unsetMockFetchKVGetValues,
13
13
  } from "./helpers/mock-cfetch";
14
14
  import { mockConsoleMethods, normalizeSlashes } from "./helpers/mock-console";
15
+ import { mockConfirm } from "./helpers/mock-dialogs";
15
16
  import { useMockIsTTY } from "./helpers/mock-istty";
16
17
  import { mockKeyListRequest } from "./helpers/mock-kv";
17
18
  import { mockOAuthFlow } from "./helpers/mock-oauth-flow";
@@ -645,6 +646,136 @@ describe("publish", () => {
645
646
  await runWrangler("publish ./index --env dev --legacy-env false");
646
647
  });
647
648
 
649
+ describe("custom domains", () => {
650
+ it("should publish routes marked with 'custom_domain' as seperate custom domains", async () => {
651
+ writeWranglerToml({
652
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
653
+ });
654
+ writeWorkerSource();
655
+ mockUpdateWorkerRequest({ enabled: false });
656
+ mockUploadWorkerRequest({ expectedType: "esm" });
657
+ mockPublishCustomDomainsRequest({
658
+ publishFlags: {
659
+ override_scope: true,
660
+ override_existing_origin: false,
661
+ override_existing_dns_record: false,
662
+ },
663
+ domains: [{ hostname: "api.example.com" }],
664
+ });
665
+ await runWrangler("publish ./index");
666
+ expect(std.out).toContain("api.example.com (custom domain)");
667
+ });
668
+
669
+ it("should allow retrying if publish fails with a conflicting custom domain error", async () => {
670
+ writeWranglerToml({
671
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
672
+ });
673
+ writeWorkerSource();
674
+ mockUpdateWorkerRequest({ enabled: false });
675
+ mockUploadWorkerRequest({ expectedType: "esm" });
676
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
677
+ originConflicts: true,
678
+ domains: [{ hostname: "api.example.com" }],
679
+ });
680
+ mockConfirm({
681
+ text: `Custom Domains already exist for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
682
+ result: true,
683
+ });
684
+ await runWrangler("publish ./index");
685
+ expect(std.out).toContain("api.example.com (custom domain)");
686
+ });
687
+
688
+ it("should allow retrying if publish fails with a conflicting DNS record error", async () => {
689
+ writeWranglerToml({
690
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
691
+ });
692
+ writeWorkerSource();
693
+ mockUpdateWorkerRequest({ enabled: false });
694
+ mockUploadWorkerRequest({ expectedType: "esm" });
695
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
696
+ dnsRecordConflicts: true,
697
+ domains: [{ hostname: "api.example.com" }],
698
+ });
699
+ mockConfirm({
700
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
701
+ result: true,
702
+ });
703
+ await runWrangler("publish ./index");
704
+ expect(std.out).toContain("api.example.com (custom domain)");
705
+ });
706
+
707
+ it("should allow retrying for conflicting custom domains and then again for conflicting dns", async () => {
708
+ writeWranglerToml({
709
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
710
+ });
711
+ writeWorkerSource();
712
+ mockUpdateWorkerRequest({ enabled: false });
713
+ mockUploadWorkerRequest({ expectedType: "esm" });
714
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
715
+ originConflicts: true,
716
+ dnsRecordConflicts: true,
717
+ domains: [{ hostname: "api.example.com" }],
718
+ });
719
+ mockConfirm(
720
+ {
721
+ text: `Custom Domains already exist for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
722
+ result: true,
723
+ },
724
+ {
725
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
726
+ result: true,
727
+ }
728
+ );
729
+ await runWrangler("publish ./index");
730
+ expect(std.out).toContain("api.example.com (custom domain)");
731
+ });
732
+
733
+ it("should throw if an invalid custom domain is requested", async () => {
734
+ writeWranglerToml({
735
+ routes: [{ pattern: "*.example.com", custom_domain: true }],
736
+ });
737
+ writeWorkerSource();
738
+ await expect(
739
+ runWrangler("publish ./index")
740
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
741
+ `"Cannot use \\"*.example.com\\" as a Custom Domain; wildcard operators (*) are not allowed"`
742
+ );
743
+
744
+ writeWranglerToml({
745
+ routes: [
746
+ { pattern: "api.example.com/at/a/path", custom_domain: true },
747
+ ],
748
+ });
749
+ writeWorkerSource();
750
+ await expect(
751
+ runWrangler("publish ./index")
752
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
753
+ `"Cannot use \\"api.example.com/at/a/path\\" as a Custom Domain; paths are not allowed"`
754
+ );
755
+ });
756
+
757
+ it("should not retry publish on error if user does not confirm", async () => {
758
+ writeWranglerToml({
759
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
760
+ });
761
+ writeWorkerSource();
762
+ mockUpdateWorkerRequest({ enabled: false });
763
+ mockUploadWorkerRequest({ expectedType: "esm" });
764
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
765
+ dnsRecordConflicts: true,
766
+ domains: [{ hostname: "api.example.com" }],
767
+ });
768
+ mockConfirm({
769
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
770
+ result: false,
771
+ });
772
+ await runWrangler("publish ./index");
773
+ expect(std.out).toContain(
774
+ 'Publishing to Custom Domain "api.example.com" was skipped, fix conflict and try again'
775
+ );
776
+ });
777
+ });
778
+
648
779
  it.todo("should error if it's a workers.dev route");
649
780
  });
650
781
 
@@ -3106,6 +3237,7 @@ addEventListener('fetch', event => {});`
3106
3237
  name: "DURABLE_OBJECT_TWO",
3107
3238
  class_name: "AnotherDurableObject",
3108
3239
  script_name: "another-durable-object-worker",
3240
+ environment: "staging",
3109
3241
  },
3110
3242
  ],
3111
3243
  },
@@ -3164,6 +3296,12 @@ addEventListener('fetch', event => {});`
3164
3296
  mockUploadWorkerRequest({
3165
3297
  expectedType: "sw",
3166
3298
  expectedBindings: [
3299
+ { json: 123, name: "ENV_VAR_ONE", type: "json" },
3300
+ {
3301
+ name: "ENV_VAR_TWO",
3302
+ text: "Hello, I'm an environment variable",
3303
+ type: "plain_text",
3304
+ },
3167
3305
  {
3168
3306
  name: "KV_NAMESPACE_ONE",
3169
3307
  namespace_id: "kv-ns-one-id",
@@ -3182,6 +3320,7 @@ addEventListener('fetch', event => {});`
3182
3320
  },
3183
3321
  {
3184
3322
  class_name: "AnotherDurableObject",
3323
+ environment: "staging",
3185
3324
  name: "DURABLE_OBJECT_TWO",
3186
3325
  script_name: "another-durable-object-worker",
3187
3326
  type: "durable_object_namespace",
@@ -3196,12 +3335,6 @@ addEventListener('fetch', event => {});`
3196
3335
  name: "R2_BUCKET_TWO",
3197
3336
  type: "r2_bucket",
3198
3337
  },
3199
- { json: 123, name: "ENV_VAR_ONE", type: "json" },
3200
- {
3201
- name: "ENV_VAR_TWO",
3202
- text: "Hello, I'm an environment variable",
3203
- type: "plain_text",
3204
- },
3205
3338
  {
3206
3339
  name: "WASM_MODULE_ONE",
3207
3340
  part: "WASM_MODULE_ONE",
@@ -4123,6 +4256,47 @@ addEventListener('fetch', event => {});`
4123
4256
  });
4124
4257
  });
4125
4258
 
4259
+ describe("[services]", () => {
4260
+ it("should support service bindings", async () => {
4261
+ writeWranglerToml({
4262
+ services: [
4263
+ {
4264
+ binding: "FOO",
4265
+ service: "foo-service",
4266
+ environment: "production",
4267
+ },
4268
+ ],
4269
+ });
4270
+ writeWorkerSource();
4271
+ mockSubDomainRequest();
4272
+ mockUploadWorkerRequest({
4273
+ expectedBindings: [
4274
+ {
4275
+ type: "service",
4276
+ name: "FOO",
4277
+ service: "foo-service",
4278
+ environment: "production",
4279
+ },
4280
+ ],
4281
+ });
4282
+
4283
+ await runWrangler("publish index.js");
4284
+ expect(std.out).toMatchInlineSnapshot(`
4285
+ "Uploaded test-name (TIMINGS)
4286
+ Published test-name (TIMINGS)
4287
+ test-name.test-sub-domain.workers.dev"
4288
+ `);
4289
+ expect(std.err).toMatchInlineSnapshot(`""`);
4290
+ expect(std.warn).toMatchInlineSnapshot(`
4291
+ "▲ [WARNING] Processing wrangler.toml configuration:
4292
+
4293
+ - \\"services\\" fields are experimental and may change or break at any time.
4294
+
4295
+ "
4296
+ `);
4297
+ });
4298
+ });
4299
+
4126
4300
  describe("[unsafe]", () => {
4127
4301
  it("should warn if using unsafe bindings", async () => {
4128
4302
  writeWranglerToml({
@@ -4625,8 +4799,16 @@ addEventListener('fetch', event => {});`
4625
4799
 
4626
4800
  describe("--dry-run", () => {
4627
4801
  it("should not publish the worker if --dry-run is specified", async () => {
4628
- writeWranglerToml();
4802
+ writeWranglerToml({
4803
+ // add a durable object with migrations
4804
+ // to make sure we _don't_ fetch migration status
4805
+ durable_objects: {
4806
+ bindings: [{ name: "NAME", class_name: "SomeClass" }],
4807
+ },
4808
+ migrations: [{ tag: "v1", new_classes: ["SomeClass"] }],
4809
+ });
4629
4810
  writeWorkerSource();
4811
+ process.env.CLOUDFLARE_ACCOUNT_ID = "";
4630
4812
  await runWrangler("publish index.js --dry-run");
4631
4813
  expect(std).toMatchInlineSnapshot(`
4632
4814
  Object {
@@ -4656,6 +4838,27 @@ addEventListener('fetch', event => {});`
4656
4838
  `);
4657
4839
  });
4658
4840
 
4841
+ it("should recommend node compatibility mode when using node builtins and node-compat isn't enabled", async () => {
4842
+ writeWranglerToml();
4843
+ fs.writeFileSync(
4844
+ "index.js",
4845
+ `
4846
+ import path from 'path';
4847
+ console.log(path.join("some/path/to", "a/file.txt"));
4848
+ export default {}
4849
+ `
4850
+ );
4851
+ let err: Error | undefined;
4852
+ try {
4853
+ await runWrangler("publish index.js --dry-run"); // expecting this to throw, as node compatibility isn't enabled
4854
+ } catch (e) {
4855
+ err = e as Error;
4856
+ }
4857
+ expect(err?.message).toMatch(
4858
+ `Detected a Node builtin module import while Node compatibility is disabled.\nAdd node_compat = true to your wrangler.toml file to enable Node compatibility.`
4859
+ );
4860
+ });
4861
+
4659
4862
  it("should polyfill node builtins when enabled", async () => {
4660
4863
  writeWranglerToml();
4661
4864
  fs.writeFileSync(
@@ -4850,6 +5053,102 @@ function mockPublishRoutesRequest({
4850
5053
  );
4851
5054
  }
4852
5055
 
5056
+ function mockPublishCustomDomainsRequest({
5057
+ publishFlags,
5058
+ domains = [],
5059
+ env = undefined,
5060
+ legacyEnv = false,
5061
+ }: {
5062
+ publishFlags: {
5063
+ override_scope: boolean;
5064
+ override_existing_origin: boolean;
5065
+ override_existing_dns_record: boolean;
5066
+ };
5067
+ domains: Array<
5068
+ { hostname: string } & ({ zone_id?: string } | { zone_name?: string })
5069
+ >;
5070
+ env?: string | undefined;
5071
+ legacyEnv?: boolean | undefined;
5072
+ }) {
5073
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
5074
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
5075
+
5076
+ setMockResponse(
5077
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/domains`,
5078
+ "PUT",
5079
+ ([_url, accountId, scriptName, envName], { body }) => {
5080
+ expect(accountId).toEqual("some-account-id");
5081
+ expect(scriptName).toEqual(
5082
+ legacyEnv && env ? `test-name-${env}` : "test-name"
5083
+ );
5084
+ if (!legacyEnv) {
5085
+ expect(envName).toEqual(env);
5086
+ }
5087
+
5088
+ expect(JSON.parse(body as string)).toEqual({
5089
+ ...publishFlags,
5090
+ origins: domains,
5091
+ });
5092
+
5093
+ return null;
5094
+ }
5095
+ );
5096
+ }
5097
+
5098
+ function mockPublishCustomDomainsRequestConflictWithoutOverride({
5099
+ domains = [],
5100
+ originConflicts = false,
5101
+ dnsRecordConflicts = false,
5102
+ env = undefined,
5103
+ legacyEnv = false,
5104
+ }: {
5105
+ originConflicts?: boolean;
5106
+ dnsRecordConflicts?: boolean;
5107
+ domains: Array<
5108
+ { hostname: string } & ({ zone_id?: string } | { zone_name?: string })
5109
+ >;
5110
+ env?: string | undefined;
5111
+ legacyEnv?: boolean | undefined;
5112
+ }) {
5113
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
5114
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
5115
+
5116
+ setMockRawResponse(
5117
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/domains`,
5118
+ "PUT",
5119
+ ([_url, accountId, scriptName, envName], { body }) => {
5120
+ expect(accountId).toEqual("some-account-id");
5121
+ expect(scriptName).toEqual(
5122
+ legacyEnv && env ? `test-name-${env}` : "test-name"
5123
+ );
5124
+ if (!legacyEnv) {
5125
+ expect(envName).toEqual(env);
5126
+ }
5127
+
5128
+ const parsed = JSON.parse(body as string);
5129
+ expect(parsed.origins).toEqual(domains);
5130
+
5131
+ if (originConflicts && !parsed.override_existing_origin) {
5132
+ return createFetchResult(null, false, [
5133
+ {
5134
+ code: 100116,
5135
+ message: `Cannot create Custom Domain "${domains[0].hostname}": Custom Domain already exists and points to a different script; retry and use option "override_existing_origin" to override`,
5136
+ },
5137
+ ]);
5138
+ }
5139
+ if (dnsRecordConflicts && !parsed.override_existing_dns_record) {
5140
+ return createFetchResult(null, false, [
5141
+ {
5142
+ code: 100117,
5143
+ message: `Cannot create Custom Domain "${domains[0].hostname}": a DNS record already exists for this origin; retry and use option "override_existing_dns_record" to override`,
5144
+ },
5145
+ ]);
5146
+ }
5147
+ return createFetchResult(null, true);
5148
+ }
5149
+ );
5150
+ }
5151
+
4853
5152
  /** Create a mock handler for the request to get a list of all KV namespaces. */
4854
5153
  function mockListKVNamespacesRequest(...namespaces: KVNamespaceInfo[]) {
4855
5154
  setMockResponse(
@@ -17,6 +17,33 @@ describe("wrangler", () => {
17
17
 
18
18
  describe("r2", () => {
19
19
  describe("bucket", () => {
20
+ it("should show the correct help when an invalid command is passed", async () => {
21
+ await expect(() =>
22
+ runWrangler("r2 bucket foo")
23
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`"Unknown argument: foo"`);
24
+ expect(std.err).toMatchInlineSnapshot(`
25
+ "X [ERROR] Unknown argument: foo
26
+
27
+ "
28
+ `);
29
+ expect(std.out).toMatchInlineSnapshot(`
30
+ "
31
+ wrangler r2 bucket
32
+
33
+ Manage R2 buckets
34
+
35
+ Commands:
36
+ wrangler r2 bucket create <name> Create a new R2 bucket
37
+ wrangler r2 bucket list List R2 buckets
38
+ wrangler r2 bucket delete <name> Delete an R2 bucket
39
+
40
+ Flags:
41
+ -c, --config Path to .toml configuration file [string]
42
+ -h, --help Show help [boolean]
43
+ -v, --version Show version number [boolean]"
44
+ `);
45
+ });
46
+
20
47
  describe("list", () => {
21
48
  function mockListRequest(buckets: R2BucketInfo[]) {
22
49
  const requests = { count: 0 };
@@ -69,10 +96,7 @@ describe("wrangler", () => {
69
96
  );
70
97
  expect(std.out).toMatchInlineSnapshot(`
71
98
  "
72
- "
73
- `);
74
- expect(std.err).toMatchInlineSnapshot(`
75
- "wrangler r2 bucket create <name>
99
+ wrangler r2 bucket create <name>
76
100
 
77
101
  Create a new R2 bucket
78
102
 
@@ -82,8 +106,10 @@ describe("wrangler", () => {
82
106
  Flags:
83
107
  -c, --config Path to .toml configuration file [string]
84
108
  -h, --help Show help [boolean]
85
- -v, --version Show version number [boolean]
86
- X [ERROR] Not enough non-option arguments: got 0, need at least 1
109
+ -v, --version Show version number [boolean]"
110
+ `);
111
+ expect(std.err).toMatchInlineSnapshot(`
112
+ "X [ERROR] Not enough non-option arguments: got 0, need at least 1
87
113
 
88
114
  "
89
115
  `);
@@ -97,10 +123,7 @@ describe("wrangler", () => {
97
123
  );
98
124
  expect(std.out).toMatchInlineSnapshot(`
99
125
  "
100
- "
101
- `);
102
- expect(std.err).toMatchInlineSnapshot(`
103
- "wrangler r2 bucket create <name>
126
+ wrangler r2 bucket create <name>
104
127
 
105
128
  Create a new R2 bucket
106
129
 
@@ -110,8 +133,10 @@ describe("wrangler", () => {
110
133
  Flags:
111
134
  -c, --config Path to .toml configuration file [string]
112
135
  -h, --help Show help [boolean]
113
- -v, --version Show version number [boolean]
114
- X [ERROR] Unknown arguments: def, ghi
136
+ -v, --version Show version number [boolean]"
137
+ `);
138
+ expect(std.err).toMatchInlineSnapshot(`
139
+ "X [ERROR] Unknown arguments: def, ghi
115
140
 
116
141
  "
117
142
  `);
@@ -151,10 +176,7 @@ describe("wrangler", () => {
151
176
  );
152
177
  expect(std.out).toMatchInlineSnapshot(`
153
178
  "
154
- "
155
- `);
156
- expect(std.err).toMatchInlineSnapshot(`
157
- "wrangler r2 bucket delete <name>
179
+ wrangler r2 bucket delete <name>
158
180
 
159
181
  Delete an R2 bucket
160
182
 
@@ -164,8 +186,10 @@ describe("wrangler", () => {
164
186
  Flags:
165
187
  -c, --config Path to .toml configuration file [string]
166
188
  -h, --help Show help [boolean]
167
- -v, --version Show version number [boolean]
168
- X [ERROR] Not enough non-option arguments: got 0, need at least 1
189
+ -v, --version Show version number [boolean]"
190
+ `);
191
+ expect(std.err).toMatchInlineSnapshot(`
192
+ "X [ERROR] Not enough non-option arguments: got 0, need at least 1
169
193
 
170
194
  "
171
195
  `);
@@ -179,10 +203,7 @@ describe("wrangler", () => {
179
203
  );
180
204
  expect(std.out).toMatchInlineSnapshot(`
181
205
  "
182
- "
183
- `);
184
- expect(std.err).toMatchInlineSnapshot(`
185
- "wrangler r2 bucket delete <name>
206
+ wrangler r2 bucket delete <name>
186
207
 
187
208
  Delete an R2 bucket
188
209
 
@@ -192,8 +213,10 @@ describe("wrangler", () => {
192
213
  Flags:
193
214
  -c, --config Path to .toml configuration file [string]
194
215
  -h, --help Show help [boolean]
195
- -v, --version Show version number [boolean]
196
- X [ERROR] Unknown arguments: def, ghi
216
+ -v, --version Show version number [boolean]"
217
+ `);
218
+ expect(std.err).toMatchInlineSnapshot(`
219
+ "X [ERROR] Unknown arguments: def, ghi
197
220
 
198
221
  "
199
222
  `);
@@ -60,6 +60,22 @@ describe("wrangler secret", () => {
60
60
  describe("interactive", () => {
61
61
  useMockStdin({ isTTY: true });
62
62
 
63
+ it("should trim stdin secret value", async () => {
64
+ mockPrompt({
65
+ text: "Enter a secret value:",
66
+ type: "password",
67
+ result: `hunter2
68
+ `,
69
+ });
70
+
71
+ mockPutRequest({ name: `secret-name`, text: `hunter2` });
72
+ await runWrangler("secret put secret-name --name script-name");
73
+ expect(std.out).toMatchInlineSnapshot(`
74
+ "🌀 Creating the secret for script script-name
75
+ ✨ Success! Uploaded secret secret-name"
76
+ `);
77
+ });
78
+
63
79
  it("should create a secret", async () => {
64
80
  mockPrompt({
65
81
  text: "Enter a secret value:",
@@ -146,6 +162,25 @@ describe("wrangler secret", () => {
146
162
  describe("non-interactive", () => {
147
163
  const mockStdIn = useMockStdin({ isTTY: false });
148
164
 
165
+ it("should trim stdin secret value, from piped input", async () => {
166
+ mockPutRequest({ name: "the-key", text: "the-secret" });
167
+ // Pipe the secret in as three chunks to test that we reconstitute it correctly.
168
+ mockStdIn.send(
169
+ `the`,
170
+ `-`,
171
+ `secret
172
+ ` // whitespace & newline being removed
173
+ );
174
+ await runWrangler("secret put the-key --name script-name");
175
+
176
+ expect(std.out).toMatchInlineSnapshot(`
177
+ "🌀 Creating the secret for script script-name
178
+ ✨ Success! Uploaded secret the-key"
179
+ `);
180
+ expect(std.warn).toMatchInlineSnapshot(`""`);
181
+ expect(std.err).toMatchInlineSnapshot(`""`);
182
+ });
183
+
149
184
  it("should create a secret, from piped input", async () => {
150
185
  mockPutRequest({ name: "the-key", text: "the-secret" });
151
186
  // Pipe the secret in as three chunks to test that we reconstitute it correctly.
package/src/bundle.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import assert from "node:assert";
2
2
  import * as fs from "node:fs";
3
+ import { builtinModules } from "node:module";
3
4
  import * as path from "node:path";
4
5
  import NodeGlobalsPolyfills from "@esbuild-plugins/node-globals-polyfill";
5
6
  import NodeModulesPolyfills from "@esbuild-plugins/node-modules-polyfill";
@@ -16,6 +17,33 @@ type BundleResult = {
16
17
  stop: (() => void) | undefined;
17
18
  };
18
19
 
20
+ /**
21
+ * Searches for any uses of node's builtin modules, and throws an error if it
22
+ * finds anything. This plugin is only used when nodeCompat is not enabled.
23
+ * Supports both regular node builtins, and the new "node:<MODULE>" format.
24
+ */
25
+ const checkForNodeBuiltinsPlugin = {
26
+ name: "checkForNodeBuiltins",
27
+ setup(build: esbuild.PluginBuild) {
28
+ build.onResolve(
29
+ {
30
+ filter: new RegExp(
31
+ "^(" +
32
+ builtinModules.join("|") +
33
+ "|" +
34
+ builtinModules.map((module) => "node:" + module).join("|") +
35
+ ")$"
36
+ ),
37
+ },
38
+ () => {
39
+ throw new Error(
40
+ `Detected a Node builtin module import while Node compatibility is disabled.\nAdd node_compat = true to your wrangler.toml file to enable Node compatibility.`
41
+ );
42
+ }
43
+ );
44
+ },
45
+ };
46
+
19
47
  /**
20
48
  * Generate a bundle for the worker identified by the arguments passed in.
21
49
  */
@@ -60,6 +88,7 @@ export async function bundleWorker(
60
88
  format: entry.format,
61
89
  rules,
62
90
  });
91
+
63
92
  const result = await esbuild.build({
64
93
  ...getEntryPoint(entry.file, serveAssetsFromWorker),
65
94
  bundle: true,
@@ -87,7 +116,9 @@ export async function bundleWorker(
87
116
  moduleCollector.plugin,
88
117
  ...(nodeCompat
89
118
  ? [NodeGlobalsPolyfills({ buffer: true }), NodeModulesPolyfills()]
90
- : []),
119
+ : // we use checkForNodeBuiltinsPlugin to throw a nicer error
120
+ // if we find node builtins when nodeCompat isn't turned on
121
+ [checkForNodeBuiltinsPlugin]),
91
122
  ],
92
123
  ...(jsxFactory && { jsxFactory }),
93
124
  ...(jsxFragment && { jsxFragment }),