Skip to content

Commit

Permalink
feat: --assets / config.assets to serve a folder of static assets
Browse files Browse the repository at this point in the history
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
  • Loading branch information
threepointone committed Jun 17, 2022
1 parent 35482da commit fdcb02f
Show file tree
Hide file tree
Showing 14 changed files with 422 additions and 86 deletions.
9 changes: 9 additions & 0 deletions .changeset/wise-steaks-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"wrangler": patch
---

feat: `--assets` / `config.assets` to serve a folder of static assets

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 https://github.com/cloudflare/wrangler2/issues/1162
61 changes: 61 additions & 0 deletions packages/wrangler/src/__tests__/configuration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,67 @@ describe("normalizeAndValidateConfig()", () => {
});
});

describe("assets", () => {
it("should error if `assets` config is missing `bucket`", () => {
const expectedConfig: RawConfig = {
// @ts-expect-error we're intentionally passing an invalid configuration here
assets: {
include: ["INCLUDE_1", "INCLUDE_2"],
exclude: ["EXCLUDE_1", "EXCLUDE_2"],
},
};

const { config, diagnostics } = normalizeAndValidateConfig(
expectedConfig,
undefined,
{ env: undefined }
);

expect(config).toEqual(expect.objectContaining(expectedConfig));
expect(diagnostics.hasWarnings()).toBe(true);
expect(diagnostics.hasErrors()).toBe(true);

expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
"Processing wrangler configuration:
- \\"assets\\" fields are experimental and may change or break at any time."
`);
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
"Processing wrangler configuration:
- \\"assets.bucket\\" is a required field."
`);
});

it("should error on invalid `assets` values", () => {
const expectedConfig = {
assets: {
bucket: "BUCKET",
include: [222, 333],
exclude: [444, 555],
},
};

const { config, diagnostics } = normalizeAndValidateConfig(
expectedConfig as unknown as RawConfig,
undefined,
{ env: undefined }
);

expect(config).toEqual(expect.objectContaining(expectedConfig));
expect(diagnostics.hasWarnings()).toBe(true);
expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
"Processing wrangler configuration:
- \\"assets\\" fields are experimental and may change or break at any time."
`);
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
"Processing wrangler configuration:
- Expected \\"assets.include.[0]\\" to be of type string but got 222.
- Expected \\"assets.include.[1]\\" to be of type string but got 333.
- Expected \\"assets.exclude.[0]\\" to be of type string but got 444.
- Expected \\"assets.exclude.[1]\\" to be of type string but got 555."
`);
});
});

