Vite plugin to develop Vue SSR apps
pnpm install vite-plugin-vue-ssr -D
Install devalue if you need to hydrate the state
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueSsr from 'vite-plugin-vue-ssr/plugin'
import { fileURLToPath } from 'node:url'
export default defineConfig({
plugins: [
vue(),
vueSsr(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
})
Add the build commands to your package.json
file.
{
"scripts": {
"dev": "vite",
"build": "pnpm run build:client && pnpm run build:server",
"build:client": "vite build --ssrManifest --outDir dist/client",
"build:server": "vite build --ssr src/main.ts --outDir dist/server"
}
}
This will build a client and server bundle.
Use the vite
command to start a SSR enabled dev server.
Disabling SSR in vite will enable to build a SPA version.
The main.ts
file should export the imported vueSSR function.
import { vueSSR } from 'vite-plugin-vue-ssr'
import App from '@/App.vue'
const Counter = () => import('@/Counter.vue')
const routes = [
{
path: '/',
name: 'counter',
component: Counter,
}
]
export default vueSSR(App, { routes })
Pinia/Vuex is supported by using the app
and state
property inside the callback.
export default vueSSR(App, { routes }, ({ app, state }) => {
const pinia = createPinia()
app.use(pinia)
if (import.meta.env.SSR) {
state.value = pinia.state.value
} else {
pinia.state.value = state.value
}
})
The state will be persisted on
window.__INITIAL_STATE__
property and serialized usingdevalue
It's possible to make changes to the router, use the router
property in the callback.
const routes = [
{
path: '/',
name: 'counter',
component: Counter,
},
]
export default vueSSR(App, { routes }, ({ router }) => {
router.beforeEach(async (to, from) => {
if (
!isAuthenticated &&
to.name !== 'Login'
) {
return { name: 'Login' }
}
})
})
To customize the router, just return the router instance.
The routes
parameter is omitted, because we create a fresh router instance in the method.
export default vueSSR(App, {}, async ({ app }) => {
const router = createRouter({
history: import.meta.env.SSR ? createMemoryHistory('/') : createWebHistory('/'),
routes: [
{
path: '/',
name: 'counter',
component: Counter,
},
],
})
return {
router,
}
})
H3 is the underlaying server. During development it injects as an middleware.
The event
param is used to access the H3 composables.
NOTE: only works in SSR
import { getRequestURL } from 'h3'
export default vueSSR(App, { routes }, ({ event }) => {
if (import.meta.env.SSR) {
console.log(getRequestURL(event)) // "https://example.com/path"
}
console.log(event) // undefined
})
In a Vue component, use the useH3Event()
composable
import { useH3Event } from 'vite-plugin-vue-ssr'
import { getRequestURL } from 'h3'
if (import.meta.env.SSR) {
const event = useH3Event()
console.log(getRequestURL(event)) // "https://example.com/path"
}
See https://h3.unjs.io/utils for more composables.
Using Teleport
is supported, but requires a little bit of setup. Targeting body
is not supported (in SSR), use #teleports
instead.
<template>
<Teleport to="#teleports">
<button @click="store.increment">Increment</button>
</Teleport>
</template>
During SSR, the Teleport component will be rendered as a div
with the id
set to the to
property.
MIT