Closed bowencool closed 9 months ago
666 学习了 组件库的下一步就是搞demo简化了
vitepress 支持 vite 插件,在 vitepress <命令> <文件夹>
命令中 <文件夹>
的根目录创建 vite.config.js
即可。
例如:
.
├─ docs
│ ├─ .vitepress
│ │ ├─ theme
│ │ │ └─ index.js
│ │ └─ config.js
│ ├─ vite.config.js <------ 创建
│ └─ index.md
└─ package.json
更多例子可参考:
vitepress 支持 vite 插件,在
vitepress <命令> <文件夹>
命令中<文件夹>
的根目录创建vite.config.js
即可。 例如:. ├─ docs │ ├─ .vitepress │ │ ├─ theme │ │ │ └─ index.js │ │ └─ config.js │ ├─ vite.config.js <------ 创建 │ └─ index.md └─ package.json
更多例子可参考:
是我表达有点问题,我的意思是 vitepress 核心功能不支持插件扩展
必须在项目初始化的就使用这个插件吗?我现在已经有一个做的差不多的文档里,可以用yarn下载插件再使用吗?
必须在项目初始化的就使用这个插件吗?我现在已经有一个做的差不多的文档里,可以用yarn下载插件再使用吗?
拷贝关键代码就行。vitepress 核心功能不支持插件扩展,所以暂时没有好的办法。
本文内容已经全部整理到 Github,你也可以查看示例站点。
背景
vitepress 凭借着 vite 的秒级启动速度、markdown-it 的强大扩展能力、天然支持 vue3 在文档圈迅速流行开来,使用 vitepress 做 vue3 组件库文档也已经非常流行。笔者也有幸实践过一次,在这里记录一下。
首先 vitepress 的 markdown 扩展能力 无疑是极香的,我觉得及其舒适的有以下几点:
笔者使用 vitepress 搭建业务组件库的文档,依赖 element-plus,根据 vitepress 文档,写了一个简单的 DemoContainer 组件用于包裹 Demo。
vitepress 缺点
随着时间的推移和组件数量的累积,现有的开发方式逐渐暴露出来一些问题:
前两点很容易想到用 iframe 是完美的解决方案,而且还能顺手解决第三点。
总结一下缺点有两个:
前置介绍
涉及到的框架之间的关系
vitepress 本质上是一个 vite 插件,使用它开发的文档网站效果相当于 vue3 + vite 的 ssr 项目,它在内部帮你把所有逻辑都封装好了,你只需要写 markdown 就行。
对 markdown 的扩展能力是基于 markdown-it 写了很多 markdown-it 插件。源码里所写的 markdown 文档最终都会转成 vue 组件,原理如下:
vitepress 运行 vue 组件原理
把 markdown 编译成 html 字符串,把 html 字符串拼凑成一个 vue 字符串,交给 vue-loader,处理成一个 vue 组件挂载到页面上。
调研
最终决定尝试通过修改配置和自定义插件解决。
研发
demo 引入简化
参考了 element-plus 和 vitepress-for-component ,定制一个 markdown-it 插件修改 html 编译结果。
引入方式设计
element-plus 的引入方式不够清晰,也不够灵活。采用相对路径更清晰更灵活:
当然 container 的方式也顺便兼容下,里面的内容可以写写 markdown:
插件思路
遇到特定标记(如:
<demo src=xxx ... />
),根据标记拼接字符串,将来会被插入到 vue template 里相应位置,通常情况下拼接<DemoContainer ... ><Demo/></DemoContainer>
,如果标记了以 iframe 模式运行 demo,则拼接一个<iframe src=xxx ... />
此过程还会包括如下步骤,感兴趣可以看源码:
这一步把引入 Demo 的过程从原来的 15 行代码之间简化到 1 行。
iframe 模式
运行时动态创建 iframe
试过在 DemoContainer 里 document.createElement('iframe'),但是没有成功:
微前端
这明显更复杂了,而且和动态 iframe 具有相同的问题。
在 vite 配置里直接加入口
第一个念头是 vite.config 里添加入口,因为 vite 就是支持多个 html 的。
实际操作之后发现根本行不通:vitepress 接管路由了,访问任何路径都会经过 vitepress router 处理。即使设置 base,也会收到 vitepress 的提醒。
查看源码得知,devServer 拦截了所有 html 请求,根据请求路径动态生成 html:
查看代码 vitepress/src/node/plugin.ts
```ts const vitePressPlugin: Plugin = { name: 'vitepress', // ... configureServer(server) { if (configPath) { server.watcher.add(configPath); } // serve our index.html after vite history fallback return () => { server.middlewares.use((req, res, next) => { if (req.url!.endsWith('.html')) { res.statusCode = 200; res.end(`定制 devServer 中间件
上面 vitepress 的操作给了我灵感,我也写个 devServer 中间件,根据请求路径动态生成 html。试了一下,还真成功了,流程如下:
<iframe src=xxx />
/^\/~demos\/(?<demoId>\w+)\.html$
,则拼接一个可以运行此 demo 的 html 字符串给浏览器。const module = await import('@fs/${demoEntry}')
构建模式
由于构建模式没有 devServer,所以上述 devServer 也不会生效。
vitepress 和处理请求一样一刀切,没有留余地,无法通过 vite 添加入口。
所以只能在
vitepress build
之后再跑一遍vite build -c=xxx
总结
由于这套刚刚出炉,所以有很多的优化点,发出来权当抛砖引玉了。
因为 vitepress 暂时没有插件机制,所以这套方案也没什么抽象的点子,暂时作为一个样板仓库,仓库地址,使用方法:
如果你有好的点子或者优化的地方,我们评论区见。