Skip to content

Commit 590d69b

Browse files
authored
Full build support for assets (#9510)
* Output build manifest for entry Worker environment * Temporarily disable the dev registry in preview mode * Always include assets field in output wrangler.json and remove post build if there are no assets * Use virtual module as dummy entry file when there are assets and no client entry * Added public only test * Move server assets to client build output and enable build tests * Refactoring * Improve tests * Added inline asset to assets playground * Reenable dev registry * Add changeset * Update changeset * Remove hasClientBuild * Remove redundant code * Add messages to assertions * Remove unnecessary fs.existsSync
1 parent b23fee6 commit 590d69b

File tree

21 files changed

+396
-100
lines changed

21 files changed

+396
-100
lines changed

.changeset/tidy-hoops-win.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
"@cloudflare/vite-plugin": minor
3+
---
4+
5+
Enhanced build support for Workers with assets.
6+
7+
Assets that are imported in the entry Worker are now automatically moved to the client build output. This enables importing assets in your Worker and accessing them via the [assets binding](https://developers.cloudflare.com/workers/static-assets/binding/#binding). See [Static Asset Handling](https://vite.dev/guide/assets) to find out about all the ways you can import assets in Vite.
8+
9+
Additionally, a broader range of build scenarios are now supported. These are:
10+
11+
- Assets only build with client entry/entries
12+
- Assets only build with no client entry/entries that includes `public` directory assets
13+
- Worker(s) + assets build with client entry/entries
14+
- Worker(s) + assets build with no client entry/entries that includes imported and/or `public` directory assets
15+
- Worker(s) build with no assets

packages/vite-plugin-cloudflare/playground/assets/__tests__/assets.spec.ts

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,6 @@
11
import { expect, test } from "vitest";
2-
import {
3-
getResponse,
4-
getTextResponse,
5-
isBuild,
6-
page,
7-
viteTestUrl,
8-
} from "../../__test-utils__";
9-
10-
test("fetches public directory asset", async () => {
11-
const response = await getResponse("/public-directory-asset");
12-
const contentType = await response.headerValue("content-type");
13-
const additionalHeader = await response.headerValue("additional-header");
14-
expect(contentType).toBe("image/svg+xml");
15-
expect(additionalHeader).toBe("public-directory-asset");
16-
});
17-
18-
// TODO: enable build test when assets are copied to client output directory
19-
test.skipIf(isBuild)("fetches imported asset", async () => {
20-
const response = await getResponse("/imported-asset");
21-
const contentType = await response.headerValue("content-type");
22-
const additionalHeader = await response.headerValue("additional-header");
23-
expect(contentType).toBe("image/svg+xml");
24-
expect(additionalHeader).toBe("imported-asset");
25-
});
26-
27-
// TODO: enable build test when assets are copied to client output directory
28-
test.skipIf(isBuild)("fetches imported asset with url suffix", async () => {
29-
const text = await getTextResponse("/imported-asset-url-suffix");
30-
expect(text).toBe(`The text content is "Text content"`);
31-
});
2+
import { page, viteTestUrl } from "../../__test-utils__";
3+
import "./base-tests";
324

335
test("fetches transformed HTML asset", async () => {
346
await page.goto(`${viteTestUrl}/transformed-html-asset`);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { expect, test } from "vitest";
2+
import { getResponse, getTextResponse } from "../../__test-utils__";
3+
4+
test("fetches public directory asset", async () => {
5+
const response = await getResponse("/public-directory-asset");
6+
const contentType = await response.headerValue("content-type");
7+
const additionalHeader = await response.headerValue("additional-header");
8+
expect(contentType).toBe("image/svg+xml");
9+
expect(additionalHeader).toBe("public-directory-asset");
10+
});
11+
12+
test("fetches imported asset", async () => {
13+
const response = await getResponse("/imported-asset");
14+
const contentType = await response.headerValue("content-type");
15+
const additionalHeader = await response.headerValue("additional-header");
16+
expect(contentType).toBe("image/svg+xml");
17+
expect(additionalHeader).toBe("imported-asset");
18+
});
19+
20+
test("fetches imported asset with url suffix", async () => {
21+
const text = await getTextResponse("/imported-asset-url-suffix");
22+
expect(text).toBe(`The text content is "Text content"`);
23+
});
24+
25+
test("fetches inline asset", async () => {
26+
const response = await getResponse("/inline-asset");
27+
const contentType = await response.headerValue("content-type");
28+
const additionalHeader = await response.headerValue("additional-header");
29+
expect(contentType).toBe("image/svg+xml");
30+
expect(additionalHeader).toBe("inline-asset");
31+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import * as fs from "node:fs";
2+
import * as path from "node:path";
3+
import { expect, test, vi } from "vitest";
4+
import { isBuild, testDir } from "../../../__test-utils__";
5+
import "../base-tests";
6+
7+
test.runIf(isBuild)("deletes fallback client entry file", async () => {
8+
const fallbackEntryPath = path.join(
9+
testDir,
10+
"dist",
11+
"client",
12+
"__cloudflare_fallback_entry__"
13+
);
14+
15+
await vi.waitFor(() => {
16+
expect(fs.existsSync(fallbackEntryPath)).toBe(false);
17+
});
18+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import * as fs from "node:fs";
2+
import * as path from "node:path";
3+
import { expect, test, vi } from "vitest";
4+
import { getResponse, isBuild, testDir } from "../../../__test-utils__";
5+
6+
test("fetches public directory asset", async () => {
7+
const response = await getResponse("/public-image.svg");
8+
const contentType = await response.headerValue("content-type");
9+
expect(contentType).toBe("image/svg+xml");
10+
});
11+
12+
test.runIf(isBuild)("deletes fallback client entry file", async () => {
13+
const fallbackEntryPath = path.join(
14+
testDir,
15+
"dist",
16+
"__cloudflare_fallback_entry__"
17+
);
18+
19+
await vi.waitFor(() => {
20+
expect(fs.existsSync(fallbackEntryPath)).toBe(false);
21+
});
22+
});
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
<!doctype html>
2-
<head>
3-
<title>HTML page</title>
4-
</head>
5-
<body>
6-
<h1>Original content</h1>
7-
</body>
2+
<html lang="en">
3+
<head>
4+
<title>HTML page</title>
5+
</head>
6+
<body>
7+
<h1>Original content</h1>
8+
</body>
9+
</html>

packages/vite-plugin-cloudflare/playground/assets/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
"private": true,
44
"type": "module",
55
"scripts": {
6-
"build": "vite build --app",
6+
"build": "vite build",
7+
"build:no-client-entry": "vite build -c vite.config.no-client-entry.ts",
8+
"build:public-dir-only": "vite build -c vite.config.public-dir-only.ts",
79
"check:types": "tsc --build",
810
"dev": "vite dev",
11+
"dev:no-client-entry": "vite dev -c vite.config.no-client-entry.ts",
12+
"dev:public-dir-only": "vite dev -c vite.config.public-dir-only.ts",
913
"preview": "vite preview"
1014
},
1115
"devDependencies": {

packages/vite-plugin-cloudflare/playground/assets/src/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
>Imported asset with URL query param</a
1212
>
1313
</li>
14+
<li><a href="/inline-asset">Inline asset</a></li>
1415
<li><a href="/transformed-html-asset">Transformed HTML asset</a></li>
1516
</ul>
1617
</body>

packages/vite-plugin-cloudflare/playground/assets/src/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import html from "./index.html?raw";
22
import importedImage from "./imported-image.svg";
33
import importedText from "./imported-text.txt?url";
4+
import inlineImage from "./inline-image.svg?inline";
45

56
interface Env {
67
ASSETS: Fetcher;
@@ -42,6 +43,13 @@ export default {
4243

4344
return new Response(`The text content is "${textContent}"`);
4445
}
46+
case "/inline-asset": {
47+
const response = await env.ASSETS.fetch(new URL(inlineImage, origin));
48+
const modifiedResponse = new Response(response.body, response);
49+
modifiedResponse.headers.append("additional-header", "inline-asset");
50+
51+
return modifiedResponse;
52+
}
4553
case "/transformed-html-asset": {
4654
const response = await env.ASSETS.fetch(new URL("/html-page", origin));
4755

Lines changed: 8 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)