Compile Markdown to Vue component.
- 📚 Use Markdown as Vue components.
- 💚 Use Vue components in Markdown.
- 🔌 Supports Vite, Webpack, Vue CLI and more, powered by unplugin.
- ⚡️ The same transformation as VitePress.
npm i unplugin-vue-markdown
Vite
// vite.config.ts
import Vue from '@vitejs/plugin-vue'
import Markdown from 'unplugin-vue-markdown/vite'
export default defineConfig({
plugins: [
Vue({
include: [/\.vue$/, /\.md$/], // <-- allows Vue to compile Markdown files
}),
Markdown({ /* options */ }),
],
})
Example: examples/vite
Webpack
// webpack.config.js
const Markdown = require('unplugin-vue-markdown/webpack')
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
/* ... */
module: {
rules: [
// ... other rules
{
test: /\.(vue|md)$/,
loader: 'vue-loader'
}
]
},
plugins: [
new VueLoaderPlugin(),
Markdown({ /* options */ })
]
}
Vue CLI
// vue.config.js
const Markdown = require('unplugin-vue-markdown/webpack')
module.exports = {
parallel: false, // Disable thread-loader which will cause errors, we are still investigating the root cause
chainWebpack: (config) => {
config.module
.rule('vue')
.test(/\.(vue|md)$/) // <-- allows Vue to compile Markdown files
config
.plugin('markdown')
.use(Markdown({
markdownItUses: [
prism,
],
}))
},
}
Example: examples/vue-cli
<template>
<HelloWorld />
</template>
<script>
import HelloWorld from './README.md'
export default {
components: {
HelloWorld,
},
}
</script>
You can even use Vue components inside your markdown, for example
<Counter :init='5'/>
Note you can either register the components globally, or use the <script setup>
tag to register them locally.
import { createApp } from 'vue'
import App from './App.vue'
import Counter from './Counter.vue'
const app = createApp(App)
// register global
app.component('Counter', Counter) // <--
app.mount()
<script setup>
import { Counter } from './Counter.vue'
</script>
<Counter :init='5'/>
Or you can use unplugin-vue-components
for auto components registration.
Frontmatter will be parsed and inject into Vue's instance data frontmatter
field.
For example:
---
name: My Cool App
description: This is My Cool App
---
# Hello World
This is {{frontmatter.name}}
Will be rendered as
<h1>Hello World</h1>
<p>{{frontmatter.description}}</p>
You can override existing frontmatter values by passing the :frontmatter-merge prop to the component.
<template>
<HelloWorld :frontmatter-merge="{ name: 'My Awesome App' }" />
</template>
<script>
import HelloWorld from './README.md'
export default {
components: {
HelloWorld,
},
}
</script>
Alternatively, you can replace all frontmatter values using the :frontmatter-replace
prop. Any remaining frontmatter properties will not render and will be undefined
.
<template>
<HelloWorld :frontmatter-replace="{ name: 'My Super App' }" />
</template>
<script>
import HelloWorld from './README.md'
export default {
components: {
HelloWorld,
},
}
</script>
For example, if you use :frontmatter-replace
, the description
property will not be shown on the screen.
Use either
:frontmatter-merge
or:frontmatter-replace
for a component. If both props are provided, only:frontmatter-replace
will take effect.
It will also be passed to the wrapper component's props if you have set wrapperComponent
option.
To manage document head and meta, you would need to install @unhead/vue
and do some setup.
npm i @unhead/vue
// vite.config.js
import Vue from '@vitejs/plugin-vue'
import Markdown from 'unplugin-vue-markdown/vite'
export default {
plugins: [
Vue({
include: [/\.vue$/, /\.md$/],
}),
Markdown({
headEnabled: true // <--
})
]
}
// src/main.js
import { createHead } from '@unhead/vue' // <--
import { createApp } from 'vue'
const app = createApp(App)
const head = createHead() // <--
app.use(head) // <--
Then you can use frontmatter to control the head. For example:
---
title: My Cool App
meta:
- name: description
content: Hello World
---
For more options available, please refer to @unhead/vue
's docs.
unplugin-vue-markdown
uses markdown-it
under the hood, see markdown-it
's docs for more details
// vite.config.js
import MarkdownItAnchor from 'markdown-it-anchor'
import MarkdownItPrism from 'markdown-it-prism'
import Markdown from 'unplugin-vue-markdown/vite'
export default {
plugins: [
Markdown({
// default options passed to markdown-it
// see: https://markdown-it.github.io/markdown-it/
markdownItOptions: {
html: true,
linkify: true,
typographer: true,
},
// A function providing the Markdown It instance gets the ability to apply custom settings/plugins
markdownItSetup(md) {
// for example
md.use(MarkdownItAnchor)
md.use(MarkdownItPrism)
},
// Class names for the wrapper div
wrapperClasses: 'markdown-body'
})
],
}
See the tsdoc for more advanced options
See the /examples.
Or the pre-configured Markdown template Vitesse.
Work with vite-plugin-pages
import Vue from '@vitejs/plugin-vue'
import Markdown from 'unplugin-vue-markdown/vite'
import Pages from 'vite-plugin-pages'
export default {
plugins: [
Vue({
include: [/\.vue$/, /\.md$/],
}),
Pages({
extensions: ['vue', 'md'],
}),
Markdown()
],
}
Put your markdown under ./src/pages/xx.md
, then you can access the page via route /xx
.
Work with unplugin-vue-components
unplugin-vue-components
allows you to do on-demand components auto-importing without worrying about registration.
import Vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite'
import Markdown from 'unplugin-vue-markdown/vite'
export default {
plugins: [
Vue({
include: [/\.vue$/, /\.md$/],
}),
Markdown(),
// should be placed after `Markdown()`
Components({
// allow auto load markdown components under `./src/components/`
extensions: ['vue', 'md'],
// allow auto import and register components used in markdown
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
})
],
}
Components under ./src/components
can be directly used in markdown components, and markdown components can also be put under ./src/components
to be auto imported.
declare module '*.vue' {
import type { ComponentOptions } from 'vue'
const Component: ComponentOptions
export default Component
}
declare module '*.md' {
import type { ComponentOptions } from 'vue'
const Component: ComponentOptions
export default Component
}
MIT License © 2020-PRESENT Anthony Fu