Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c77f353
feat: add vue-router-ssr example
hi-ogawa Oct 2, 2025
e3cedad
chore: cleanup
hi-ogawa Oct 2, 2025
b38da74
chore: cleanup
hi-ogawa Oct 2, 2025
ffd7bf9
chore: cleanup
hi-ogawa Oct 2, 2025
97726ba
chore(deps): update to fix vue scoped css hmr
hi-ogawa Oct 2, 2025
8a1281e
cleanup
hi-ogawa Oct 2, 2025
42a3774
chore: tweak demo
hi-ogawa Oct 2, 2025
aab87ca
chore: use npm package
hi-ogawa Oct 3, 2025
774f47f
fix: use `asEntry`
hi-ogawa Oct 3, 2025
9c6e351
chore: remove @tsconfig/strictest
hi-ogawa Oct 3, 2025
34e1386
chore: use alpha release
hi-ogawa Oct 3, 2025
91ca0c9
chore(deps): alpha.2
hi-ogawa Oct 4, 2025
d1ffc47
chore(deps): update to `?assets` query
hi-ogawa Oct 4, 2025
bf7e121
chore: alpha.3
hi-ogawa Oct 5, 2025
4aaae44
chore: 0.0.0
hi-ogawa Oct 5, 2025
6f59a73
chore: update nitro-nightly + fix server build
hi-ogawa Oct 5, 2025
6177edd
chore: lint
hi-ogawa Oct 5, 2025
f1c481a
chore: use `nitro` environment
hi-ogawa Oct 5, 2025
6c4c1d6
chore: update 0.0.2
hi-ogawa Oct 8, 2025
b6efc13
Merge branch 'main' into 10-02-feat_add_vue-router-ssr_example
pi0 Oct 15, 2025
9b9ed1c
update to working state
pi0 Oct 15, 2025
9610255
chore(deps): update https://github.com/nitrojs/nitro/pull/3662
hi-ogawa Oct 16, 2025
4502fdb
test: add test
hi-ogawa Oct 16, 2025
e12f786
test: fix cwd for client entry on dev
hi-ogawa Oct 16, 2025
10e5dca
fix: fix base
hi-ogawa Oct 16, 2025
b05563a
test: tweak timeout
hi-ogawa Oct 16, 2025
3278967
chore: cleanup
hi-ogawa Oct 16, 2025
f4fd234
chore: test pr
hi-ogawa Oct 16, 2025
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
| `standard` | [examples/standard](./examples/standard/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/standard?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/standard standard-app` |
| `tanstack-router-react` | [examples/tanstack-router-react](./examples/tanstack-router-react/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/tanstack-router-react?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/tanstack-router-react tanstack-router-react-app` |
| `tanstack-start-react` | [examples/tanstack-start-react](./examples/tanstack-start-react/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/tanstack-start-react?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/tanstack-start-react tanstack-start-react-app` |
| `vue-router-ssr` | [examples/vue-router-ssr](./examples/vue-router-ssr/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/vue-router-ssr?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/vue-router-ssr vue-router-ssr-app` |
| `vue-ssr` | [examples/vue-ssr](./examples/vue-ssr/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/vue-ssr?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/vue-ssr vue-ssr-app` |

<!-- /automd -->
Expand Down
5 changes: 5 additions & 0 deletions examples/vue-router-ssr/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dist
node_modules
*.tsbuildinfo
.output
.nitro
1 change: 1 addition & 0 deletions examples/vue-router-ssr/api/hello.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => "API Works!";
19 changes: 19 additions & 0 deletions examples/vue-router-ssr/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "nitro-vite-vue-router-ssr",
"private": true,
"type": "module",
"scripts": {
"build": "vite build",
"dev": "vite dev",
"preview": "vite preview"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.1",
"nitro": "npm:nitro-nightly",
"unhead": "^2.0.17",
"vite": "^7",
"vite-plugin-devtools-json": "^1.0.0",
"vue": "^3.5.22",
"vue-router": "^4.5.1"
}
}
Binary file added examples/vue-router-ssr/public/favicon.ico
Binary file not shown.
49 changes: 49 additions & 0 deletions examples/vue-router-ssr/src/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script setup lang="ts">
import { RouterLink, RouterView } from "vue-router";
import "./styles.css";
</script>

<template>
<nav>
<ul>
<li>
<RouterLink to="/" exact-active-class="active">Home</RouterLink>
</li>
<li>
<RouterLink to="/about" active-class="active">About</RouterLink>
</li>
</ul>
</nav>
<RouterView />
</template>

<style scoped>
nav {
background: white;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
padding: 1rem;
}

nav ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
gap: 2rem;
max-width: 800px;
margin: 0 auto;
}

nav a {
color: #666;
text-decoration: none;
}

nav a:hover {
color: #333;
}

nav a.active {
color: #646cff;
}
</style>
14 changes: 14 additions & 0 deletions examples/vue-router-ssr/src/entry-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createSSRApp } from "vue";
import { RouterView, createRouter, createWebHistory } from "vue-router";
import { routes } from "./routes";

async function main() {
const app = createSSRApp(RouterView);
const router = createRouter({ history: createWebHistory(), routes });
app.use(router);

await router.isReady();
app.mount("#root");
}

main();
65 changes: 65 additions & 0 deletions examples/vue-router-ssr/src/entry-server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { createSSRApp } from "vue";
import { renderToString } from "vue/server-renderer";
import { RouterView, createMemoryHistory, createRouter } from "vue-router";

import { createHead, transformHtmlTemplate } from "unhead/server";

import { routes } from "./routes";
import clientEntry from "./entry-client.ts?assets=client";

async function handler(request: Request): Promise<Response> {
const app = createSSRApp(RouterView);
const router = createRouter({ history: createMemoryHistory(), routes });
app.use(router);

const url = new URL(request.url);
const href = url.href.slice(url.origin.length);

await router.push(href);
await router.isReady();

const assets = clientEntry.merge(
...(await Promise.all(
router.currentRoute.value.matched
.map((to) => to.meta.assets)
.filter(Boolean)
.map((fn) => fn!().then((m) => m.default)),
)),
);

const head = createHead();

head.push({
link: [
...assets.css.map((attrs) => ({ rel: "stylesheet", ...attrs })),
...assets.js.map((attrs) => ({ rel: "modulepreload", ...attrs })),
],
script: [{ type: "module", src: clientEntry.entry }],
});

const renderedApp = await renderToString(app);

const html = await transformHtmlTemplate(head, htmlTemplate(renderedApp));

return new Response(html, {
headers: { "Content-Type": "text/html;charset=utf-8" },
});
}

function htmlTemplate(body: string): string {
return /* html */ `\<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue Router Custom Framework</title>
</head>
<body>
<div id="root">${body}</div>
</body>
</html>`;
}

export default {
fetch: handler,
};
11 changes: 11 additions & 0 deletions examples/vue-router-ssr/src/pages/about.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<template>
<main>
<h1>About</h1>
<div class="card">
<p>
This is a simple Vue Router demo app built with Vite Plugin Fullstack.
</p>
<p>It demonstrates basic routing and server-side rendering.</p>
</div>
</main>
</template>
49 changes: 49 additions & 0 deletions examples/vue-router-ssr/src/pages/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script setup lang="ts">
import { ref } from "vue";

const count = ref(0);

function increment() {
count.value++;
}
</script>

<template>
<main>
<div class="hero">
<h1>Vue Router Custom Framework</h1>
<p class="subtitle">A simple demo app with Vite</p>
</div>

<div class="card counter-card">
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</main>
</template>

<style scoped>
.hero {
text-align: center;
margin-bottom: 2rem;
}

.hero h1 {
color: rgb(100, 108, 255);
}

.counter-card {
text-align: center;
}

.counter-card h2 {
color: #646cff;
margin-bottom: 1rem;
}

.counter-card p {
font-size: 1.5rem;
font-weight: bold;
margin: 1rem 0;
}
</style>
5 changes: 5 additions & 0 deletions examples/vue-router-ssr/src/pages/not-found.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<main>
<h1>Not Found 404</h1>
</main>
</template>
38 changes: 38 additions & 0 deletions examples/vue-router-ssr/src/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { RouteRecordRaw } from "vue-router";

export const routes: RouteRecordRaw[] = [
{
path: "/",
name: "app",
component: () => import("./app.vue"),
meta: {
assets: () => import("./app.vue?assets"),
},
children: [
{
path: "/",
name: "home",
component: () => import("./pages/index.vue"),
meta: {
assets: () => import("./pages/index.vue?assets"),
},
},
{
path: "/about",
name: "about",
component: () => import("./pages/about.vue"),
meta: {
assets: () => import("./pages/about.vue?assets"),
},
},
{
path: "/:catchAll(.*)",
name: "not-found",
component: () => import("./pages/not-found.vue"),
meta: {
assets: () => import("./pages/not-found.vue?assets"),
},
},
],
},
];
49 changes: 49 additions & 0 deletions examples/vue-router-ssr/src/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
* {
box-sizing: border-box;
}

body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: #f5f5f5;
color: #333;
}

main {
max-width: 800px;
margin: 0 auto;
padding: 2rem;
}

h1 {
font-size: 2.5rem;
margin-bottom: 0.5rem;
}

.card {
background: white;
border-radius: 8px;
padding: 2rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
margin: 2rem 0;
}

button {
background: rgb(83, 91, 242);
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
}

button:hover {
background: #535bf2;
}

.subtitle {
color: #666;
font-size: 1.1rem;
margin-bottom: 2rem;
}
10 changes: 10 additions & 0 deletions examples/vue-router-ssr/src/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// https://router.vuejs.org/guide/advanced/meta.html#TypeScript
import "vue-router";

export {};

declare module "vue-router" {
interface RouteMeta {
assets?: () => Promise<typeof import("*?assets")>;
}
}
18 changes: 18 additions & 0 deletions examples/vue-router-ssr/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"include": ["src", "*.ts", "src/**/*.vue"],
"compilerOptions": {
"erasableSyntaxOnly": true,
"allowImportingTsExtensions": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"skipLibCheck": true,
"verbatimModuleSyntax": true,
"noEmit": true,
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ESNext",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"types": ["vite/client"]
}
}
31 changes: 31 additions & 0 deletions examples/vue-router-ssr/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import vue from "@vitejs/plugin-vue";
import { defineConfig, type Plugin } from "vite";
import devtoolsJson from "vite-plugin-devtools-json";
import { nitro } from "nitro/vite";

export default defineConfig((_env) => ({
clearScreen: false,
plugins: [patchVueExclude(vue(), /\?assets/), devtoolsJson(), nitro()],
environments: {
client: {
build: {
rollupOptions: { input: "./src/entry-client.ts" },
},
},
ssr: {
build: {
rollupOptions: { input: "./src/entry-server.ts" },
},
},
},
}));

// Workaround https://github.com/vitejs/vite-plugin-vue/issues/677
function patchVueExclude(plugin: Plugin, exclude: RegExp) {
const original = (plugin.transform as any).handler;
(plugin.transform as any).handler = function (this: any, ...args: any[]) {
if (exclude.test(args[1])) return;
return original.call(this, ...args);
};
return plugin;
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"lint:fix": "automd && prettier -w ."
},
"resolutions": {
"nitro": "npm:nitro-nightly@3.0.1-20251015-103211-44b2f091",
"nitro": "https://pkg.pr.new/nitrojs/nitro@e6a242a",
"vite": "^7.1.0"
},
"devDependencies": {
Expand Down
Loading