it("should map `wasm_module` paths from relative to the config path to relative to the cwd", () => {
const expectedConfig: RawConfig = {
wasm_modules: {
Expand Down
61 changes: 53 additions & 8 deletions packages/wrangler/src/__tests__/dev.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ describe("wrangler dev", () => {
});
});

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

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

it("should error if --experimental-public and config.site are used together", async () => {
it("should error if --assets and config.site are used together", async () => {
writeWranglerToml({
main: "./index.js",
site: {
Expand All @@ -878,11 +878,56 @@ describe("wrangler dev", () => {
});
fs.writeFileSync("index.js", `export default {};`);
await expect(
runWrangler("dev --experimental-public abc")
runWrangler("dev --assets abc")
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Cannot use --experimental-public and a Site configuration together."`
`"Cannot use Assets and Workers Sites in the same Worker."`
);
});

it("should error if config.assets and --site are used together", async () => {
writeWranglerToml({
main: "./index.js",
assets: "abc",
});
fs.writeFileSync("index.js", `export default {};`);
await expect(
runWrangler("dev --site xyz")
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Cannot use Assets and Workers Sites in the same Worker."`
);
});

it("should error if config.assets and config.site are used together", async () => {
writeWranglerToml({
main: "./index.js",
assets: "abc",
site: {
bucket: "xyz",
},
});
fs.writeFileSync("index.js", `export default {};`);
await expect(
runWrangler("dev --assets abc")
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Cannot use Assets and Workers Sites in the same Worker."`
);
});

it("should indicate whether Sites is being used", async () => {
writeWranglerToml({
main: "index.js",
});
fs.writeFileSync("index.js", `export default {};`);

await runWrangler("dev");
expect((Dev as jest.Mock).mock.calls[0][0].isWorkersSite).toEqual(false);

await runWrangler("dev --site abc");
expect((Dev as jest.Mock).mock.calls[1][0].isWorkersSite).toEqual(true);

await runWrangler("dev --assets abc");
expect((Dev as jest.Mock).mock.calls[2][0].isWorkersSite).toEqual(false);
});
});

describe("--inspect", () => {
Expand Down
137 changes: 125 additions & 12 deletions packages/wrangler/src/__tests__/publish.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1405,7 +1405,7 @@ addEventListener('fetch', event => {});`
expect(std.err).toMatchInlineSnapshot(`""`);
});

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

expect(std.out).toMatchInlineSnapshot(`
"Reading file-1.txt...
expect(std).toMatchInlineSnapshot(`
Object {
"debug": "",
"err": "",
"out": "Reading file-1.txt...
Uploading as file-1.2ca234f380.txt...
Reading file-2.txt...
Uploading as file-2.5938485188.txt...
↗️ Done syncing assets
Uploaded test-name (TIMINGS)
Published test-name (TIMINGS)
test-name.test-sub-domain.workers.dev"
test-name.test-sub-domain.workers.dev",
"warn": "",
}
`);
});

it("should error when trying to use --assets with a service-worker Worker", async () => {
writeWranglerToml({
main: "./index.js",
});
writeWorkerSource({ type: "sw" });
await expect(
runWrangler("publish --assets abc")
).rejects.toThrowErrorMatchingInlineSnapshot(
`"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/"`
);

expect(std).toMatchInlineSnapshot(`
Object {
"debug": "",
"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/
",
"out": "
If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
"warn": "",
}
`);
});

it("should error if --assets and --site are used together", async () => {
writeWranglerToml({
main: "./index.js",
});
writeWorkerSource();
await expect(
runWrangler("publish --assets abc --site xyz")
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Cannot use Assets and Workers Sites in the same Worker."`
);

expect(std).toMatchInlineSnapshot(`
Object {
"debug": "",
"err": "X [ERROR] Cannot use Assets and Workers Sites in the same Worker.
",
"out": "
If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
"warn": "",
}
`);
expect(std.err).toMatchInlineSnapshot(`""`);
});

it("should error if --experimental-public and --site are used together", async () => {
it("should error if --assets and config.site are used together", async () => {
writeWranglerToml({
main: "./index.js",
site: {
bucket: "xyz",
},
});
writeWorkerSource();
await expect(
runWrangler("publish --experimental-public abc --site xyz")
runWrangler("publish --assets abc")
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Cannot use --experimental-public and a Site configuration together."`
`"Cannot use Assets and Workers Sites in the same Worker."`
);

expect(std).toMatchInlineSnapshot(`
Object {
"debug": "",
"err": "X [ERROR] Cannot use Assets and Workers Sites in the same Worker.
",
"out": "
If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
"warn": "",
}
`);
});

it("should error if --experimental-public and config.site are used together", async () => {
it("should error if config.assets and --site are used together", async () => {
writeWranglerToml({
main: "./index.js",
assets: "abc",
});
writeWorkerSource();
await expect(
runWrangler("publish --site xyz")
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Cannot use Assets and Workers Sites in the same Worker."`
);

expect(std).toMatchInlineSnapshot(`
Object {
"debug": "",
"err": "X [ERROR] Cannot use Assets and Workers Sites in the same Worker.
",
"out": "
If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
"warn": "▲ [WARNING] Processing wrangler.toml configuration:
- \\"assets\\" fields are experimental and may change or break at any time.
",
}
`);
});

it("should error if config.assets and config.site are used together", async () => {
writeWranglerToml({
main: "./index.js",
assets: "abc",
site: {
bucket: "xyz",
},
});
writeWorkerSource();
await expect(
runWrangler("publish --experimental-public abc")
runWrangler("publish")
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Cannot use --experimental-public and a Site configuration together."`
`"Cannot use Assets and Workers Sites in the same Worker."`
);

expect(std).toMatchInlineSnapshot(`
Object {
"debug": "",
"err": "X [ERROR] Cannot use Assets and Workers Sites in the same Worker.
",
"out": "
If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
"warn": "▲ [WARNING] Processing wrangler.toml configuration:
- \\"assets\\" fields are experimental and may change or break at any time.
",
}
`);
});

it("should not contain backslash for assets with nested directories", async () => {
Expand Down
9 changes: 9 additions & 0 deletions packages/wrangler/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,15 @@ export interface ConfigFields<Dev extends RawDevConfig> {
}
| undefined;

/**
* Serve a folder of static assets with your Worker, without any additional code.
* This can either be a string, or an object with additional config fields.
*/
assets:
| string
| { bucket: string; include: string[]; exclude: string[] }
| undefined;

/**
* A list of wasm modules that your worker should be bound to. This is
* the "legacy" way of binding to a wasm module. ES module workers should
Expand Down
Loading

0 comments on commit fdcb02f

Please sign in to comment.