Skip to content

Commit e1b8ac4

Browse files
feat: --assets / config.assets to serve a folder of static assets (#1237)
This adds support for defining `assets` in `wrangler.toml`. You can configure it with a string path, or a `{bucket, include, exclude}` object (much like `[site]`). This also renames the `--experimental-public` arg as `--assets`. Via #1162
1 parent 191f4d6 commit e1b8ac4

14 files changed

+422
-86
lines changed

.changeset/wise-steaks-end.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"wrangler": patch
3+
---
4+
5+
feat: `--assets` / `config.assets` to serve a folder of static assets
6+
7+
This adds support for defining `assets` in `wrangler.toml`. You can configure it with a string path, or a `{bucket, include, exclude}` object (much like `[site]`). This also renames the `--experimental-public` arg as `--assets`.
8+
9+
Via https://github.com/cloudflare/wrangler2/issues/1162

packages/wrangler/src/__tests__/configuration.test.ts

+61
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,67 @@ describe("normalizeAndValidateConfig()", () => {
412412
});
413413
});
414414

415+
describe("assets", () => {
416+
it("should error if `assets` config is missing `bucket`", () => {
417+
const expectedConfig: RawConfig = {
418+
// @ts-expect-error we're intentionally passing an invalid configuration here
419+
assets: {
420+
include: ["INCLUDE_1", "INCLUDE_2"],
421+
exclude: ["EXCLUDE_1", "EXCLUDE_2"],
422+
},
423+
};
424+
425+
const { config, diagnostics } = normalizeAndValidateConfig(
426+
expectedConfig,
427+
undefined,
428+
{ env: undefined }
429+
);
430+
431+
expect(config).toEqual(expect.objectContaining(expectedConfig));
432+
expect(diagnostics.hasWarnings()).toBe(true);
433+
expect(diagnostics.hasErrors()).toBe(true);
434+
435+
expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
436+
"Processing wrangler configuration:
437+
- \\"assets\\" fields are experimental and may change or break at any time."
438+
`);
439+
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
440+
"Processing wrangler configuration:
441+
- \\"assets.bucket\\" is a required field."
442+
`);
443+
});
444+
445+
it("should error on invalid `assets` values", () => {
446+
const expectedConfig = {
447+
assets: {
448+
bucket: "BUCKET",
449+
include: [222, 333],
450+
exclude: [444, 555],
451+
},
452+
};
453+
454+
const { config, diagnostics } = normalizeAndValidateConfig(
455+
expectedConfig as unknown as RawConfig,
456+
undefined,
457+
{ env: undefined }
458+
);
459+
460+
expect(config).toEqual(expect.objectContaining(expectedConfig));
461+
expect(diagnostics.hasWarnings()).toBe(true);
462+
expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
463+
"Processing wrangler configuration:
464+
- \\"assets\\" fields are experimental and may change or break at any time."
465+
`);
466+
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
467+
"Processing wrangler configuration:
468+
- Expected \\"assets.include.[0]\\" to be of type string but got 222.
469+
- Expected \\"assets.include.[1]\\" to be of type string but got 333.
470+
- Expected \\"assets.exclude.[0]\\" to be of type string but got 444.
471+
- Expected \\"assets.exclude.[1]\\" to be of type string but got 555."
472+
`);
473+
});
474+
});
475+
415476
it("should map `wasm_module` paths from relative to the config path to relative to the cwd", () => {
416477
const expectedConfig: RawConfig = {
417478
wasm_modules: {

packages/wrangler/src/__tests__/dev.test.tsx

+53-8
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ describe("wrangler dev", () => {
799799
});
800800
});
801801

802-
describe("site", () => {
802+
describe("serve static assets", () => {
803803
it("should error if --site is used with no value", async () => {
804804
await expect(
805805
runWrangler("dev --site")
@@ -839,7 +839,7 @@ describe("wrangler dev", () => {
839839
--routes, --route Routes to upload [array]
840840
--host Host to forward requests to, defaults to the zone of project [string]
841841
--local-protocol Protocol to listen to requests on, defaults to http. [choices: \\"http\\", \\"https\\"]
842-
--experimental-public Static assets to be served [string]
842+
--assets Static assets to be served [string]
843843
--site Root folder of static assets for Workers Sites [string]
844844
--site-include Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded. [array]
845845
--site-exclude Array of .gitignore-style patterns that match file or directory names from the sites directory. Matched items will not be uploaded. [array]
@@ -857,19 +857,19 @@ describe("wrangler dev", () => {
857857
`);
858858
});
859859

860-
it("should error if --experimental-public and --site are used together", async () => {
860+
it("should error if --assets and --site are used together", async () => {
861861
writeWranglerToml({
862862
main: "./index.js",
863863
});
864864
fs.writeFileSync("index.js", `export default {};`);
865865
await expect(
866-
runWrangler("dev --experimental-public abc --site xyz")
866+
runWrangler("dev --assets abc --site xyz")
867867
).rejects.toThrowErrorMatchingInlineSnapshot(
868-
`"Cannot use --experimental-public and a Site configuration together."`
868+
`"Cannot use Assets and Workers Sites in the same Worker."`
869869
);
870870
});
871871

872-
it("should error if --experimental-public and config.site are used together", async () => {
872+
it("should error if --assets and config.site are used together", async () => {
873873
writeWranglerToml({
874874
main: "./index.js",
875875
site: {
@@ -878,11 +878,56 @@ describe("wrangler dev", () => {
878878
});
879879
fs.writeFileSync("index.js", `export default {};`);
880880
await expect(
881-
runWrangler("dev --experimental-public abc")
881+
runWrangler("dev --assets abc")
882882
).rejects.toThrowErrorMatchingInlineSnapshot(
883-
`"Cannot use --experimental-public and a Site configuration together."`
883+
`"Cannot use Assets and Workers Sites in the same Worker."`
884884
);
885885
});
886+
887+
it("should error if config.assets and --site are used together", async () => {
888+
writeWranglerToml({
889+
main: "./index.js",
890+
assets: "abc",
891+
});
892+
fs.writeFileSync("index.js", `export default {};`);
893+
await expect(
894+
runWrangler("dev --site xyz")
895+
).rejects.toThrowErrorMatchingInlineSnapshot(
896+
`"Cannot use Assets and Workers Sites in the same Worker."`
897+
);
898+
});
899+
900+
it("should error if config.assets and config.site are used together", async () => {
901+
writeWranglerToml({
902+
main: "./index.js",
903+
assets: "abc",
904+
site: {
905+
bucket: "xyz",
906+
},
907+
});
908+
fs.writeFileSync("index.js", `export default {};`);
909+
await expect(
910+
runWrangler("dev --assets abc")
911+
).rejects.toThrowErrorMatchingInlineSnapshot(
912+
`"Cannot use Assets and Workers Sites in the same Worker."`
913+
);
914+
});
915+
916+
it("should indicate whether Sites is being used", async () => {
917+
writeWranglerToml({
918+
main: "index.js",
919+
});
920+
fs.writeFileSync("index.js", `export default {};`);
921+
922+
await runWrangler("dev");
923+
expect((Dev as jest.Mock).mock.calls[0][0].isWorkersSite).toEqual(false);
924+
925+
await runWrangler("dev --site abc");
926+
expect((Dev as jest.Mock).mock.calls[1][0].isWorkersSite).toEqual(true);
927+
928+
await runWrangler("dev --assets abc");
929+
expect((Dev as jest.Mock).mock.calls[2][0].isWorkersSite).toEqual(false);
930+
});
886931
});
887932

888933
describe("--inspect", () => {

packages/wrangler/src/__tests__/publish.test.ts

+125-12
Original file line numberDiff line numberDiff line change
@@ -1405,7 +1405,7 @@ addEventListener('fetch', event => {});`
14051405
expect(std.err).toMatchInlineSnapshot(`""`);
14061406
});
14071407

1408-
it("should upload all the files in the directory specified by `--experimental-public`", async () => {
1408+
it("should upload all the files in the directory specified by `--assets`", async () => {
14091409
const assets = [
14101410
{ filePath: "file-1.txt", content: "Content of file-1" },
14111411
{ filePath: "file-2.txt", content: "Content of file-2" },
@@ -1426,46 +1426,159 @@ addEventListener('fetch', event => {});`
14261426
mockListKVNamespacesRequest(kvNamespace);
14271427
mockKeyListRequest(kvNamespace.id, []);
14281428
mockUploadAssetsToKVRequest(kvNamespace.id, assets);
1429-
await runWrangler("publish --experimental-public assets");
1429+
await runWrangler("publish --assets assets");
14301430

1431-
expect(std.out).toMatchInlineSnapshot(`
1432-
"Reading file-1.txt...
1431+
expect(std).toMatchInlineSnapshot(`
1432+
Object {
1433+
"debug": "",
1434+
"err": "",
1435+
"out": "Reading file-1.txt...
14331436
Uploading as file-1.2ca234f380.txt...
14341437
Reading file-2.txt...
14351438
Uploading as file-2.5938485188.txt...
14361439
↗️ Done syncing assets
14371440
Uploaded test-name (TIMINGS)
14381441
Published test-name (TIMINGS)
1439-
test-name.test-sub-domain.workers.dev"
1442+
test-name.test-sub-domain.workers.dev",
1443+
"warn": "",
1444+
}
1445+
`);
1446+
});
1447+
1448+
it("should error when trying to use --assets with a service-worker Worker", async () => {
1449+
writeWranglerToml({
1450+
main: "./index.js",
1451+
});
1452+
writeWorkerSource({ type: "sw" });
1453+
await expect(
1454+
runWrangler("publish --assets abc")
1455+
).rejects.toThrowErrorMatchingInlineSnapshot(
1456+
`"You cannot use the service-worker format with an \`assets\` directory yet. For information on how to migrate to the module-worker format, see: https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/"`
1457+
);
1458+
1459+
expect(std).toMatchInlineSnapshot(`
1460+
Object {
1461+
"debug": "",
1462+
"err": "X [ERROR] You cannot use the service-worker format with an \`assets\` directory yet. For information on how to migrate to the module-worker format, see: https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/
1463+
1464+
",
1465+
"out": "
1466+
If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
1467+
"warn": "",
1468+
}
1469+
`);
1470+
});
1471+
1472+
it("should error if --assets and --site are used together", async () => {
1473+
writeWranglerToml({
1474+
main: "./index.js",
1475+
});
1476+
writeWorkerSource();
1477+
await expect(
1478+
runWrangler("publish --assets abc --site xyz")
1479+
).rejects.toThrowErrorMatchingInlineSnapshot(
1480+
`"Cannot use Assets and Workers Sites in the same Worker."`
1481+
);
1482+
1483+
expect(std).toMatchInlineSnapshot(`
1484+
Object {
1485+
"debug": "",
1486+
"err": "X [ERROR] Cannot use Assets and Workers Sites in the same Worker.
1487+
1488+
",
1489+
"out": "
1490+
If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
1491+
"warn": "",
1492+
}
14401493
`);
1441-
expect(std.err).toMatchInlineSnapshot(`""`);
14421494
});
14431495

1444-
it("should error if --experimental-public and --site are used together", async () => {
1496+
it("should error if --assets and config.site are used together", async () => {
14451497
writeWranglerToml({
14461498
main: "./index.js",
1499+
site: {
1500+
bucket: "xyz",
1501+
},
14471502
});
14481503
writeWorkerSource();
14491504
await expect(
1450-
runWrangler("publish --experimental-public abc --site xyz")
1505+
runWrangler("publish --assets abc")
14511506
).rejects.toThrowErrorMatchingInlineSnapshot(
1452-
`"Cannot use --experimental-public and a Site configuration together."`
1507+
`"Cannot use Assets and Workers Sites in the same Worker."`
14531508
);
1509+
1510+
expect(std).toMatchInlineSnapshot(`
1511+
Object {
1512+
"debug": "",
1513+
"err": "X [ERROR] Cannot use Assets and Workers Sites in the same Worker.
1514+
1515+
",
1516+
"out": "
1517+
If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
1518+
"warn": "",
1519+
}
1520+
`);
14541521
});
14551522

1456-
it("should error if --experimental-public and config.site are used together", async () => {
1523+
it("should error if config.assets and --site are used together", async () => {
14571524
writeWranglerToml({
14581525
main: "./index.js",
1526+
assets: "abc",
1527+
});
1528+
writeWorkerSource();
1529+
await expect(
1530+
runWrangler("publish --site xyz")
1531+
).rejects.toThrowErrorMatchingInlineSnapshot(
1532+
`"Cannot use Assets and Workers Sites in the same Worker."`
1533+
);
1534+
1535+
expect(std).toMatchInlineSnapshot(`
1536+
Object {
1537+
"debug": "",
1538+
"err": "X [ERROR] Cannot use Assets and Workers Sites in the same Worker.
1539+
1540+
",
1541+
"out": "
1542+
If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
1543+
"warn": "▲ [WARNING] Processing wrangler.toml configuration:
1544+
1545+
- \\"assets\\" fields are experimental and may change or break at any time.
1546+
1547+
",
1548+
}
1549+
`);
1550+
});
1551+
1552+
it("should error if config.assets and config.site are used together", async () => {
1553+
writeWranglerToml({
1554+
main: "./index.js",
1555+
assets: "abc",
14591556
site: {
14601557
bucket: "xyz",
14611558
},
14621559
});
14631560
writeWorkerSource();
14641561
await expect(
1465-
runWrangler("publish --experimental-public abc")
1562+
runWrangler("publish")
14661563
).rejects.toThrowErrorMatchingInlineSnapshot(
1467-
`"Cannot use --experimental-public and a Site configuration together."`
1564+
`"Cannot use Assets and Workers Sites in the same Worker."`
14681565
);
1566+
1567+
expect(std).toMatchInlineSnapshot(`
1568+
Object {
1569+
"debug": "",
1570+
"err": "X [ERROR] Cannot use Assets and Workers Sites in the same Worker.
1571+
1572+
",
1573+
"out": "
1574+
If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
1575+
"warn": "▲ [WARNING] Processing wrangler.toml configuration:
1576+
1577+
- \\"assets\\" fields are experimental and may change or break at any time.
1578+
1579+
",
1580+
}
1581+
`);
14691582
});
14701583

14711584
it("should not contain backslash for assets with nested directories", async () => {

packages/wrangler/src/config/config.ts

+9
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ export interface ConfigFields<Dev extends RawDevConfig> {
114114
}
115115
| undefined;
116116

117+
/**
118+
* Serve a folder of static assets with your Worker, without any additional code.
119+
* This can either be a string, or an object with additional config fields.
120+
*/
121+
assets:
122+
| string
123+
| { bucket: string; include: string[]; exclude: string[] }
124+
| undefined;
125+
117126
/**
118127
* A list of wasm modules that your worker should be bound to. This is
119128
* the "legacy" way of binding to a wasm module. ES module workers should

0 commit comments

Comments
 (0)