⚠️
The vite-plugin-ssr project has been renamed Vike.
  • If you are already using vite-plugin-ssr then migrate to Vike.
  • For new projects, don't use vite-plugin-ssr but use Vike instead.

Markdown

Vue

If you use Vue, you can use unplugin-vue-markdown, or vite-plugin-md (make sure to use at least vite-plugin-md@0.22.x, see this bug report).

Example:

React

If you use React, you can use @mdx-js/rollup.

Example:

Metadata

A somewhat unconventional, but simple yet powerful, way to define the metadata of your pages (title, publishing date, ...) is to define a metadata.js file that contains the metadata of all your markdown pages.

If you want to show the list of pages to your users, then we recommend this approach over Metadata with frontmatter and Metadata with pageContext.exports. See explanation at Page list.

// /pages/metadata.js

export const metadata = [
  {
    url: '/blog/introducing-vike',
    title: 'Introducing Vike',
    date: new Date('2024-01-01')
  },
  {
    url: '/blog/v1',
    title: 'v1.0.0 release',
    date: new Date('2024-02-01')
  }
]
// /pages/index/index.page.jsx

import { metadata } from './metadata'

// Show the list of blog posts
export function Page() {
  return <>
    <p>Blog posts:</p>
    <ul>{
      metadata.map(({ title, url, date }) =>
        <li>
          <a href={url}>{title}</a> published in {date.toDateString()}
        </li>
      )
    }</ul>
  </>
}

We don't have to redefine/duplicate the page titles in the markdown:

// /pages/blog/introducing-vike.md

We're thrilled to officially introduce Vike, the new name of vite-plugin-ssr,
marking a new era for the project.
// /pages/blog/v1.md

The `v1.0.0` release signals that Vike is ready for prime time: it now includes
all essentials you'd expect from a frontend framework with a robust design.

Instead, we integrate the page title defined by metadata.js:

// /renderer/PageShell.jsx

import { metadata } from '../pages/metadata'

export function PageShell({ pageContext }) {
  // The component defined by our .md files
  const { Page } = pageContext
  // Current URL
  const url = pageContext.urlParsed.pathname
  // The page's metadata
  const { title } = metadata.find(m => m.url === url)
  return <>
    <h1>{title}</h1>
    <Page />
  </>
}
// /renderer/_default.page.server.jsx

import { PageShell } from './PageShell'
import { escapeInject, dangerouslySkipEscape } from 'vite-plugin-ssr/server'
import { renderToString } from 'some-ui-framework' // React/Vue/Solid/...

export async function render(pageContext) {
  const url = pageContext.urlParsed.pathname
  const { title } = metadata.find(m => m.url === url)
  const page = <PageShell pageContext={pageContext} />
  const pageHtml = renderToString(page)
  return escapeInject`<html>
    <head>
      <title>${title}</title>
    </head>
    <body>
      <div id="page-view">
        ${dangerouslySkipEscape(pageHtml)}
      </div>
    <body>
  </html>`
}

Metadata with pageContext.exports

To set the <head> tags value of a markdown page, you can use Custom Export.

// some.page.md

export const documentProps = {
  title: 'A Markdown Page',
  description: 'Example of setting `<title>` and `<meta name="description">`'
}

# Markdown

This page is written in _Markdown_.
// _default.page.server.js

import { escapeInject } from 'vite-plugin-ssr/server'

export async function render(pageContext) {
  // `pageContext.exports` holds all exports of the page's `.page.js` file
  const { title, description } = pageContext.exports.documentProps
  return escapeInject`<html>
    <head>
      <title>${title}</title>
      <meta name="description" content="${description}">
    </head>
    <!-- ... -->
  </html>`
}

Examples:

Metadata with frontmatter

Some markdown processors also have support for a so-called frontmatter to define the page's metadata.

---
title: A Markdown Page
description: Example of setting `<title>` and `<meta name="description">`
---

# Markdown

This page is written in _Markdown_.

Make sure the Vite markdown plugin you are using has frontmatter support.

Markdown processors usually expose the frontmatter data as an export, which you can access at pageContext.exports.

// _default.page.server.js

import { escapeInject } from 'vite-plugin-ssr/server'

export async function render(pageContext) {
  // Read the documentation of your Vite markdown plugin or of its underlying markdown
  // processor to find the name of the export that holds the frontmatter data.
  const frontmatterExportName = 'nameOfTheFrontmatterExport'
  const frontmatter = pageContext.exports[frontmatterExportName]
  const { title, description } = frontmatter
  return escapeInject`<html>
    <head>
      <title>${title}</title>
      <meta name="description" content="${description}">
    </head>
    <!-- ... -->
  </html>`
}

Page list

A frequent need when using markdown is to show the list of markdown pages to your users, for example the list of your blog posts.

To be able to do so, we recommend defining a file metadata.js that contains the metadata of all your markdown pages, see Metadata.

Another apporach is to use import.meta.glob() to retrieve the list of markdown files, but we usually recommend against this approach. The problem is that, in order to retrieve the metadata of all your markdown files, you'd need to load the entire code of all your markdown files, which contradicts Vite's lazy-transpiling approach and dramatically degrading Vite's development DX speed.