Skip to content

unplugin/unplugin-vue-markdown

Repository files navigation

unplugin-vue-markdown

NPM version

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.

Install

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 { VueLoaderPlugin } = require('vue-loader')
const Markdown = require('unplugin-vue-markdown/webpack')

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


Import Markdown as Vue components

<template>
  <HelloWorld />
</template>

<script>
import HelloWorld from './README.md'

export default {
  components: {
    HelloWorld,
  },
}
</script>

Use Vue Components inside Markdown

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

Frontmatter will be parsed and inject into Vue's instance data frontmatter field.

For example:

---
name: My Cool App
---

# Hello World

This is {{frontmatter.name}}

Will be rendered as

<h1>Hello World</h1>
<p>This is My Cool App</p>

It will also be passed to the wrapper component's props if you have set wrapperComponent option.

Document head and meta

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 { createApp } from 'vue'

import { createHead } from '@unhead/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.

Options

unplugin-vue-markdown uses markdown-it under the hood, see markdown-it's docs for more details

// vite.config.js
import Markdown from 'unplugin-vue-markdown/vite'
import MarkdownItAnchor from 'markdown-it-anchor'
import MarkdownItPrism from 'markdown-it-prism'

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

Example

See the /examples.

Or the pre-configured Markdown template Vitesse.

Integrations

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.

unplugin-vue-components allows you to do on-demand components auto-importing without worrying about registration.

import Vue from '@vitejs/plugin-vue'
import Markdown from 'unplugin-vue-markdown/vite'
import Components from 'unplugin-vue-components/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.

TypeScript Shim

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
}

License

MIT License © 2020-PRESENT Anthony Fu