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

avatar
前端组件库 @华为

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

DevOps理论中有一个很重要的观点:在复杂的系统中工作时,我们不可能预测到所有的结果。

因此错误或缺陷在所难免,我们要将错误视作机会,学习和自我改进的机会,当我们深刻理解了错误,我们就能避免下一次更严重的错误。

Vue DevUI 是 Vue3 版本的 DevUI 组件库,基于 Ng DevUI

Vue DevUI 使用最新的技术栈进行开发:

在开发 Vue DevUI 的过程中,我们也遇到不少问题:

  1. 有些是我们的contributor提的issue
  2. 有些在和村长直播过程中发现的问题
  3. 还有一些和VitePress文档系统相关

以下是本文将要分享的问题列表:

问题一:vitepress中使用自定义指令导致的问题

问题背景和描述

第一个问题最早可以追溯到8月16日,由vue devui的早期贡献者wailen提出 I45VB6,当时vue devui的文档系统刚刚切换到vitepress一个多星期。

以下是wailen同学当时提的issue:

yarn build时会报错(loading组件报错)

当时通过执行yarn build文档构建命令就可以很轻易地复现该错误:

报错信息如下:

SyntaxError: Custom directive is missing corresponding SSR transform and will be ignored.

以下是当时wailen的截图:

图片.png

不过当时vue devui项目刚开始活跃,大家都忙着提交pr、提交issue、检视和合入代码,没有太关注到这个issue,而且当时咱们的网站还没有通过域名访问,不需要部署实际的主机,也就不需要执行yarn build构建生产包,因此都没关注到这个问题。

问题分析

图片.png

看截图的报错信息,是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-ssr

patch-vue-directive-ssr补丁包专门用于修补@vue/compiler-ssr,以使用SSR/SSG方式构建vue自定义指令。

问题二:defineEmit 导致的文档启动白页问题

问题背景和描述

这个问题最早发现于9月18日和村长在B站直播的那个晚上,以下是直播的录播地址:

【我要做开源】华为大佬亲授,Vue DevUI开源指南01:提交我的第一次pr

这个问题发生在执行yarn dev命令启动组件库文档的时候,执行完yarn dev命令,在浏览器地址栏输入http://localhost:3000/访问文档,出现白页。

图片.png

问题分析

打开浏览器控制台,发现红色的报错,提示了一个语法错误:

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 devuivue版本升级到了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:3building 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命令时,实际上构建的过程分成两个步骤:

  1. 调用bundle方法,使用vite进行ssr构建,也就是构建日志中的building client + server bundles...
  2. 调用renderPage方法,使用vue routerrouter.go(routePath)进行页面的渲染,也就是构建日志中的rendering pages...

但是渲染页面的时候,vitepress并不知道具体是哪个文件出错,所以没法给出定位到具体文件的详细提示信息。

这时就需要靠有经验的程序员的直觉进行问题定位了。

图片.png

由于是服务端渲染,并没有浏览器环境,只是一个nodejs的环境,因此window变量肯定是不存在的,所以提示:

ReferenceError: window is not defined

但到底是哪个文件导致的报错呢?

先尝试全局搜索下关键字window,一共有20个文件包含window

图片.png

再加个点window.缩小下范围,还有17个文件包含window.

图片.png

通过慢慢分析每一个文件,就能解决这个问题。

解决方案

这个棘手的问题最终由Zcating同学解决。

fix(build): 修复 vitepress 打包时出现的问题

Zcating同学是devui开源组织的核心成员,从去年Ng DevUI刚开始开源以来就一直非常活跃,而且给我们的掘金专栏投过6篇RxJS原理分析的文章,vue devui组件库的第一个组件Button就是Zcating同学贡献的。

除了Button组件,Zcating同学还是Modal/Overlay等多个组件的田主,不仅频繁活跃地检视代码,而且承担着vue devui最复杂组件Table的设计和开发工作。

Zcating同学也在运营一个公众号:zcx的工作室,欢迎大家关注呀~

图片.png

主要解决手段包括:

  1. 定义inBrowser方法,在使用了window等浏览器变量的地方提前返回
  2. 将包含window等浏览器变量的代码移到onMounted生命周期事件中

感兴趣的小伙伴可以看下Zcating同学的pr:

fix(build): 修复 vitepress 打包时出现的问题

欢迎一起建设 DevUI 开源项目

我们 DevUI 团队有多个开源项目,现在都在招募contributor,欢迎大家一起参与开源中来!(感兴趣的小伙伴可以添加DevUI小助手的微信:devui-official,将你拉到我们的核心开发群)

DevUI官网:devui.design/

也欢迎关注我和村长的【Vue DevUI开源指南】系列直播!

Vue DevUI开源指南系列直播打算分成两条线:

  1. 组件设计和实现
  2. 组件库的工程化

目前【组件设计和实现】已经完成了3期(还未结束):

  1. 【我要做开源】华为大佬亲授,Vue DevUI开源指南01:提交我的第一次pr
  2. 【我要做开源】华为大佬亲授,Vue DevUI开源指南02:做一个有模有样的Tree组件
  3. 【我要做开源】华为大佬亲授,Vue DevUI开源指南03:学会“单测”才会有安全感!完成Tree组件!

【组件库工程化】已经完成了2期(正在进行中):

  1. 【我要做开源】华为大佬亲授,Vue DevUI开源指南04:组件库工程化建设之项目初始化、jsx支持
  2. 【我要做开源】华为大佬亲授,Vue DevUI开源指南05:开源组件库中的文档建设,vitepress使用过程中的踩坑经历,克服这些困难你将收获多多!
  3. 【我要做开源】Vue DevUI开源指南06:手把手带你开发一个脚手架

已经跟村长老师达成共识image.png,只要村长老师的直播间不倒,只要还有小伙伴愿意参与进来,这个系列就会一直做下去!

欢迎大家持续关注、分享出去~我们一起来从0到1做一个vue3开源组件库!

每周五晚上九点,我们在村长的直播间,不见不散!

村长直播间地址