Vuepress如何做到在 Markdown 中使用 Vue 语法

2020-03-03 20:18:21

参考地址 深入浅出 VuePress(一)

前言

在 vuepress 刚出时,我就觉得这是个很值得追更的开源项目。果不其然,里面众多的前端编程技巧让我受益良多。

于是在周末这种日子里,人家追剧我追码。

今天,我就和大家分享下 vuepress 是如何做到在 Markdown 中使用 Vue 语法的。

原理

众所周知,Markdown 是一种标记语言,类似于 HTML,它也有对应的语法和词法。而 Vue 说白了也是一种语法,关键在于,Markdown 和 Vue 代码都可以被解释成 HTML。

聪明的读者应该想到了:添加一个中间过程,让 Vue 转成 Markdown 或者让 Markdown 转成 Vue,是不是就可以实现在 Markdown 中使用 Vue 语法了呢?

让我们再考虑一下两个方案的实现难点:

  1. Vue -> Markdown:template 和 style 部分还好,可 js 部分怎么办?

  2. Markdown -> Vue:可以将 markdown 代码解释成 html 或者 js 混入到 vue 代码中。

很显然,第二种方案实现起来更靠谱些,所以尤雨溪也是这样选的:


vuepress 在 Markdown 中使用 Vue 语法原理

在语法之间的转换工作上,webpack  的 loader 可是很擅长的。所以,vuepress 自定义了一个 markdownLoader 来将 Markdown 转成 Vue,再通过 vue-loader 得到最终的 HTML。

代码实现

markdownLoader

这是一个自定义的 loader,可参考如何编写一个 loader?

  1. 这个 loader 接收一个参数,里面包含一个 markdown-it 实例,作者用它来把 markdown 解释成 html。

  2. 得到 html 后将之包裹在 template 标签内,返回。

`<template>\n` +
    `<div class="markdown">${html}</div>\n` +
`</template>\n`

主要过程其实就这两步。当然,vuepress 还在 markdownLoader 里做了很多其他的事情,比如解析 yaml front matter、推断标题、获取 markdown 里提升的 style、script 等标签。

自己实现一个 demo

接下来,大家可以跟我一起实现一个基本的 demo。完整代码可见 github

  1. 新建一个 Vue 项目
    我们使用 vue-cli(v2.9.6) 新建一个项目:


    vue-cli 新建项目

  2. 编写 markdownLoader

  • 2.1 引入 markdown-it

    npm install markdown-it --save
  • 2.2 新建 markdownLoader 文件

    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`
      )}
  • 2.3 在 webpack 的 module rules 配置中添加 markdownLoader

    {
      test: /\.md$/,
      use: [
        { loader: 'vue-loader' },
        {
          loader: require.resolve('./markdownLoader')
        }
      ]}
  1. 在 Vue 文件里使用 markdown 文件

  • 3.1 在 src/components 新建一个 markdown.md

## 我是一个 markdown 
{{1+2}}
  • 3.2 在 src/router/index 中引入 markdown

 const Markdown = () => import('@/components/markdown.md')
  • 3.3 将这个组件添加进路由里去

{
  path: '/md',
  name: 'Markdown',
  component: Markdown}

结果

在 Markdown 中使用 React(JSX) 语法

既然可以在 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 访问限制、代码块和高亮的处理等需要解决,这篇文章就不涉及了。



  • 2019-03-15 15:31:21

    内网穿透 ngrok 服务器和客户端配置

    ngrok 简介及作用 ngrok 是一款用 go 语言开发的开源软件,它是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。下图简述了 ngrok 的原理。

  • 2019-03-15 15:32:09

    内网打洞以及代码实现

    假设内网的多个ip或者同一ip的不同port,都要访问同一个(外网ip:port)。对NAT来说,从外网接收的包它的(srcIp:srcPort)==(serverIp,serverPort),它的dstIp==natIp,所以NAT只能用dstPort来决定把这个包转发给哪一个(内网Ip:port)

  • 2019-03-15 15:33:08

    Xshell不能按退格、删除键的解决方案

    在使用xshell时,由于每个服务器不同,一些无法使用Backspace键向后删除字符。针对这个问题,本文为大家解答下退格键无法识别如何设置?

  • 2019-03-15 15:49:28

    win10远程桌面连接不上解决方法

    有朋友就感叹电脑的世界真的是很神奇,可以将整个世界连接在一起。如果别人想要摆弄你的电脑,即使不在一个地方也可以利用远程桌面来控制。而这就是所谓的远程控制操作了,大部分人都知道它的作用,不过这也不排除会遇到一些突发情况的时候,例如win10远程桌面连接不上,这该怎么去解决呢?为此,小编给大家带来了解决的图文操作。

  • 2019-03-15 16:49:18

    Win7无法进入家庭组提示“您的系统管理员不允许访问家庭组”怎么办

     家庭组是家庭网络上可以共享文件和打印机的一组计算机,可以方便用户们共享文件或者视频等,可是最近有win7纯净版系统用户却发现无法进入家庭组,提示“您的系统管理员不允许访问家庭组”,该怎么办呢?现在给大家分享一下Win7无法进入家庭组提示“您的系统管理员不允许访问家庭组”的解决方法。

  • 2019-03-17 22:19:28

    动态更新Toolbar Menu以及Menu中同时显示文字和图标

    我们经常会有这样的需求,在切换Fragment或者点击某个按钮后动态更新Toolbar上Menu项.但是onCreateOptionsMenu方法只在创建Activity的时候调用一次,以后就不再调用了,所以就不能在onCreateOptionsMenu中做处理了。 不过系统提供了另外的一个方法onPrepa

  • 2019-03-26 19:25:01

    Android studio 打包后安装闪退 Fatal Signal 6(SIGABRT)...

    项目上线前打包安装后闪退,查了很多原因,比如混淆文件的内容,第三方库不加入混淆等等,均未成功,后来关闭混淆打包后运行成功,原因可能是依赖工程中的库文件不能被混淆,关闭本工程混淆开关后,依赖工程的混淆开关也要关闭,关闭混淆后如果怕被反编译,可使用百度开发平台的app加固,加固的同时还能使用多渠道打包工具。