Skip to content

Commit d9019b5

Browse files
committed
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` (and adds `--assets-include and `--assets-exclude` for parity with Sites. Via #1162
1 parent f8a21ed commit d9019b5

File tree

12 files changed

+272
-56
lines changed

12 files changed

+272
-56
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` (and adds `--assets-include and `--assets-exclude` for parity with Sites.
8+
9+
Via https://github.com/cloudflare/wrangler2/issues/1162

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

+53
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,59 @@ 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(false);
433+
expect(diagnostics.hasErrors()).toBe(true);
434+
435+
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
436+
"Processing wrangler configuration:
437+
- \\"assets.bucket\\" is a required field."
438+
`);
439+
});
440+
441+
it("should error on invalid `assets` values", () => {
442+
const expectedConfig = {
443+
assets: {
444+
bucket: "BUCKET",
445+
include: [222, 333],
446+
exclude: [444, 555],
447+
},
448+
};
449+
450+
const { config, diagnostics } = normalizeAndValidateConfig(
451+
expectedConfig as unknown as RawConfig,
452+
undefined,
453+
{ env: undefined }
454+
);
455+
456+
expect(config).toEqual(expect.objectContaining(expectedConfig));
457+
expect(diagnostics.hasWarnings()).toBe(false);
458+
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
459+
"Processing wrangler configuration:
460+
- Expected \\"assets.include.[0]\\" to be of type string but got 222.
461+
- Expected \\"assets.include.[1]\\" to be of type string but got 333.
462+
- Expected \\"assets.exclude.[0]\\" to be of type string but got 444.
463+
- Expected \\"assets.exclude.[1]\\" to be of type string but got 555."
464+
`);
465+
});
466+
});
467+
415468
it("should map `wasm_module` paths from relative to the config path to relative to the cwd", () => {
416469
const expectedConfig: RawConfig = {
417470
wasm_modules: {

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,9 @@ 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]
843+
--assets-include Array of .gitignore-style patterns that match file or directory names from the assets directory. Only matched items will be uploaded. [array]
844+
--assets-exclude Array of .gitignore-style patterns that match file or directory names from the assets directory. Matched items will not be uploaded. [array]
843845
--site Root folder of static assets for Workers Sites [string]
844846
--site-include Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded. [array]
845847
--site-exclude Array of .gitignore-style patterns that match file or directory names from the sites directory. Matched items will not be uploaded. [array]

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

packages/wrangler/src/config/validation.ts

+30
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ export function normalizeAndValidateConfig(
186186
rawConfig,
187187
activeEnv.main
188188
),
189+
assets: normalizeAndValidateAssets(diagnostics, configPath, rawConfig),
189190
wasm_modules: normalizeAndValidateModulePaths(
190191
diagnostics,
191192
configPath,
@@ -562,6 +563,35 @@ function normalizeAndValidateSite(
562563
return undefined;
563564
}
564565

566+
/**
567+
* Validate the `assets` configuration and return normalized values.
568+
*/
569+
function normalizeAndValidateAssets(
570+
diagnostics: Diagnostics,
571+
configPath: string | undefined,
572+
rawConfig: RawConfig
573+
) {
574+
if (
575+
typeof rawConfig?.assets === "string" ||
576+
rawConfig?.assets === undefined
577+
) {
578+
return rawConfig?.assets;
579+
}
580+
581+
const { bucket, include = [], exclude = [], ...rest } = rawConfig.assets;
582+
583+
validateAdditionalProperties(diagnostics, "assets", Object.keys(rest), []);
584+
validateRequiredProperty(diagnostics, "assets", "bucket", bucket, "string");
585+
validateTypedArray(diagnostics, "assets.include", include, "string");
586+
validateTypedArray(diagnostics, "assets.exclude", exclude, "string");
587+
588+
return {
589+
bucket,
590+
include,
591+
exclude,
592+
};
593+
}
594+
565595
/**
566596
* Map the paths of the `wasm_modules`, `text_blobs` or `data_blobs` configuration to be relative to the current working directory.
567597
*/

packages/wrangler/src/dev/dev.tsx

+13-7
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export type DevProps = {
3939
enableLocalPersistence: boolean;
4040
bindings: CfWorkerInit["bindings"];
4141
crons: Config["triggers"]["crons"];
42-
public: string | undefined;
42+
isWorkersSite: boolean;
4343
assetPaths: AssetPaths | undefined;
4444
compatibilityDate: string;
4545
compatibilityFlags: string[] | undefined;
@@ -62,9 +62,13 @@ export function DevImplementation(props: DevProps): JSX.Element {
6262

6363
useCustomBuild(props.entry, props.build);
6464

65-
if (props.public && props.entry.format === "service-worker") {
65+
if (
66+
!props.isWorkersSite &&
67+
props.assetPaths &&
68+
props.entry.format === "service-worker"
69+
) {
6670
throw new Error(
67-
"You cannot use the service-worker format with a `public` directory."
71+
"You cannot use the service-worker format with an `assets` directory."
6872
);
6973
}
7074

@@ -89,11 +93,13 @@ export function DevImplementation(props: DevProps): JSX.Element {
8993
const bundle = useEsbuild({
9094
entry: props.entry,
9195
destination: directory,
92-
staticRoot: props.public,
96+
staticRoot: props.isWorkersSite
97+
? undefined
98+
: props.assetPaths?.assetDirectory,
9399
jsxFactory: props.jsxFactory,
94100
rules: props.rules,
95101
jsxFragment: props.jsxFragment,
96-
serveAssetsFromWorker: !!props.public,
102+
serveAssetsFromWorker: Boolean(!props.isWorkersSite && props.assetPaths),
97103
tsconfig: props.tsconfig,
98104
minify: props.minify,
99105
nodeCompat: props.nodeCompat,
@@ -161,7 +167,7 @@ function DevSession(props: DevSessionProps) {
161167
compatibilityFlags={props.compatibilityFlags}
162168
bindings={props.bindings}
163169
assetPaths={props.assetPaths}
164-
public={props.public}
170+
isWorkersSite={props.isWorkersSite}
165171
port={props.port}
166172
ip={props.ip}
167173
rules={props.rules}
@@ -177,7 +183,7 @@ function DevSession(props: DevSessionProps) {
177183
accountId={props.accountId}
178184
bindings={props.bindings}
179185
assetPaths={props.assetPaths}
180-
public={props.public}
186+
isWorkersSite={props.isWorkersSite}
181187
port={props.port}
182188
ip={props.ip}
183189
localProtocol={props.localProtocol}

packages/wrangler/src/dev/local.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ interface LocalProps {
2222
compatibilityFlags: string[] | undefined;
2323
bindings: CfWorkerInit["bindings"];
2424
assetPaths: AssetPaths | undefined;
25-
public: string | undefined;
25+
isWorkersSite: boolean;
2626
port: number;
2727
ip: string;
2828
rules: Config["rules"];
@@ -49,7 +49,7 @@ function useLocalWorker({
4949
compatibilityFlags,
5050
bindings,
5151
assetPaths,
52-
public: publicDirectory,
52+
isWorkersSite,
5353
port,
5454
rules,
5555
enableLocalPersistence,
@@ -82,9 +82,9 @@ function useLocalWorker({
8282
abortSignal: abortController.signal,
8383
});
8484

85-
if (publicDirectory) {
85+
if (!isWorkersSite && assetPaths) {
8686
throw new Error(
87-
'⎔ A "public" folder is not yet supported in local mode.'
87+
'⎔ An "assets" folder is not yet supported in local mode.'
8888
);
8989
}
9090
if (bindings.services && bindings.services.length > 0) {
@@ -307,7 +307,7 @@ function useLocalWorker({
307307
compatibilityFlags,
308308
localPersistencePath,
309309
assetPaths,
310-
publicDirectory,
310+
isWorkersSite,
311311
rules,
312312
bindings.wasm_modules,
313313
bindings.text_blobs,

packages/wrangler/src/dev/remote.tsx

+8-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export function Remote(props: {
1616
name: string | undefined;
1717
bundle: EsbuildBundle | undefined;
1818
format: CfScriptFormat | undefined;
19-
public: string | undefined;
19+
isWorkersSite: boolean;
2020
assetPaths: AssetPaths | undefined;
2121
port: number;
2222
ip: string;
@@ -40,6 +40,7 @@ export function Remote(props: {
4040
accountId: props.accountId,
4141
bindings: props.bindings,
4242
assetPaths: props.assetPaths,
43+
isWorkersSite: props.isWorkersSite,
4344
port: props.port,
4445
compatibilityDate: props.compatibilityDate,
4546
compatibilityFlags: props.compatibilityFlags,
@@ -52,7 +53,9 @@ export function Remote(props: {
5253

5354
usePreviewServer({
5455
previewToken,
55-
publicRoot: props.public,
56+
assetDirectory: props.isWorkersSite
57+
? undefined
58+
: props.assetPaths?.assetDirectory,
5659
localProtocol: props.localProtocol,
5760
localPort: props.port,
5861
ip: props.ip,
@@ -74,6 +77,7 @@ export function useWorker(props: {
7477
accountId: string | undefined;
7578
bindings: CfWorkerInit["bindings"];
7679
assetPaths: AssetPaths | undefined;
80+
isWorkersSite: boolean;
7781
port: number;
7882
compatibilityDate: string | undefined;
7983
compatibilityFlags: string[] | undefined;
@@ -131,7 +135,7 @@ export function useWorker(props: {
131135
// include it in the kv namespace name regardless (since there's no
132136
// concept of service environments for kv namespaces yet).
133137
name + (!props.legacyEnv && props.env ? `-${props.env}` : ""),
134-
assetPaths,
138+
props.isWorkersSite ? assetPaths : undefined,
135139
true,
136140
false
137141
); // TODO: cancellable?
@@ -223,6 +227,7 @@ export function useWorker(props: {
223227
accountId,
224228
port,
225229
assetPaths,
230+
props.isWorkersSite,
226231
compatibilityDate,
227232
compatibilityFlags,
228233
usageModel,

0 commit comments

Comments
 (0)