Vue 3+

npm i fastify fastify-vite fastify-vite-vue --save

Minimal Boilerplate

Below is a minimal script to boot a Fastify server with an integrated Vite app:

import Fastify from 'fastify'
import FastifyVite from 'fastify-vite'
import renderer from 'fastify-vite-vue'

const root = import.meta.url
const app = Fastify({ logger: true })

await app.register(FastifyVite, { root, renderer })
await app.vite.commands()
await app.listen(3000)

With that, create a view at views/index.vue:

<template>
  <h1>Hello World</h1>
</template>

<script>
export const path = '/'
</script>

TIP

View files can be named anything, in the examples index.vue is always associated to / as a convention.

And then, assuming you have saved the first snippet as app.mjs:

node app.mjs

Take note that root and renderer are fastify-vite's only required plugin options. The first is the Vite application root and the second determines what renderer adapter to use.

TIP

All examples in the documentation use ESM, but it's not required. If you use CJS, use __dirname instead of import.meta.url when setting the root option. It will know the difference.

Index HTML template

Vite's required index.html is provided by fastify-vite-vue automatically on the first run if you don't provide one yourself. See the default template below:

<!DOCTYPE html>
<html>
<head>
${head.preload}
${head.tags}
</head>
<body>
${hydration}
<div id="app">${element}</div>
<script type="module" src="@app/entry/client.js"></script>
</body>
</html>

As you can probably imagine, these variable names cannot be changed because they are used by fastify-vite-vue's internal rendering functions. The contents of index.html itself are compiled into a function loaded into memory for maximum performance.

The @app/ import prefix is used to load the client entry from the project blueprint provided by fastify-vite-vue. If you create a entry/client.js file at the root of your Vite application, that will be used instead. See Project Blueprint for more info on this works.

Blueprint Files

The fastify-vite-vue package will provide nearly all your starting boilerplate. The script where you actually register fastify-vite in your Fastify application being the only exception (you're expected to write it yourself). The files provided by fastify-vite-vue are listed below.

client.mjsMust export a createApp function returning a Vue application instance.
client.vueMust export the main Vue component for your app.

That would be the one where you set a layout, a router view etc.
routes.jsMust have a default export with the Vite application's routes array.
head.jsArray of <head> elements, following @vueuse/head's format.
entry/client.jsVite application client entry point (DOM element mount).
entry/server.jsVite application server entry point (render function and routes).
index.htmlVite application main entry point (loads client entry point).

Global Data

Global Data is automaticallyed added to globalProperties as $global.

<template>
  <h2>Accessing global data from the server</h2>
  <p>{{ $global }}</p>
</template>

You can also access it via the context object returned by the useHydration hook.

<template>
  <h2>Accessing global data from the server</h2>
  <p>{{ foobar }}</p>
</template>

<script>
import { useHydration } from 'fastify-vite-vue/client'

export const path = '/global-data'

export default {
  async setup () {
    const ctx = await useHydration()
    return { foobar: ctx.$global }
  }
}
</script>