Skip to content

Commit fc820e8

Browse files
feat: add error messages for missing build cache (denoland#2551)
1 parent 28eca25 commit fc820e8

File tree

8 files changed

+89
-12
lines changed

8 files changed

+89
-12
lines changed

deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"screenshot": "deno run -A www/utils/screenshot.ts",
1616
"check:types": "deno check src/**/*.ts src/**/*.tsx tests/**/*.ts tests/**/*.tsx update/**/*.ts plugin-tailwindcss/**/*.ts init/**/*.ts",
1717
"ok": "deno fmt --check && deno lint && deno task check:types && deno task test",
18-
"test:www": "deno test -A tests/www/",
18+
"test:www": "deno test -A www/main_test.*",
1919
"release": "deno run -A tools/release.ts"
2020
},
2121
"exclude": ["**/_fresh/*", "**/tmp/*", "*/tests_OLD/**"],

deno.lock

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

init/src/init_test.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { expect } from "@std/expect";
22
import { initProject, InitStep, type MockTTY } from "./init.ts";
33
import * as path from "@std/path";
4-
import { withBrowser } from "../../tests/test_utils.tsx";
4+
import { getStdOutput, withBrowser } from "../../tests/test_utils.tsx";
55
import { waitForText } from "../../tests/test_utils.tsx";
66
import { withChildProcessServer } from "../../tests/test_utils.tsx";
77

@@ -194,7 +194,7 @@ Deno.test("init - can start dev server", async () => {
194194
});
195195
});
196196

197-
Deno.test("init - can start build project", async () => {
197+
Deno.test("init - can start built project", async () => {
198198
await withTmpDir(async (dir) => {
199199
const mock = mockUserInput({
200200
[InitStep.ProjectName]: ".",
@@ -227,3 +227,29 @@ Deno.test("init - can start build project", async () => {
227227
);
228228
});
229229
});
230+
231+
Deno.test("init - errors on missing build cache in prod", async () => {
232+
await withTmpDir(async (dir) => {
233+
const mock = mockUserInput({
234+
[InitStep.ProjectName]: ".",
235+
});
236+
await initProject(dir, [], {}, mock.tty);
237+
await expectProjectFile(dir, "main.ts");
238+
await expectProjectFile(dir, "dev.ts");
239+
240+
await patchProject(dir);
241+
242+
const cp = await new Deno.Command(Deno.execPath(), {
243+
args: ["run", "-A", "main.ts"],
244+
stdin: "null",
245+
stdout: "piped",
246+
stderr: "piped",
247+
cwd: dir,
248+
}).output();
249+
250+
const { stderr } = getStdOutput(cp);
251+
expect(cp.code).toEqual(1);
252+
253+
expect(stderr).toMatch(/Found 1 islands, but did not/);
254+
});
255+
});

src/app.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,10 @@ export class App<State> {
171171
(request: Request, info?: Deno.ServeHandlerInfo) => Promise<Response>
172172
> {
173173
if (this.#buildCache === null) {
174-
this.#buildCache = await ProdBuildCache.fromSnapshot(this.config);
174+
this.#buildCache = await ProdBuildCache.fromSnapshot(
175+
this.config,
176+
this.#islandRegistry.size,
177+
);
175178
}
176179

177180
if (

src/app_test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect } from "@std/expect";
2-
import { App, setBuildCache } from "./app.ts";
2+
import { App, getIslandRegistry, setBuildCache } from "./app.ts";
33
import { FakeServer } from "./test_utils.ts";
44
import { ProdBuildCache } from "./build_cache.ts";
55

@@ -429,7 +429,7 @@ Deno.test.ignore("FreshApp - finish setup", async () => {
429429
build: {
430430
outDir: "foo",
431431
},
432-
}),
432+
}, getIslandRegistry(app).size),
433433
);
434434

435435
const server = new FakeServer(await app.handler());

src/build_cache.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as path from "@std/path";
22
import type { ResolvedFreshConfig } from "./config.ts";
3-
import { setBuildId } from "./runtime/build_id.ts";
3+
import { DENO_DEPLOYMENT_ID, setBuildId } from "./runtime/build_id.ts";
4+
import * as colors from "@std/fmt/colors";
45

56
export interface FileSnapshot {
67
generated: boolean;
@@ -28,7 +29,7 @@ export interface BuildCache {
2829
}
2930

3031
export class ProdBuildCache implements BuildCache {
31-
static async fromSnapshot(config: ResolvedFreshConfig) {
32+
static async fromSnapshot(config: ResolvedFreshConfig, islandCount: number) {
3233
const snapshotPath = path.join(config.build.outDir, "snapshot.json");
3334

3435
const staticFiles = new Map<string, FileSnapshot>();
@@ -53,8 +54,29 @@ export class ProdBuildCache implements BuildCache {
5354
const pathname = islands[i];
5455
islandToChunk.set(pathname, snapshot.islands[pathname]);
5556
}
57+
58+
if (!DENO_DEPLOYMENT_ID) {
59+
// deno-lint-ignore no-console
60+
console.log(
61+
`Found snapshot at ${colors.cyan(snapshotPath)}`,
62+
);
63+
}
5664
} catch (err) {
57-
if (!(err instanceof Deno.errors.NotFound)) {
65+
if ((err instanceof Deno.errors.NotFound)) {
66+
if (islandCount > 0) {
67+
throw new Error(
68+
`Found ${
69+
colors.green(`${islandCount} islands`)
70+
}, but did not find build snapshot at:\n${
71+
colors.red(snapshotPath)
72+
}.\n\nMaybe your forgot to run ${
73+
colors.cyan("deno task build")
74+
} before starting the production server\nor maybe you wanted to run ${
75+
colors.cyan("deno task dev")
76+
} to spin up a development server instead?\n`,
77+
);
78+
}
79+
} else {
5880
throw err;
5981
}
6082
}

tests/test_utils.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { App, setBuildCache } from "../src/app.ts";
1+
import { App, getIslandRegistry, setBuildCache } from "../src/app.ts";
22
import { launch, type Page } from "@astral/astral";
33
import * as colors from "@std/fmt/colors";
44
import { type Document, DOMParser, HTMLElement } from "linkedom";
@@ -66,7 +66,10 @@ export async function buildProd(app: App<unknown>) {
6666
app.config.build.outDir = outDir;
6767
const builder = new Builder({});
6868
await builder.build(app);
69-
const cache = await ProdBuildCache.fromSnapshot(app.config);
69+
const cache = await ProdBuildCache.fromSnapshot(
70+
app.config,
71+
getIslandRegistry(app).size,
72+
);
7073
setBuildCache(app, cache);
7174
}
7275

www/main_test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import { buildProd, withBrowserApp } from "../tests/test_utils.tsx";
44
import { expect } from "@std/expect";
55
import { retry } from "@std/async/retry";
66

7+
await buildProd(app);
78
const handler = await app.handler();
89

910
Deno.test("CORS should not set on GET /fresh-badge.svg", async () => {
1011
const req = new Request("http://localhost/fresh-badge.svg");
11-
await buildProd(app);
1212
const resp = await handler(req);
1313
await resp?.body?.cancel();
1414

0 commit comments

Comments
 (0)