Vite Setup
The biggest requirement is a vite setup that generates SSR manifests so the server knows what client chunks are generated so it can reference them.
import { defineConfig, UserConfig } from "vite";
export default defineConfig({
ssr: {
noExternal: ['vite'],
},
build: {
target: "esnext",
rollupOptions: {
input: 'app/entry.client.ts'
},
outDir: 'dist/client',
assetsDir: 'dist/asset',
ssrEmitAssets: true,
manifest: true
},
plugins: []
});
The second requirement is that you define a client, and server entry point for compilation to work effectively
import { GenerateRouteTree } from 'htmx-router/router';
export const tree = GenerateRouteTree({
modules: import.meta.glob('./routes/**/*.{ts,tsx}', { eager: true }),
scope: "./routes",
});
// vite complains if the client entry doesn't have a default export
export default {};
Plugins
There are also two optional plugins provided by htmx-router for vite, with both being optional, however ClientIsland
is required if you plan on using client islands
import { BundleSplitter, ClientIsland } from "htmx-router/vite";
import { defineConfig, UserConfig } from "vite";
export default defineConfig({
// same as before
plugins: [
ClientIsland("react"),
BundleSplitter()
],
});
We also recommend using tsconfig paths to make ~
resolve to ./app/
, that way as you move your route files around you do not have to change your relative imports.
{
"compilerOptions": {
"paths": { "~/*": ["./app/*"] },
"noEmit": true // Vite takes care of building everything, not tsc
}
}
Bundle Splitter
The bundle splitter will omit certain code from the client and server builds, if a file ends with .client.tsx
(also supports .ts
, .js
.jsx
) then it will be omitted from the server bundled, and likewise if it ends with .server.tsx
for the client.
This can be helpful to ensure certain code never leaks into the client. Or that expensive client side rendering for interactivity it processed on the server.
Client Island
This plugin will intercept imports for your app/manifest.tsx
within vite and instead will import either the server side hydration code, or the client side manifest for hydration based on which mode is being built.
Build Scripts
Since there is a client and a server build being generated, we recommend making a build setup like below so everything can be streamlined