Appearance
从错误中学习:分享 Vue DevUI 组件库开发过程中遇到的一些问题

DevOps理论中有一个很重要的观点:在复杂的系统中工作时,我们不可能预测到所有的结果。
因此错误或缺陷在所难免,我们要将错误视作机会,学习和自我改进的机会,当我们深刻理解了错误,我们就能避免下一次更严重的错误。
Vue DevUI 是 Vue3 版本的 DevUI 组件库,基于 Ng DevUI。
Vue DevUI 使用最新的技术栈进行开发:
- 使用
Vite搭建基础工程(【我要做开源】Vue DevUI开源指南04:使用Vite搭建一个支持TypeScript/JSX的Vue3组件库工程 ) - 使用
VitePress搭建文档系统(【我要做开源】Vue DevUI开源指南05:给Vue3组件库添加VitePress文档系统) - 使用
Vue3+TypeScript+JSX进行组件开发(【我要做开源】Vue DevUI开源指南03:如何给 tree 组件增加展开/收起功能) - 使用
Jest+@vue/test-utils进行单元测试 - 使用
eslint/stylelint/ls-lint进行代码规范检查
在开发 Vue DevUI 的过程中,我们也遇到不少问题:
- 有些是我们的contributor提的issue
- 有些在和村长直播过程中发现的问题
- 还有一些和VitePress文档系统相关
以下是本文将要分享的问题列表:
- 8.16 vitepress中使用自定义指令导致的问题
- 9.18 defineEmit导致的文档启动白页问题
- 10.3 使用window浏览器变量导致的vitepress ssr构建问题
问题一:vitepress中使用自定义指令导致的问题
问题背景和描述
第一个问题最早可以追溯到8月16日,由vue devui的早期贡献者wailen提出 I45VB6,当时vue devui的文档系统刚刚切换到vitepress一个多星期。
以下是wailen同学当时提的issue:
当时通过执行yarn build文档构建命令就可以很轻易地复现该错误:
报错信息如下:
SyntaxError: Custom directive is missing corresponding SSR transform and will be ignored.以下是当时wailen的截图:
不过当时vue devui项目刚开始活跃,大家都忙着提交pr、提交issue、检视和合入代码,没有太关注到这个issue,而且当时咱们的网站还没有通过域名访问,不需要部署实际的主机,也就不需要执行yarn build构建生产包,因此都没关注到这个问题。
问题分析
看截图的报错信息,是vitepress构建过程中遇到了语法错误导致构建失败,提示自定义指令缺少服务端渲染的转换器:
SyntaxError: Custom directive is missing corresponding SSR transform and will be ignored.很幸运,报错提示定位到了具体的文件:
file: D:/code/vue-devui/sites/components/loading/index.md:124:3这个文件是Loading组件的md文档,以下是会导致构建错误的内容:
<div
v-dLoading="promises.value"
:backdrop="true"
message="One moment please..."
style="margin-top: 20px; width: 100%; height: 80px; padding: 10px;"
>loading will show here2</div>可以看到这个只用了一个v-dLoading的自定义指令,而vitepress文档使用的构建方式SSR服务端渲染,SSR过程中没有相应的transform转换器来解析这个vue的自定义指令,所以构建文档报错啦。
解决方案
知道问题的原因,解决起来就很容易啦。
- 一种方案是为这个自定义指令编写相应的transform
- 另一种方案是安装patch-vue-directive-ssr补丁
我们选择第二种方案:
yarn add -D patch-vue-directive-ssrpatch-vue-directive-ssr补丁包专门用于修补@vue/compiler-ssr,以使用SSR/SSG方式构建vue自定义指令。
问题二:defineEmit 导致的文档启动白页问题
问题背景和描述
这个问题最早发现于9月18日和村长在B站直播的那个晚上,以下是直播的录播地址:
【我要做开源】华为大佬亲授,Vue DevUI开源指南01:提交我的第一次pr
这个问题发生在执行yarn dev命令启动组件库文档的时候,执行完yarn dev命令,在浏览器地址栏输入http://localhost:3000/访问文档,出现白页。
问题分析
打开浏览器控制台,发现红色的报错,提示了一个语法错误:
Uncaught SyntaxError: The requested module '/vue-devui/node_modules/.vite/vue.js' does not provide an export named 'defineEmit'依然非常幸运,这个报错定位到了具体的文件:
/vue-devui/sites/.vitepress/devui-theme/components/NavBar.vue这个文件从vue中导入了defineEmit这个方法:
<script setup lang="ts">
import { defineEmit } from 'vue'
import NavBarTitle from './NavBarTitle.vue'
import NavLinks from './NavLinks.vue'
import ToggleSideBarButton from './ToggleSideBarButton.vue'
defineEmit(['toggle'])
</script>错误就发生在这里。
非常巧,正好直播那天晚上,我们将vue devui的vue版本升级到了vue@3.1.5,从3.1.5这个版本开始,vue的一些api发生了变化,比如这里的defineEmit -> defineEmits。
解决方案
知道了原因,答案呼之即出。
直接把
defineEmit改成defineEmits即可。
以下是当时直播间手速最快的 hzttw 同学提的 pr:
问题三:使用 window/document 等浏览器变量导致的 vitepress ssr 构建问题
问题背景和描述
这也是一个非常典型的问题,最早发现于国庆节期间,当时我打算将 vue devui 的网站部署到域名,但我又不想购买云主机,所以打算白嫖码云的:部署到gitee.io域名。
部署之前得先构建网站的生产包,没想到那么久没执行yarn build命令,执行完直接报错了,先是包了问题一那个问题:
SyntaxError: Custom directive is missing corresponding SSR transform and will be ignored.这个问题好解决,直接安装 patch-vue-directive-ssr 补丁包即可:
yarn add -D patch-vue-directive-ssr安装完补丁包这个问题解决,再次构建还是出错,报了另一个错 I4D06D:
ReferenceError: window is not defined问题分析
很不幸,这个报错没有定位到具体的文件。
以下是报错的详细信息:
✓ building client + server bundles...
✖ rendering pages...
build error:
ReferenceError: window is not defined
at /vue-devui-theme/node_modules/vitepress/dist/client/app/temp/app.js:932:3
at Module.<anonymous> (/vue-devui-theme/node_modules/vitepress/dist/client/app/temp/app.js:937:2)
at Module._compile (internal/modules/cjs/loader.js:999:30)
at Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
at extensions..js (/vue-devui-theme/node_modules/esbuild-register/dist/node.js:2696:24)
at Object.newLoader [as .js] (/vue-devui-theme/node_modules/esbuild-register/dist/node.js:2262:9)
at Module.load (internal/modules/cjs/loader.js:863:32)
at Function.Module._load (internal/modules/cjs/loader.js:708:14)
at Module.require (internal/modules/cjs/loader.js:887:19)
at require (internal/modules/cjs/helpers.js:74:18)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.都是构建报错,我们对比下问题一的报错信息:
[vite:vue] Custom directive is missing corresponding SSR transform and will be ignored.
file: /Users/kagol/Documents/Kagol/code/vue-devui-theme/sites/components/loading/index.md:124:3
✖ building client + server bundles...
build error:
SyntaxError: Custom directive is missing corresponding SSR transform and will be ignored.
at Object.createCompilerError (/Users/kagol/Documents/Kagol/code/vue-devui-theme/node_modules/@vue/compiler-core/dist/compiler-core.cjs.js:19:19)
...还是发现了一些不同,问题一的报错出现在build bundles阶段,而现在这个报错build bundles是成功的:
✓ building client + server bundles...但是render pages阶段失败了:
✖ rendering pages...这里涉及到 vitepress ssr 构建的知识。
通过阅读vitepress源码,我们了解到我们执行vitepress build docs命令时,实际上构建的过程分成两个步骤:
- 调用
bundle方法,使用vite进行ssr构建,也就是构建日志中的building client + server bundles... - 调用
renderPage方法,使用vue router的router.go(routePath)进行页面的渲染,也就是构建日志中的rendering pages...
但是渲染页面的时候,vitepress并不知道具体是哪个文件出错,所以没法给出定位到具体文件的详细提示信息。
这时就需要靠有经验的程序员的直觉进行问题定位了。
由于是服务端渲染,并没有浏览器环境,只是一个nodejs的环境,因此window变量肯定是不存在的,所以提示:
ReferenceError: window is not defined但到底是哪个文件导致的报错呢?
先尝试全局搜索下关键字window,一共有20个文件包含window:
再加个点window.缩小下范围,还有17个文件包含window.:
通过慢慢分析每一个文件,就能解决这个问题。
解决方案
这个棘手的问题最终由Zcating同学解决。
fix(build): 修复 vitepress 打包时出现的问题
Zcating同学是devui开源组织的核心成员,从去年Ng DevUI刚开始开源以来就一直非常活跃,而且给我们的掘金专栏投过6篇RxJS原理分析的文章,vue devui组件库的第一个组件Button就是Zcating同学贡献的。
除了Button组件,Zcating同学还是Modal/Overlay等多个组件的田主,不仅频繁活跃地检视代码,而且承担着vue devui最复杂组件Table的设计和开发工作。
Zcating同学也在运营一个公众号:zcx的工作室,欢迎大家关注呀~
主要解决手段包括:
- 定义
inBrowser方法,在使用了window等浏览器变量的地方提前返回 - 将包含window等浏览器变量的代码移到
onMounted生命周期事件中
感兴趣的小伙伴可以看下Zcating同学的pr:
fix(build): 修复 vitepress 打包时出现的问题
发布时间: