前言

项目中我们会用到一些 markdown 文件作为文档在页面中展示。基本原理是用 js 去读取解析文件,最后渲染出来。所以我们可以在 webpack 编译的过程中将 markdown 文件编译为 js 模块,然后在页面中直接引入。

在了解 webpack 之后知道,每一个 loader 其实都是一个函数,函数接收资源,进行一定的处理之后输出给下一个 loader。明白了这个基本原理,我们也可以编写一个自己的 loader。

话不多说,进入正题。

代码实现

其中核心库使用了 markdown-itmarkdown-it-toc-and-anchor,将 md 文件转为 html 字符串,以及获取 md 内容中的标题目录列表。

创建 markdown-loader.js 文件,代码如下:

const MarkdownIt = require('markdown-it')
const MarkdownItTocAndAnchor = require("markdown-it-toc-and-anchor").default

const markdownIt = new MarkdownIt({
  html: true
}).use(MarkdownItTocAndAnchor, {
  anchorLink: false
})

module.exports = function (source) {
  let tocArray = []
  
  let content = markdownIt.render(source, {
    tocCallback (markdown, array, html) {
      tocArray = array
    }
  })

  // 最后返回一个 js 对象,包含文本内容和目录列表两个属性
  return `export default {
    content: \`${content}\`,
    tocArray: ${JSON.stringify(tocArray)}
  }`
}

假设使用 vue-cli 搭建的项目,可在 vue.config.js 中配置如下:

const path = require('path')

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

在文件中引入 md 文件,查看打印输出。

import demo from './demo.md'

console.log(demo);

使用

<template>
  <div class="doc">
    <div class="doc-summary">
      <ul class="doc-toc">
        <template v-for="(item, i) of tocArray">
          <li :class="doc-toc-item" :key="i">{{ item.content }}</li>
        </template>
      </ul>
    </div>

    <div class="doc-main">
      <section class="doc-content markdown-body" v-html="content"></section>
    </div>
  </div>
</template>

<script>
import demo from './demo.md'

export default {
  data () {
    return {
      content: '',
      tocArray: [],
    }
  },
  created () {
    const { content, tocArray } = demo
    this.content = content
    this.tocArray = tocArray
  }
}
</script>

<style lang="scss">
// 使用社区中提供的 github-markdown-css 样式,就可以有和 github 一样的效果了。
// https://github.com/sindresorhus/github-markdown-css
@import './github-markdown.css';

...
</style>

效果如下图所示:

总结

在项目中写一些小工具还是蛮有意思的 😘