在 vuepress 刚出时,我就以为这是个很值得追更的开源项目。果不其然,里面众多的前端编程技巧让我受益良多。html
因而在周末这种日子里,人家追剧我追码。前端
今天,我就和你们分享下 vuepress 是如何作到在 Markdown 中使用 Vue 语法的。vue
众所周知,Markdown 是一种标记语言,相似于 HTML,它也有对应的语法和词法。而 Vue 说白了也是一种语法,关键在于,Markdown 和 Vue 代码均可以被解释成 HTML。react
聪明的读者应该想到了:添加一个中间过程,让 Vue 转成 Markdown 或者让 Markdown 转成 Vue,是否是就能够实如今 Markdown 中使用 Vue 语法了呢?webpack
让咱们再考虑一下两个方案的实现难点:git
很显然,第二种方案实现起来更靠谱些,因此尤雨溪也是这样选的: github
在语法之间的转换工做上,webpack 的 loader 但是很擅长的。因此,vuepress 自定义了一个 markdownLoader 来将 Markdown 转成 Vue,再经过 vue-loader 获得最终的 HTML。web
这是一个自定义的 loader,可参考如何编写一个 loader?vue-cli
`<template>\n` +
`<div class="markdown">${html}</div>\n` +
`</template>\n`
复制代码
主要过程其实就这两步。固然,vuepress 还在 markdownLoader 里作了不少其余的事情,好比解析 yaml front matter、推断标题、获取 markdown 里提高的 style、script 等标签。npm
接下来,你们能够跟我一块儿实现一个基本的 demo。完整代码可见 github。
新建一个 Vue 项目 咱们使用 vue-cli(v2.9.6) 新建一个项目:
编写 markdownLoader
npm install markdown-it --save
复制代码
const markdown = require('markdown-it')
module.exports = function(src) {
const html = markdown().render(src)
return (
`<template>\n` +
`<div class="markdown">${html}</div>\n` +
`</template>\n`
)
}
复制代码
{
test: /\.md$/,
use: [
{ loader: 'vue-loader' },
{
loader: require.resolve('./markdownLoader')
}
]
}
复制代码
## 我是一个 markdown
{{1+2}}
复制代码
const Markdown = () => import('@/components/markdown.md')
复制代码
{
path: '/md',
name: 'Markdown',
component: Markdown
}
复制代码
既然能够在 markdown 里写 vue,那在 markdonw 里面写 react 理论上也是能够实现的:让 markdownLoader 最后返回一个 React 组件,以后使用 babel-loader 转成 js。
这一次咱们是将 markdown 转 jsx 再包裹在一个 React 组件(函数或者类)里:
return (
`import React from 'react';
${registerComponent}
function R() {
return (
<div>
<div className="markdown">${html}</div>
</div>)
}
export default R;\n`
)
复制代码
有兴趣的读者能够自行实现完整的 react 版本的 markdownLoader 代码。
本文实现的 demo 只对 markdownLoader 的关键步骤作了实现,实际上还有不少问题须要解决,如浏览器的 API 访问限制、代码块和高亮的处理等须要解决,这篇文章就不涉及了。
此系列文章还会给你们介绍 webpack 拓展、markdown-it 拓展、单元测试、插件系统等。若是您喜欢这篇文章的话,别记得点个赞噢~