Skip to content

Commit

Permalink
Allow Workers Assets to be mounted to a path
Browse files Browse the repository at this point in the history
  • Loading branch information
WalshyDev committed Dec 10, 2024
1 parent 75be0d5 commit d2da9e6
Show file tree
Hide file tree
Showing 6 changed files with 309 additions and 141 deletions.
7 changes: 7 additions & 0 deletions .changeset/early-baboons-fly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": minor
---

feat: allow routing to Workers with Assets on any HTTP route, not just the root. For example, `example.com/blog/*` can now be used to serve assets.
These assets will be served as though the assets directly were mounted to the root.
For example, if you have `asset.directory = "./public/"` then `./public/blog/logo.png` will be available at `example.com/blog/logo.png`. Assets outside of directories which match the configured HTTP routes can still be accessed with the [Assets binding](https://developers.cloudflare.com/workers/static-assets/binding/#binding) or with a [Service binding](https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/) to this Worker.
321 changes: 248 additions & 73 deletions packages/wrangler/src/__tests__/deploy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1600,95 +1600,270 @@ Update them to point to this script instead?`,
});
});

it("should error on routes with paths if assets are present", async () => {
writeWranglerConfig({
routes: [
"simple.co.uk/path",
"simple.co.uk/path/*",
"simple.co.uk/",
"simple.co.uk/*",
"simple.co.uk",
{ pattern: "route.co.uk/path", zone_id: "asdfadsf" },
{ pattern: "route.co.uk/path/*", zone_id: "asdfadsf" },
{ pattern: "route.co.uk/*", zone_id: "asdfadsf" },
{ pattern: "route.co.uk/", zone_id: "asdfadsf" },
{ pattern: "route.co.uk", zone_id: "asdfadsf" },
{ pattern: "custom.co.uk/path", custom_domain: true },
{ pattern: "custom.co.uk/*", custom_domain: true },
{ pattern: "custom.co.uk", custom_domain: true },
],
describe("deploy asset routes", () => {
it("shouldn't error on routes with paths if there are no assets", async () => {
writeWranglerConfig({
routes: [
"simple.co.uk/path",
"simple.co.uk/path/*",
"simple.co.uk/",
"simple.co.uk/*",
"simple.co.uk",
{ pattern: "route.co.uk/path", zone_id: "asdfadsf" },
{ pattern: "route.co.uk/path/*", zone_id: "asdfadsf" },
{ pattern: "route.co.uk/*", zone_id: "asdfadsf" },
{ pattern: "route.co.uk/", zone_id: "asdfadsf" },
{ pattern: "route.co.uk", zone_id: "asdfadsf" },
{ pattern: "custom.co.uk/path", custom_domain: true },
{ pattern: "custom.co.uk/*", custom_domain: true },
{ pattern: "custom.co.uk", custom_domain: true },
],
});
writeWorkerSource();

await expect(runWrangler(`deploy ./index`)).rejects
.toThrowErrorMatchingInlineSnapshot(`
[Error: Invalid Routes:
custom.co.uk/path:
Paths are not allowed in Custom Domains
custom.co.uk/*:
Wildcard operators (*) are not allowed in Custom Domains
Paths are not allowed in Custom Domains]
`);
});
writeWorkerSource();
writeAssets([{ filePath: "asset.txt", content: "Content of file-1" }]);

await expect(runWrangler(`deploy --assets="assets"`)).rejects
.toThrowErrorMatchingInlineSnapshot(`
[Error: Invalid Routes:
simple.co.uk/path:
Workers which have static assets cannot be routed on a URL which has a path component. Update the route to replace /path with /*
it("should warn on mounted paths", async () => {
writeWranglerConfig({
routes: [
"simple.co.uk/path/*",
"simple.co.uk/*",
"*/*",
"*/blog/*",
{ pattern: "example.com/blog/*", zone_id: "asdfadsf" },
{ pattern: "example.com/*", zone_id: "asdfadsf" },
{ pattern: "example.com/abc/def/*", zone_id: "asdfadsf" },
],
});
await mockAUSRequest([]);
mockSubDomainRequest();
mockUpdateWorkerSubdomain({ enabled: false, previews_enabled: true });
mockUploadWorkerRequest({
expectedAssets: {
jwt: "<<aus-completion-token>>",
config: {},
},
expectedType: "none",
});
mockPublishRoutesRequest({
routes: [
// @ts-expect-error - this is what is expected
{
pattern: "simple.co.uk/path/*",
},
// @ts-expect-error - this is what is expected
{
pattern: "simple.co.uk/*",
},
// @ts-expect-error - this is what is expected
{
pattern: "*/*",
},
// @ts-expect-error - this is what is expected
{
pattern: "*/blog/*",
},
{
pattern: "example.com/blog/*",
zone_id: "asdfadsf",
},
{
pattern: "example.com/*",
zone_id: "asdfadsf",
},
{
pattern: "example.com/abc/def/*",
zone_id: "asdfadsf",
},
],
});

