Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Jun 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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