Search code examples
vuepress

How can I pre-process markdown files in VuePress?


VuePress's standard templating, as documented, occurs during the Vue component rendering. This means the markdown compiler, markdown-it, will not see the rendered template results and will not be able to operate on them.

This can cause issues with variable substitution in links, code blocks, and a number of other edge cases. A somewhat common answer to this issue is to drop down to using raw HTML tags. I find this somewhat undesirable as it's tackles the issue at the wrong stage(post-markdown compilation) and requires content creators to juggle markdown with Vue/HTML/framework concerns.

How can I process the markdown files before markdown compilation in a manner that fits in with the dev/build pipeline?


Solution

  • VuePress currently processes markdown files in the webpack pipeline. The gist of this process is:

    .md -> markdown-loader(VuePress custom) -> vue-loader -> ...

    I will show an example of how to render the markdown templates with Nunjucks before it gets passed through to the markdown loader for compilation.

    In order to pre-process the markdown we need to slip a loader in before the first VuePress loader. Luckily we can do this through the exposed plugin/config API:

    .vuepress/config.js

    chainWebpack: config => {
        config.module
          .rule('md')
          .test(/\.md$/)
          .use(path.resolve(__dirname, './nunjucks'))
            .loader(path.resolve(__dirname, './nunjucks'))
            .end()
    },
    

    .vuepress/nunjucks.js

    const nunjucks = require('nunjucks')
    
    // Change start/end tokens so they don't collide with the Vue syntax
    nunjucks.configure({
        autoescape: false,
        tags: {
            blockStart: '{{{%',
            blockEnd: '%}}}',
            variableStart: '{{{',
            variableEnd: '}}}',
            commentStart: '{{{#',
            commentEnd: '#}}}'
          }
    })
    
    const config = {
        apiVersion: 32,
    }
    
    module.exports = function(source) {
        const rendered = nunjucks.renderString(source, config)
        return rendered
    }