vitepress
vitepress 官网 VitePress | Vite & Vue Powered Static Site Generator 什么是 VitePress? | VitePress 上手简单易用。
用到了 vitepress-demo-editor 插件 github.com/liyao1520/v…,可以将源码 lib 文件夹放入到项目中方便直接调试。
vitepress-demo-editor
vitepress-demo-editor 插件里面用到了 Demo 组件和自定义的 Compiler 类,本质是使用的 vue/compiler-sfc 库里面的 parse 以及compileTemplate\compileScript\compileStyle 方法。vue/compiler-sfc 为用户提供了将 vue 文件编译为 js 文件的能力。
compilerSFC 中,
-
compiler.parse() 函数,将 vue 文件分为3部分,template 块、script 块和 scriptup 块、多个 style 块。这一块做的是解析,并没有对代码进行编译。
-
compilerTemplate() 对 template 进行编译,得到 render 函数
-
compilerScript() 对 script 进行编译
-
compiler.compileStyle() 对 style 进行编译
得到 vue 代码片段编译后的 js 代码片段后,在页面中动态生成 script 标签,通过 Vue 提供的 h 方法和 render 方法,将代码渲染到页面中。一个简化的代码页面如下:
<div id="app"></div>
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue@3.2.33/dist/vue.esm-browser.js",
"@vue/compiler-sfc": "https://unpkg.com/@vue/compiler-sfc@3.2.47/dist/compiler-sfc.esm-browser.js"
}
}
</script>
<script type="module">
import { parse, compileTemplate, compileScript, rewriteDefault } from '@vue/compiler-sfc'
// 引入 vue 字符串
import { code } from './vue.js'
const parsedResult = parse(code)
const scopeId = 'testId'
const templateRes = compileTemplate({id: scopeId, source: parsedResult.descriptor.template.content})
const scriptRes = compileScript(parsedResult.descriptor, {id: scopeId})
// 转为 __sfc_main__ 对象
const defaultRes = rewriteDefault(scriptRes.content, "__sfc_main__")
// script 的内容
const scriptContent = `import { render as _render, h } from 'vue';
${templateRes.code}
${defaultRes}
__sfc_main__.render = render;
_render(h(__sfc_main__), document.querySelector('#app'))`
// 创建 script 标签动态插入 HTML 中
const scriptEL = document.createElement('script')
scriptEL.type = "module"
scriptEL.innerHTML = scriptContent
document.body.appendChild(scriptEL)
</script>
其中,使用 vue 的两个函数:
-
h(component) 函数,将一个组件生成 VNode
-
render(vnode, container) 函数,将 vnode 渲染到容器 container 中
这里要注意一下 vue 的版本问题,使用最新版 3.2.47 渲染有问题,会报 warn:
使用 3.2.33 没有该问题。
支持导入
如果想要在 vitepress-demo-editor 示例源码中使用其他库,例如使用 axios,需要使用 addImportMap 方法引入:
// .vitepress/theme/index.js
import { vuePlugin, addImportMap } from "vitepress-demo-editor";
import axios from "axios";
export default {
// ...otherConfig
enhanceApp({ app }) {
app.use(vuePlugin);
addImportMap("axios", axios);
},
};
在 markdown 中使用
:::demo
```vue
<template>...</template>
<script setup>
// 使用
import axios from "axios";
</script>
```
:::
ant design vue
首先一点是 vitepress 本身是支持 vue 代码编写的。在 vitepress 中,每个 markdown 文件会被编译成 HTML 文件,然后作为 Vue Single-File Component 进行处理,这意味着我们在 markdown 文件中可以加入 script 标签,写 vue 组件。如下
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
## Markdown Content
The count is: {{ count }}
<button :class="$style.button" @click="count++">Increment</button>
<style module>
.button {
color: red;
font-weight: bold;
}
</style>
同样,ant design vue 组件在 vitepress 中通过自定义 theme 也是可以在 markdown 文件中直接使用的。
// theme/index.js
import AntD from 'ant-design-vue'
import "ant-design-vue/dist/antd.css";
import DefaultTheme from 'vitepress/theme'
export default {
...DefaultTheme,
enhanceApp({ app }) {
app.use(AntD)
}
}
可以在 markdown 中使用 AntD 组件:
<script>
import { Button } from 'ant-design-vue'
</script>
## Markdown Content
<Button type="primary">primary</Button>
如果想要在可以交互使用 AntD 组件,即页面的代码框中修改 AntD 组件,渲染页面实时修改的效果,vitepress-demo-editor 插件中,也可直接使用,需要注意的是,要使用 AntD 组件的 name 值,如下:
业务组件
在 vitepress + vitepress-demo-editor 中怎么引入自己的业务组件呢?
我们知道 app.use(AntD) 方法会执行 AntD 的 install 方法,install 方法里,会将 AntD 组件一个个注册到 vue 的组件(以 Button 为例)中:
app.component(_button.default.name, _button.default);
所以针对业务组件也可以将其注册到 vue 组件中,在 theme 中实现
// theme/index.js
import DefaultTheme from 'vitepress/theme'
import { RoleSelect, } from '@xhs/people-ui'
export default {
...DefaultTheme,
enhanceApp({ app }) {
app.component("RoleSelect", RoleSelect);
}
}
一些问题
-
本地联调时业务组件中的异步数据请求统一拦截需要额外拦截
-
vitepress 打包时,会出现 global 等变量没有的情况,依赖的包无法正确编译,修改成本较高
Vue 文件是如何被转换并渲染到页面的?_vue文件是怎么转换的_蚂蚁二娘的博客-CSDN博客
vue3 -- @vue/compiler-sfc 单文件转换工具 -- 学习笔记 - 掘金
vue.js - 「将 Vue SFC 编译为 ESM 」探索之路 - 小蘿蔔丁 - SegmentFault 思否
VuePress
vuepress 官网 Home | VuePress 找到符合需求的插件是 vuepress-plugin-md-enhance,支持交互式 vue 代码演示,看起来似乎很完美,然而在支持 ant design vue UI 组件库的时候问题多多。
vuepress-plugin-md-enhance 因为只支持外部 Import Map 设置,
首先得找到 ant design vue 组件的 ES Module 形式的 cdn 形式,主要途径有两种:
-
unpkg UNPKG 按照规则自己匹配查找 cdn
-
jsDelivr 可以在 jsDelivr - A free, fast, and reliable CDN for JS and open source 搜索想要的组件的 cdn
主要的问题是,通过 cdn 引入组件,组件体量太大,同时受到网络限制,网速慢,体验差。还有就是 cdn 引入的组件不稳定,难以获得底层依赖模块的 bug 快速修复支持。
另外 vitepress 存在的业务组件本地联调拦截的问题,vuepress 也存在。
自己实现
利用 @vue/repl 自己实现, @vue/repl 可以实现 vue 代码交互式演示功能。方便代码修改。