Examples
All examples write generated Markdown under src/generated/.... Add that generated directory to .gitignore; generated Markdown files are not meant to be committed. Run vitepress build during deployment so the plugin recreates them before the site is built.
docs/src/generated/Import package README files only
This setup turns each packages/*/README.md into one generated VitePress page.
import { defineConfig } from 'vitepress'
import { externalMarkdown, getExternalMarkdownSidebar } from 'vitepress-plugin-external-markdown'
const externalMarkdownOptions = {
root: new URL('..', import.meta.url).pathname,
srcDir: 'src',
sources: [
{
baseDir: '../packages',
pattern: '*/README.md',
},
],
outDir: 'generated/packages',
routeBase: '/generated/packages/',
resolveMarkdown(ctx) {
const packageName = ctx.relativePath.replace(/\/README\.md$/u, '')
return {
slug: packageName,
title: ctx.title,
text: packageName,
order: packageName,
sidebar: true,
}
},
}
export default defineConfig({
srcDir: 'src',
vite: {
plugins: [externalMarkdown(externalMarkdownOptions)],
},
themeConfig: {
sidebar: {
'/generated/packages/': getExternalMarkdownSidebar(externalMarkdownOptions),
},
},
})Include README, CHANGELOG, and docs
This setup imports README.md, CHANGELOG.md, and files under package docs/ directories.
const externalMarkdownOptions = {
root: new URL('..', import.meta.url).pathname,
srcDir: 'src',
sources: [
{
name: 'package-docs',
baseDir: '../packages',
pattern: '{*/README.md,*/CHANGELOG.md,*/docs/**/*.md}',
},
],
outDir: 'generated/packages',
routeBase: '/generated/packages/',
resolveMarkdown(ctx) {
const slug = ctx.relativePath
.replace(/\/README\.md$/u, '')
.replace(/\.md$/u, '')
.toLowerCase()
return {
slug,
title: ctx.title,
text: ctx.fileName === 'README.md' ? ctx.relativePath.split('/')[0] : ctx.title,
order: ctx.relativePath,
sidebar: true,
}
},
}Copy colocated assets
Use copyAssets when imported Markdown refers to local images or static files. Assets are copied independently from Markdown generation, and Markdown links are not rewritten.
const externalMarkdownOptions = {
root: new URL('..', import.meta.url).pathname,
srcDir: 'src',
sources: [
{
baseDir: '../docs-content',
pattern: '**/*.md',
},
],
outDir: 'generated/docs',
routeBase: '/generated/docs/',
copyAssets: [
{
baseDir: '../docs-content',
pattern: 'images/**/*',
outDir: 'generated/docs',
},
{
baseDir: '../docs-content',
pattern: 'public/**/*',
outDir: '.',
},
],
}With this configuration, files are materialized like this.
docs/src/generated/docs/images/example.png
docs/src/public/logo.pngThis page is generated from docs-content/en/examples.md, and the image below is copied from docs-content/en/assets/ by the same plugin configuration.
Add top-level nav items
Return nav: true for files that should also appear in top-level navigation, then use getExternalMarkdownNav().
import {
externalMarkdown,
getExternalMarkdownNav,
getExternalMarkdownSidebar,
} from 'vitepress-plugin-external-markdown'
const externalMarkdownOptions = {
root: new URL('..', import.meta.url).pathname,
srcDir: 'src',
sources: [
{
baseDir: '../packages',
pattern: '*/README.md',
},
],
outDir: 'generated/packages',
routeBase: '/generated/packages/',
resolveMarkdown(ctx) {
const packageName = ctx.relativePath.replace(/\/README\.md$/u, '')
return {
slug: packageName,
title: ctx.title,
text: ctx.title,
order: packageName,
sidebar: true,
nav: packageName === 'core',
}
},
}
export default defineConfig({
srcDir: 'src',
vite: {
plugins: [externalMarkdown(externalMarkdownOptions)],
},
themeConfig: {
nav: getExternalMarkdownNav(externalMarkdownOptions),
sidebar: {
'/generated/packages/': getExternalMarkdownSidebar(externalMarkdownOptions),
},
},
})Skip private or draft docs
Return false from the resolver to skip a source file.
resolveMarkdown(ctx) {
if (ctx.relativePath.includes('/drafts/')) {
return false
}
return {
slug: ctx.relativePath.replace(/\.md$/u, ''),
title: ctx.title,
text: ctx.title,
order: ctx.relativePath,
}
}Inject generated frontmatter
Resolver frontmatter wins over source frontmatter when both define the same field.
resolveMarkdown(ctx) {
return {
slug: ctx.relativePath.replace(/\.md$/u, ''),
title: ctx.title,
text: ctx.title,
order: ctx.relativePath,
frontmatter: {
outline: 'deep',
editLink: false,
},
}
}Generated Markdown receives one frontmatter block at the top of the file.