Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@

<!-- automd:examples -->

| Example | Source | Playground | Clone |
| --- | --- | --- | --- |
| `basic-service` | [examples/basic-service](./examples/basic-service/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/basic-service?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/basic-service basic-service-app` |
| `h3` | [examples/h3](./examples/h3/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/h3?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/h3 h3-app` |
| `hono` | [examples/hono](./examples/hono/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/hono?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/hono hono-app` |
| `node-compat` | [examples/node-compat](./examples/node-compat/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/node-compat?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/node-compat node-compat-app` |
| `react-ssr` | [examples/react-ssr](./examples/react-ssr/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/react-ssr?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/react-ssr react-ssr-app` |
| `solid-ssr` | [examples/solid-ssr](./examples/solid-ssr/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/solid-ssr?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/solid-ssr solid-ssr-app` |
| Example | Source | Playground | Clone |
| ---------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| `basic-service` | [examples/basic-service](./examples/basic-service/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/basic-service?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/basic-service basic-service-app` |
| `h3` | [examples/h3](./examples/h3/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/h3?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/h3 h3-app` |
| `hono` | [examples/hono](./examples/hono/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/hono?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/hono hono-app` |
| `node-compat` | [examples/node-compat](./examples/node-compat/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/node-compat?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/node-compat node-compat-app` |
| `react-ssr` | [examples/react-ssr](./examples/react-ssr/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/react-ssr?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/react-ssr react-ssr-app` |
| `solid-ssr` | [examples/solid-ssr](./examples/solid-ssr/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/solid-ssr?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/solid-ssr solid-ssr-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-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` |
| `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
20 changes: 20 additions & 0 deletions examples/vue-router-ssr/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "nitro-vite-vue-router-ssr",
"private": true,
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "NITRO_HOST=127.0.0.1 node .output/server/index.mjs"
},
"devDependencies": {
"@hiogawa/vite-plugin-fullstack": "0.0.2",
"@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.
1 change: 1 addition & 0 deletions examples/vue-router-ssr/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./src/framework/entry.server.ts";
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>
26 changes: 26 additions & 0 deletions examples/vue-router-ssr/src/framework/entry.client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
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");

if (import.meta.hot) {
// TODO
import.meta.hot.on("fullstack:update", (e) => {
console.log("[fullstack:update]", e);
window.location.reload();
});
}
}

main();
77 changes: 77 additions & 0 deletions examples/vue-router-ssr/src/framework/entry.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { mergeAssets } from "@hiogawa/vite-plugin-fullstack/runtime";
import { createHead, transformHtmlTemplate } from "unhead/server";
import { createSSRApp } from "vue";
import { RouterView, createMemoryHistory, createRouter } from "vue-router";
import { renderToString } from "vue/server-renderer";
import { routes } from "../routes";
import clientEntry from "./entry.client.ts?assets=client";

async function handler(request: Request): Promise<Response> {
// setup app
const app = createSSRApp(RouterView);

// setup vue-router
// https://github.com/nuxt/nuxt/blob/766806c8d90015873f86c3f103b09803bd214258/packages/nuxt/src/pages/runtime/plugins/router.ts
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();

// collect assets from current route
const assets = mergeAssets(
clientEntry,
...(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 }],
});

// SSR
const ssrStream = await renderToString(app);

// inject to HTML shell with head tags
let htmlStream = `\
<!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">${ssrStream}</div>
</body>
</html>
`;
htmlStream = await transformHtmlTemplate(head, htmlStream);

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

export default {
fetch: handler,
};

if (import.meta.hot) {
import.meta.hot.accept();
}
10 changes: 10 additions & 0 deletions examples/vue-router-ssr/src/framework/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")>;
}
}
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>
39 changes: 39 additions & 0 deletions examples/vue-router-ssr/src/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { RouteRecordRaw } from "vue-router";

// custom framework may employ fs router convention to reduce boilerplace.
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;
}
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", "@hiogawa/vite-plugin-fullstack/types"]
}
}
Loading