Node integration for Vike.
With this extension, your server-side code is transpiled with Vite.
In development, the server process is restarted when a change is detected in some of your server files.
Installation
Standalone build
External packages
Caching and compression
Custom pageContext
Framework examples
Migration guide
-
npm install vike-node express
-
Extend
vite.config.js
:// vite.config.js import vikeNode from 'vike-node/plugin' export default { // ... plugins: [vikeNode('server/index.js')] }
-
Create
server/index.js
:// server/index.js import express from 'express' import vike from 'vike-node/connect' startServer() function startServer() { const app = express() app.use(vike()) const port = process.env.PORT || 3000 app.listen(port, () => console.log(`Server running at http://localhost:${port}`)) }
You can enable standalone builds by setting standalone
to true
.
After build, the output dist
folder will contain everything for a deployment.
With standalone mode, the production environment only needs the dist
folder to be present.
Example start script: NODE_ENV=production node dist/server/index.mjs
// vite.config.js
import vikeNode from 'vike-node/plugin'
export default {
// ...
plugins: [
vikeNode({
entry: 'server/index.js',
standalone: true
})
]
}
Packages that import native binaries/custom assets need to be added to external
.
When building with standalone
enabled, external
packages and their assets are copied to the output dist
directory.
By default, the external
setting includes:
sharp
@prisma/client
@node-rs/*
// vite.config.js
import vikeNode from 'vike-node/plugin'
export default {
// ...
plugins: [
vikeNode({
entry: 'server/index.js',
standalone: true,
external: ['my-rust-package']
})
]
}
In production, vike-node
:
- compresses all Vike responses
- caches the compressed static assets(.js, .css).
On a request, if the asset(.js, .css) is not in the cache, vike-node
compresses it with a fast compression level, sends it in the response, then recompresses it with a high compression level and finally caches the compressed data.
You can disable compression/caching:
app.use(
vike({
compress: false,
static: {
cache: false
}
})
)
Custom pageContext:
You can define custom pageContext properties:
app.use(
vike({
pageContext: (req) => ({
user: req.user
})
})
)
vike-node
includes middlewares for the most popular web frameworks:
- Express
- Fastify
- Hono
- H3
- Elysia (Bun)
Express:
// server/index.js
import express from 'express'
import vike from 'vike-node/connect'
startServer()
function startServer() {
const app = express()
app.use(vike())
const port = process.env.PORT || 3000
app.listen(port, () => console.log(`Server running at http://localhost:${port}`))
}
Fastify:
// server/index.js
import fastify from 'fastify'
import vike from 'vike-node/fastify'
startServer()
function startServer() {
const app = fastify()
app.register(vike())
const port = +(process.env.PORT || 3000)
app.listen({ port }, () => console.log(`Server running at http://localhost:${port}`))
}
Hono:
// server/index.js
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
import vike from 'vike-node/hono'
startServer()
function startServer() {
const app = new Hono()
app.use(vike())
const port = +(process.env.PORT || 3000)
serve(
{
fetch: app.fetch,
port
},
() => console.log(`Server running at http://localhost:${port}`)
)
}
H3:
// server/index.js
import { createApp, toNodeListener } from 'h3'
import { createServer } from 'http'
import vike from 'vike-node/h3'
startServer()
async function startServer() {
const app = createApp()
app.use(vike())
const port = process.env.PORT || 3000
const server = createServer(toNodeListener(app)).listen(port)
server.on('listening', () => {
console.log(`Server running at http://localhost:${port}`)
})
}
Elysia (Bun):
// server/index.js
import { Elysia } from 'elysia'
import vike from 'vike-node/elysia'
startServer()
function startServer() {
const app = new Elysia()
app.use(vike())
const port = +(process.env.PORT || 3000)
app.listen(port, () => console.log(`Server running at http://localhost:${port}`))
}
// server/index.js
- import { renderPage } from 'vike/server'
+ import { vike } from 'vike-node/connect'
- if (isProduction) {
- app.use(express.static(`${root}/dist/client`))
- } else {
- const vite = await import('vite')
- const viteDevMiddleware = (
- await vite.createServer({
- root,
- server: { middlewareMode: true }
- })
- ).middlewares
- app.use(viteDevMiddleware)
- }
- app.get('*', async (req, res, next) => {
- const pageContextInit = {
- urlOriginal: req.originalUrl
- }
- const pageContext = await renderPage(pageContextInit)
- const { httpResponse } = pageContext
- if (!httpResponse) {
- return next()
- } else {
- const { statusCode, headers } = httpResponse
- headers.forEach(([name, value]) => res.setHeader(name, value))
- res.status(statusCode)
- httpResponse.pipe(res)
- }
- })
+ app.use(vike())
// package.json
"scripts": {
- "dev": "node ./server",
+ "dev": "vite",
}