Skip to content

Commit 79c5578

Browse files
committed
chore: add nitro build example
1 parent 1a4a7bb commit 79c5578

File tree

4 files changed

+3204
-90
lines changed

4 files changed

+3204
-90
lines changed
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import {
2+
build,
3+
copyPublicAssets,
4+
createNitro,
5+
prepare,
6+
type NitroConfig,
7+
} from 'nitropack'
8+
import type { PresetName } from 'nitropack/presets'
9+
import type { Plugin, ViteBuilder } from 'vite'
10+
11+
// Using Nitro as post-build to target deployment platform. Inspired by Tanstack Start's approach.
12+
// https://github.com/TanStack/router/blob/5fd079e482b1252b8b11a936f1524a0dee368cae/packages/start-plugin-core/src/nitro-plugin/plugin.ts
13+
14+
// The goal is to replace framework's hand-written post-build scripts, such as
15+
// https://github.com/hi-ogawa/waku/blob/084c71a6d2450b4a69146e97b0005d59ee9394cd/packages/waku/src/vite-rsc/deploy/vercel/plugin.ts
16+
17+
type NitroPluginOptions = {
18+
preset: PresetName
19+
clientDir: string
20+
serverEntry: string
21+
}
22+
23+
export function nitroPlugin(nitroPluginOptions: NitroPluginOptions): Plugin[] {
24+
return [
25+
{
26+
name: 'nitro',
27+
apply: 'build',
28+
29+
// TODO: might want to reuse some platform specific resolution etc...
30+
configEnvironment() {
31+
return {
32+
resolve: {},
33+
}
34+
},
35+
36+
// reuse Nitro for post-build
37+
buildApp: {
38+
order: 'post',
39+
handler: async (builder) => {
40+
await buildNitroApp(builder, nitroPluginOptions)
41+
},
42+
},
43+
},
44+
]
45+
}
46+
47+
async function buildNitroApp(
48+
_builder: ViteBuilder,
49+
nitroPluginOptions: NitroPluginOptions,
50+
) {
51+
const nitroConfig: NitroConfig = {
52+
// ===
53+
// === essential features
54+
// ===
55+
preset: nitroPluginOptions.preset,
56+
publicAssets: [
57+
{
58+
dir: nitroPluginOptions.clientDir,
59+
baseURL: '/',
60+
maxAge: 31536000, // 1 year
61+
},
62+
],
63+
renderer: 'virtual:renderer-entry',
64+
rollupConfig: {
65+
plugins: [
66+
{
67+
name: 'virtual-server-entry',
68+
resolveId(source) {
69+
if (source === 'virtual:renderer-entry') {
70+
return '\0' + source
71+
}
72+
if (source === 'virtual:renderer-entry-inner') {
73+
return this.resolve(nitroPluginOptions.serverEntry)
74+
}
75+
},
76+
load(id) {
77+
if (id === '\0virtual:renderer-entry') {
78+
return `\
79+
import handler from 'virtual:renderer-entry-inner';
80+
import { defineEventHandler, toWebRequest } from "h3"
81+
export default defineEventHandler((event) => handler(toWebRequest(event)))
82+
`
83+
}
84+
},
85+
},
86+
// TODO: preserve server source maps
87+
// virtualBundlePlugin(getSsrBundle()),
88+
],
89+
},
90+
91+
// ===
92+
// === basic settings
93+
// ===
94+
buildDir: 'dist/nitro/build',
95+
output: { dir: 'dist/nitro/output' },
96+
97+
// ===
98+
// === disable other features
99+
// ===
100+
dev: false,
101+
// TODO: do we need this? should this be made configurable?
102+
compatibilityDate: '2024-11-19',
103+
// logLevel: 3,
104+
// baseURL: globalThis.TSS_APP_BASE,
105+
// TODO: how to avoid .nitro/types?
106+
typescript: {
107+
generateRuntimeConfigTypes: false,
108+
generateTsConfig: false,
109+
},
110+
prerender: undefined,
111+
plugins: [], // Nitro's plugins
112+
appConfigFiles: [],
113+
scanDirs: [],
114+
imports: false, // unjs/unimport for global/magic imports
115+
virtual: {
116+
// This is Nitro's way of defining virtual modules
117+
// Should we define the ones for TanStack Start's here as well?
118+
},
119+
}
120+
121+
const nitro = await createNitro(nitroConfig)
122+
await prepare(nitro)
123+
await copyPublicAssets(nitro)
124+
await prerender()
125+
await build(nitro)
126+
await nitro.close()
127+
128+
// TODO
129+
async function prerender() {}
130+
}

packages/plugin-rsc/examples/react-router/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"@types/react": "^19.1.8",
2727
"@types/react-dom": "^19.1.6",
2828
"@vitejs/plugin-react": "latest",
29+
"h3": "^1.15.3",
30+
"nitropack": "^2.11.13",
2931
"tailwindcss": "^4.1.11",
3032
"vite": "^7.0.2",
3133
"vite-plugin-inspect": "^11.3.0",

packages/plugin-rsc/examples/react-router/vite.config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import react from '@vitejs/plugin-react'
44
import { defineConfig } from 'vite'
55
import inspect from 'vite-plugin-inspect'
66
import { reactRouter } from './react-router-vite/plugin'
7+
import { nitroPlugin } from './nitro'
8+
import path from 'path'
79

810
export default defineConfig({
911
clearScreen: false,
@@ -26,6 +28,14 @@ export default defineConfig({
2628
},
2729
}),
2830
inspect(),
31+
!!process.env.NITRO_PRESET &&
32+
nitroPlugin({
33+
preset: process.env.NITRO_PRESET as any,
34+
// TODO: this can be inferred from config, such as
35+
// - builder.environments.client.config.build.outDir
36+
clientDir: path.resolve('./dist/client'),
37+
serverEntry: path.resolve('./dist/ssr/index.js'),
38+
}),
2939
],
3040
optimizeDeps: {
3141
include: ['react-router', 'react-router/internal/react-server-client'],

0 commit comments

Comments
 (0)