vite插件,实现将markdown转成vue组件

我心飞翔 分类:javascript

本文目标是实现vite插件,面向vue做的代码实现,所以代码全是以vue的api形式展示,不过不管什么框架实现思路基本一致。

前言

我们在开发库或者文档系统的时候,希望能够直接将编写的markdown作为组件的内容,目前多数博客提供的解决方案要干两个事

  1. 利用markdown的解析库将md解析成html内容
  2. 在业务中编写一个组件将前一步解析出的html文本作为v-html属性的值

那么问题来了,这个承载markdown的组件作用仅仅是提供了插入html文本的容器,而你需要在业务里编写,即便提出到组件库,也需要进行导入和使用,可以说是事倍功半。

所以我们希望能够将编写的md文件直接导入成可使用的组件,比如:

<template>
  <Start />
</template>
<script>
import { defineComponent } from 'vue';
import Start from 'docs/start.md';
export default defineComponent({  
    name: 'App', 
    components: { Start },
})
</script>
 

也就是插件需要把前面所提到的两件事都干完,输出一个vue组件。

实现

理清需求

遇到markdown文件,将内容解析成html,利用vue渲染函数的api编写代码,将html内容插入,最终输出整个代码

解析markdown文件

我们采用marked库对markdown文件做解析,所以先安装

yarn add marked
 

vite插件

vite插件的使用和基本api可以直接看中文文档,这里不做赘述,直接看实现。

拦截markdown文件我们利用的是transform,意思是转换,功能类似webpack的loader,基本结构代码如下:

// /plugins/vite-plugin-md2vue.js

const marked = require('marked')

export default function (options) {
  return {
    name: 'vitePluginMd2Vue',
    transform(src, id) {
      /**
      * id是导入的文件路径
      * src是导入的文件内容
      */
      if (id.endsWith(".md")) { // 判断结尾字符串判断是否为markdown文件
        return {
          code: ``, // code是转换后最终输出的代码
          map: null // 是否提供source map,这里可以不用考虑
        }
      }
    }
  }
}
 

code中我们需要编写组件代码,但是这里不能使用sfc也就是单文件组件的形式去写,因为vite中会专门拦截.vue结尾的文件去做解析,如果我们直接导出sfc形式的代码,就没有走vite中的解析流程导致报错,所以我们直接编写渲染函数,代码如下:

import {h, defineComponent} from "vue";
const _sfc_md = defineComponent({
    name: "Markdown",
});

const _sfc_render =() => {
    return h("div", {
      // 这里赋值解析好的markdown内容,marked是上一段代码中导入的解析库
      // src也是上一段代码中md文件的导入内容,我们直接解析后转成字符串
      innerHTML: ${JSON.stringify(marked(src))}, 
    })
};

_sfc_md.render = _sfc_render
export default _sfc_md
 

最终合成代码如下:

// /plugins/vite-plugin-md2vue.js

const marked = require('marked')

export default function (options) {
  return {
    name: 'vitePluginMd2Vue',
    transform(src, id) {
      if (id.endsWith(".md")) {
        return {
          code: `import {h, defineComponent} from "vue";
                const _sfc_md = defineComponent({
                    name: "Markdown",
                });

                const _sfc_render =() => {
                    return h("div", {
                      innerHTML: ${JSON.stringify(marked(src))}, 
                    })
                };

                _sfc_md.render = _sfc_render
                export default _sfc_md`,
          map: null
        }
      }
    }
  }
}
 

使用插件

vite.config.js使用插件,代码如下:

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vitePluginMd2Vue from "./plugins/vite-plugin-md2vue";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), vitePluginMd2Vue()],
  ...
});
 

最终实现的代码在vite-plugin-md2vue

回复

我来回复
  • 暂无回复内容