simple.co.uk/path/*:
Workers which have static assets cannot be routed on a URL which has a path component. Update the route to replace /path/* with /*
writeWorkerSource();
writeAssets([{ filePath: "asset.txt", content: "Content of file-1" }]);

await runWrangler(`deploy --assets assets`);

simple.co.uk/:
Workers which have static assets must end with a wildcard path. Update the route to end with /*
expect(std.warn).toMatchInlineSnapshot(`
"[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mWarning: The following routes will attempt to serve Assets on a mounted path:[0m
simple.co.uk:
Workers which have static assets must end with a wildcard path. Update the route to end with /*
• simple.co.uk/path/* (Will match assets: assets/path/*)
• */blog/* (Will match assets: assets/blog/*)
• example.com/blog/* (Will match assets: assets/blog/*)
• example.com/abc/def/* (Will match assets: assets/abc/def/*)
route.co.uk/path:
Workers which have static assets cannot be routed on a URL which has a path component. Update the route to replace /path with /*
"
`);
expect(std.out).toMatchInlineSnapshot(`
"Total Upload: xx KiB / gzip: xx KiB
Worker Startup Time: 100 ms
Uploaded test-name (TIMINGS)
Deployed test-name triggers (TIMINGS)
simple.co.uk/path/*
simple.co.uk/*
*/*
*/blog/*
example.com/blog/* (zone id: asdfadsf)
example.com/* (zone id: asdfadsf)
example.com/abc/def/* (zone id: asdfadsf)
Current Version ID: Galaxy-Class"
`);
});

route.co.uk/path/*:
Workers which have static assets cannot be routed on a URL which has a path component. Update the route to replace /path/* with /*
it("assets only will not mention invoking Worker on 404", async () => {
writeWranglerConfig({
routes: [
{ pattern: "example.com/blog/*", zone_id: "asdfadsf" },
{ pattern: "example.com/*", zone_id: "asdfadsf" },
{ pattern: "example.com/abc/def/*", zone_id: "asdfadsf" },
],
assets: {
directory: "assets",
},
});
await mockAUSRequest([]);
mockSubDomainRequest();
mockUpdateWorkerSubdomain({ enabled: false, previews_enabled: true });
mockUploadWorkerRequest({
expectedAssets: {
jwt: "<<aus-completion-token>>",
config: {},
},
expectedType: "none",
});
mockPublishRoutesRequest({
routes: [
{
pattern: "example.com/blog/*",
zone_id: "asdfadsf",
},
{
pattern: "example.com/*",
zone_id: "asdfadsf",
},
{
pattern: "example.com/abc/def/*",
zone_id: "asdfadsf",
},
],
});

route.co.uk/:
Workers which have static assets must end with a wildcard path. Update the route to end with /*
writeAssets([{ filePath: "asset.txt", content: "Content of file-1" }]);

route.co.uk:
Workers which have static assets must end with a wildcard path. Update the route to end with /*
await runWrangler(`deploy`);

custom.co.uk/path:
Paths are not allowed in Custom Domains
expect(std.warn).toMatchInlineSnapshot(`
"[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mWarning: The following routes will attempt to serve Assets on a mounted path:[0m
custom.co.uk/*:
Wildcard operators (*) are not allowed in Custom Domains
Paths are not allowed in Custom Domains]
`);
});
• example.com/blog/* (Will match assets: assets/blog/*)
• example.com/abc/def/* (Will match assets: assets/abc/def/*)
it("shouldn't error on routes with paths if there are no assets", async () => {
writeWranglerConfig({
routes: [
"simple.co.uk/path",
"simple.co.uk/path/*",
"simple.co.uk/",
"simple.co.uk/*",
"simple.co.uk",
{ pattern: "route.co.uk/path", zone_id: "asdfadsf" },
{ pattern: "route.co.uk/path/*", zone_id: "asdfadsf" },
{ pattern: "route.co.uk/*", zone_id: "asdfadsf" },
{ pattern: "route.co.uk/", zone_id: "asdfadsf" },
{ pattern: "route.co.uk", zone_id: "asdfadsf" },
{ pattern: "custom.co.uk/path", custom_domain: true },
{ pattern: "custom.co.uk/*", custom_domain: true },
{ pattern: "custom.co.uk", custom_domain: true },
],
"
`);
expect(std.out).toMatchInlineSnapshot(`
"Total Upload: xx KiB / gzip: xx KiB
Worker Startup Time: 100 ms
Uploaded test-name (TIMINGS)
Deployed test-name triggers (TIMINGS)
example.com/blog/* (zone id: asdfadsf)
example.com/* (zone id: asdfadsf)
example.com/abc/def/* (zone id: asdfadsf)
Current Version ID: Galaxy-Class"
`);
});
writeWorkerSource();

await expect(runWrangler(`deploy ./index`)).rejects
.toThrowErrorMatchingInlineSnapshot(`
[Error: Invalid Routes:
custom.co.uk/path:
Paths are not allowed in Custom Domains
it("should not warn on mounted paths if serve_directly = true", async () => {
writeWranglerConfig({
routes: [
"simple.co.uk/path/*",
"simple.co.uk/*",
"*/*",
"*/blog/*",
{ pattern: "example.com/blog/*", zone_id: "asdfadsf" },
{ pattern: "example.com/*", zone_id: "asdfadsf" },
{ pattern: "example.com/abc/def/*", zone_id: "asdfadsf" },
],
assets: {
directory: "assets",
experimental_serve_directly: true,
},
});
await mockAUSRequest([]);
mockSubDomainRequest();
mockUpdateWorkerSubdomain({ enabled: false, previews_enabled: true });
mockUploadWorkerRequest({
expectedAssets: {
jwt: "<<aus-completion-token>>",
config: {
serve_directly: true,
},
},
expectedType: "none",
});
mockPublishRoutesRequest({
routes: [
// @ts-expect-error - this is what is expected
{
pattern: "simple.co.uk/path/*",
},
// @ts-expect-error - this is what is expected
{
pattern: "simple.co.uk/*",
},
// @ts-expect-error - this is what is expected
{
pattern: "*/*",
},
// @ts-expect-error - this is what is expected
{
pattern: "*/blog/*",
},
{
pattern: "example.com/blog/*",
zone_id: "asdfadsf",
},
{
pattern: "example.com/*",
zone_id: "asdfadsf",
},
{
pattern: "example.com/abc/def/*",
zone_id: "asdfadsf",
},
],
});

custom.co.uk/*:
Wildcard operators (*) are not allowed in Custom Domains
Paths are not allowed in Custom Domains]
`);
});
writeWorkerSource();
writeAssets([{ filePath: "asset.txt", content: "Content of file-1" }]);

await runWrangler(`deploy`);

expect(std.warn).toMatchInlineSnapshot(`""`);
expect(std.out).toMatchInlineSnapshot(`
"Total Upload: xx KiB / gzip: xx KiB
Worker Startup Time: 100 ms
Uploaded test-name (TIMINGS)
Deployed test-name triggers (TIMINGS)
simple.co.uk/path/*
simple.co.uk/*
*/*
*/blog/*
example.com/blog/* (zone id: asdfadsf)
example.com/* (zone id: asdfadsf)
example.com/abc/def/* (zone id: asdfadsf)
Current Version ID: Galaxy-Class"
`);
});
});
it.todo("should error if it's a workers.dev route");
});

Expand Down
Loading

0 comments on commit d2da9e6

Please sign in to comment.