vite-ssg

repository·main·Indexed 23 days ago

https://github.com/antfu-collective/vite-ssg

Server-side generation for Vue 3 applications built on Vite. It enables the creation of SEO-friendly, high-performance static sites while maintaining Vue application flexibility. Features include support for multi-page and single-page apps, critical CSS inlining via beasties, document head management with @unhead/vue, and a <ClientOnly /> component to prevent SSR mismatches.

Tokens
5.4K
Snippets
19
Records
33
Agent score
81%

What's inside vite-ssg

  1. Tree-shake client code using import.meta.env.SSR

    main

    To ensure Rollup can tree-shake server-only code out of your client bundle, wrap server-specific logic in a check for import.meta.env.SSR. This allows the bundler to remove the server block during the client build.

    if (import.meta.env.SSR) {
      // your server code will be removed in the client build
    }
    else {
      // your client code will be removed in the server build
    }
  2. Manage Initial State for Hydration

    main

    The initialState object allows you to serialize data during SSR so it can be hydrated in the browser without refetching. This is useful for data fetched from APIs or for synchronizing application stores like Pinia or Vuex.

    In the createApp setup callback, check import.meta.env.SSR to set data on the server, and access initialState on the client to restore it.

    // src/main.ts
    export const createApp = ViteSSG(
      App,
      { routes },
      ({ app, router, initialState }) => {
        if (import.meta.env.SSR) {
          // Set initial state during server side
          initialState.data = { cats: 2, dogs: 3 }
        }
        else {
          // Restore or read the initial state on the client side
          console.log(initialState.data) // => { cats: 2, dogs: 3 }
        }
      },
    )
  3. Configure Vite SSG for Single-Page Apps

    main

    If you want to perform SSG for an index page only (without vue-router), import from vite-ssg/single-page instead. For this mode, you only need to install vite-ssg and @unhead/vue.

    // src/main.ts
    import { ViteSSG } from 'vite-ssg/single-page'
    import App from './App.vue'
    
    export const createApp = ViteSSG(App)
  4. Configure Vite SSG for Multi-Page Apps

    main

    For standard applications using vue-router, you must export a createApp function from your entry file (e.g., src/main.ts) instead of calling .mount() directly. The ViteSSG function accepts the root component, router options, and a setup callback where you can install plugins and handle initial state.

    import { ViteSSG } from 'vite-ssg'
    import App from './App.vue'
    
    // `export const createApp` is required
    export const createApp = ViteSSG(
      // the root component
      App,
      // vue-router options
      { routes },
      // function to have custom setups
      ({ app, router, routes, isClient, initialState }) => {
        // install plugins etc.
      },
    )
  5. Manage Document Head with @unhead/vue

    main

    Vite SSG includes @unhead/vue v2 to manage the document <head> out of the box. You can use the useHead composable in your components or pages to set titles and meta tags. Vite SSG handles the server-side rendering and merging of these tags automatically.

    <script setup>
    import { useHead } from '@unhead/vue'
    
    useHead({
      title: 'Website Title',
      meta: [
        {
          name: 'description',
          content: 'Website description',
        },
      ],
    })
    </script>
  6. Install Vite SSG

    main

    To use Vite SSG for a Vue 3 application, install vite-ssg along with vue-router and @unhead/vue. Note that this library requires Node.js version >= 14 and is ESM-only from v27.0.0 onwards.

    Update your package.json scripts to use vite-ssg build instead of vite build. You can also specify a custom Vite configuration file using the -c flag.

    npm i -D vite-ssg vue-router @unhead/vue
    // package.json
    {
      "scripts": {
        "dev": "vite",
        "build": "vite-ssg build"
      }
    }
  7. Run and build the project examples

    main

    The repository contains several example implementations demonstrating different usage patterns of vite-ssg. You can run, build, and serve these examples using the following pnpm scripts depending on the specific example type you want to explore.

    # Multiple pages
    pnpm example:dev
    pnpm example:build
    pnpm example:serve
    
    # Multiple pages with store
    pnpm example:store:dev
    pnpm example:store:build
    pnpm example:store:serve
    
    # Single Page
    pnpm example:single:dev
    pnpm example:single:build
    pnpm example:single:serve
  8. Enable and Configure Critical CSS

    main

    Vite SSG supports inlining Critical CSS using the beasties package.

    1. Install beasties: npm i -D beasties.
    2. Configuration is handled via ssgOptions.beastsOptions in your vite.config.ts.
    npm i -D beasties
    // vite.config.ts
    export default defineConfig({
      ssgOptions: {
        beastiesOptions: {
          // E.g., change the preload strategy
          preload: 'media',
        },
      },
    })
  9. Navigate between pages using <router-link>

    main

    Since vite-ssg uses Vue Router under the hood, you can use the <router-link> component within your Markdown files to create links to other generated static pages. This enables client-side navigation between the pre-rendered routes.

    <router-link to="/a">/a</router-link>
    <router-link to="/b">/b</router-link>
    <router-link to="/nested/deep/b">/nested/deep/b</router-link>
  10. Use the <ClientOnly> component in Markdown

    main

    In vite-ssg projects using Markdown for routing, you can wrap components that rely on browser-only APIs (like window or document) inside the <ClientOnly> component. This prevents the SSG process from attempting to render these components on the server/build-time, which would otherwise cause errors. Content inside <ClientOnly> will only be rendered once the application is hydrated in the browser.

    <client-only>
      <mouse-pos/>
    </client-only>