Skip to content

Commit e910e36

Browse files
authored
chore(fullstack): add ssg example (#1184)
~e2e is failing. It looks like `srvx` (preview server) isn't killed properly between tests.~ Fixed by using `tree-kill` https://github.com/pkrumins/node-tree-kill
1 parent 5c72aa8 commit e910e36

File tree

13 files changed

+215
-16
lines changed

13 files changed

+215
-16
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"react-dom": "^19.1.0",
3131
"react-server-dom-webpack": "^19.1.0",
3232
"tinyexec": "^1.0.1",
33+
"tree-kill": "^1.2.2",
3334
"tsdown": "^0.12.9",
3435
"typescript": "^5.8.3",
3536
"vite": "^7.1.5",

packages/fullstack/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
This is a proposal to introduce a new API to allow non-client environment to access assets information commonly required for SSR.
66

7-
Currently, it is prototyped in my package `@hiogawa/vite-plugin-fullstack` and it provides `import.meta.vite.assets` function with a following signature:
7+
Currently, it is prototyped in my package `@hiogawa/vite-plugin-fullstack`, which provides `import.meta.vite.assets` function with a following signature:
88

99
```ts
1010
function assets({
@@ -134,7 +134,7 @@ See [./examples](./examples) for concrete usages.
134134
| --- | --- |
135135
| [Basic](./examples/basic/) | [stackblitz](https://stackblitz.com/github/hi-ogawa/vite-plugins/tree/main/packages/fullstack/examples/basic) |
136136
| [React Router](./examples/react-router/) | [stackblitz](https://stackblitz.com/github/hi-ogawa/vite-plugins/tree/main/packages/fullstack/examples/react-router) |
137-
| [Vue Router](./examples/vue-router/) | [stackblitz](https://stackblitz.com/github/hi-ogawa/vite-plugins/tree/main/packages/fullstack/examples/vue-router) |
137+
| [Vue Router / SSG](./examples/vue-router/) | [stackblitz](https://stackblitz.com/github/hi-ogawa/vite-plugins/tree/main/packages/fullstack/examples/vue-router) |
138138
| [Nitro](https://github.com/hi-ogawa/nitro-vite-examples/tree/10-02-feat_add_vue-router-ssr_example/examples/vue-router-ssr) | [stackblitz](https://stackblitz.com/github/hi-ogawa/nitro-vite-examples/tree/10-02-feat_add_vue-router-ssr_example/examples/vue-router-ssr) |
139139
| [Cloudflare](./examples/cloudflare/) | - |
140140

packages/fullstack/e2e/fixture.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import assert from "node:assert";
2-
import { type SpawnOptions, spawn } from "node:child_process";
2+
import { type SpawnOptions } from "node:child_process";
33
import fs from "node:fs";
44
import path from "node:path";
55
import { stripVTControlCharacters, styleText } from "node:util";
66
import test from "@playwright/test";
77
import { x } from "tinyexec";
8+
import treeKill from "tree-kill"; // need to kill srvx's worker process
89

910
function runCli(options: { command: string; label?: string } & SpawnOptions) {
1011
const [name, ...args] = options.command.split(" ");
@@ -43,11 +44,7 @@ function runCli(options: { command: string; label?: string } & SpawnOptions) {
4344
}
4445

4546
function kill() {
46-
if (process.platform === "win32") {
47-
spawn("taskkill", ["/pid", String(child.pid), "/t", "/f"]);
48-
} else {
49-
child.kill();
50-
}
47+
treeKill(child.pid!);
5148
}
5249

5350
return { proc: child, done, findPort, kill };

packages/fullstack/e2e/helper.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ export async function waitForHydration(page: Page, selector = "body") {
1313
.evaluate(
1414
(el) =>
1515
el &&
16-
Object.keys(el).some((key) => key.startsWith("__reactFiber")),
16+
Object.keys(el).some(
17+
(key) =>
18+
key.startsWith("__reactFiber") ||
19+
key.startsWith("__vue_app__"),
20+
),
1721
),
1822
{ timeout: 3000 },
1923
)
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { expect, test } from "@playwright/test";
2+
import { type Fixture, useFixture } from "./fixture";
3+
import { expectNoReload, waitForHydration } from "./helper";
4+
5+
test.describe("dev", () => {
6+
const f = useFixture({ root: "examples/vue-router", mode: "dev" });
7+
defineTest(f);
8+
});
9+
10+
test.describe("build", () => {
11+
const f = useFixture({ root: "examples/vue-router", mode: "build" });
12+
defineTest(f);
13+
});
14+
15+
test.describe("build ssg", () => {
16+
const f = useFixture({
17+
root: "examples/vue-router",
18+
mode: "build",
19+
command: "pnpm preview-ssg",
20+
buildCommand: "pnpm build-ssg",
21+
});
22+
defineTest(f);
23+
});
24+
25+
function defineTest(f: Fixture) {
26+
test("basic", async ({ page }) => {
27+
await page.goto(f.url());
28+
await using _ = await expectNoReload(page);
29+
30+
const errors: Error[] = [];
31+
page.on("pageerror", (error) => {
32+
errors.push(error);
33+
});
34+
35+
// hydration
36+
await waitForHydration(page, "#root");
37+
expect(errors).toEqual([]); // no hydration mismatch
38+
39+
// client
40+
await expect(page.locator(".counter-card")).toContainText("Count: 0");
41+
await page.getByRole("button", { name: "Increment" }).click();
42+
await expect(page.locator(".counter-card")).toContainText("Count: 1");
43+
44+
// css
45+
// - styles.css
46+
await expect(page.getByRole("button", { name: "Increment" })).toHaveCSS(
47+
"background-color",
48+
"rgb(83, 91, 242)",
49+
);
50+
// - index.vue (scoped css)
51+
await expect(
52+
page.getByRole("heading", { name: "Vue Router Custom Framework" }),
53+
).toHaveCSS("color", "rgb(100, 108, 255)");
54+
55+
expect(errors).toEqual([]);
56+
});
57+
58+
// TODO: hmr
59+
}

packages/fullstack/examples/basic/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"scripts": {
66
"dev": "vite dev",
77
"build": "vite build",
8-
"preview": "srvx -s ../client dist/ssr/index.js"
8+
"preview": "srvx --prod -s ../client dist/ssr/index.js"
99
},
1010
"devDependencies": {
1111
"@hiogawa/vite-plugin-fullstack": "latest",

packages/fullstack/examples/island/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"scripts": {
66
"dev": "vite dev",
77
"build": "vite build",
8-
"preview": "srvx -s ../client dist/ssr/index.js"
8+
"preview": "srvx --prod -s ../client dist/ssr/index.js"
99
},
1010
"devDependencies": {
1111
"@hiogawa/vite-plugin-fullstack": "latest",

packages/fullstack/examples/react-router/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"scripts": {
66
"dev": "vite dev",
77
"build": "vite build",
8-
"preview": "srvx -s ../client dist/ssr/index.js"
8+
"preview": "srvx --prod -s ../client dist/ssr/index.js"
99
},
1010
"devDependencies": {
1111
"@hiogawa/vite-plugin-fullstack": "latest",

packages/fullstack/examples/vue-router/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
"scripts": {
66
"dev": "vite dev",
77
"build": "vite build",
8-
"preview": "srvx -s ../client dist/ssr/index.js"
8+
"preview": "srvx --prod -s ../client dist/ssr/index.js",
9+
"build-ssg": "TEST_SSG=1 vite build",
10+
"preview-ssg": "TEST_SSG=1 sirv dist/client"
911
},
1012
"devDependencies": {
1113
"@hiogawa/vite-plugin-fullstack": "latest",
1214
"@unhead/vue": "^2.0.17",
1315
"@vitejs/plugin-vue": "^6.0.1",
16+
"sirv-cli": "^3.0.1",
1417
"srvx": "^0.8.7",
1518
"vite": "^7.1.5",
1619
"vite-plugin-devtools-json": "^1.0.0",

packages/fullstack/examples/vue-router/src/routes/index.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ function increment() {
3131
}
3232
3333
.hero h1 {
34-
color: #646cff;
34+
color: rgb(100, 108, 255);
3535
}
3636
3737
.counter-card {

0 commit comments

Comments
 (0)