前端组件库本地开发调试的自动化流程实现

574 阅读6分钟

1.背景

目前要开发商业图表组件的组件库,主要是封装了商业常用的图表组件,基于Echarts组件。但是由于是上传到npm上组件进行管理,因此我们开发组件的时候,要想Demo项目能够实时调用,需要每次都发版然后Demo项目再更新依赖,对于小的组件版本规范也许不是很严格,但是本地化开发调试的配置还是很必要的。当模块化功能开发完成再进行测试发版,这才是最优的选择。因此本文主要讲述如何搭建自动化流程的本地组件库开发调试

文中涉及到的三方/二方组件库、组件、本地依赖、依赖、开源库、component 和 library 等词汇在此均指同一概念,即抽象出来的通用组件。

2.方案一:npm link

2.1 方案描述

代码逻辑:每次我们在组件库的开发Library项目中产生变更时,需要运行打包命令,将组件库build成node_modules可用的包。完成这一步之后需要将我们打包的结果npm link到全局的依赖,然后在Demo项目里面也是用npm link到我们前面打成的包并重启项目。这个时候,就可以在Demo本地中看到Library的更新。

npm run build // 执行构建
cd dist/hello // 进入构建后结果目录
npm link // 将 library 链接到全局

然后到项目所在目录重新绑定并重启服务

npm link @fudao/hello 
npm run start // 对应到具体执行脚本

但是这样也太麻烦了,每次Libary有更新的时候都要build之后link,两个项目link之后还要重启Demo,这样太难受了。Pass👋

3.方案二:暴力复制法

3.1 方案描述

和上面的方法一样,每次更新之后还是需要build,但是build之后不用link了,而是直接把我们的包复制到Demo项目对应的包里面,替换掉原来的包。然后在Demo项目的项目依赖配置里,对这个包采用文件路径依赖。like this⬇️

{
  "name": "big-platform",
  "dependencies": 
    {
        "@fudao/hello": "file:../hello/dist/hello"
    }
}

waring:每次Demo提交之前都要把这个改过来哈!不然线上直接无法使用

所以!这个方法还是得在组件库里面build,并且这个方式很容易产生线上问题,毕竟不是每一次都记得改的!!

  1. 方案三:源码引用

如果是 React 或者 Vue 项目,将 library 声明为一个 ES Module 并列好入口文件,那么直接更改项目中 import 方式(从包名改为路径形式)或是直接拷贝未构建代码均可达到调试的效果。如果是 Angular 项目,你可以在 tsconfig.json 中指定 library 的路径映射(直接引入)。

  1. 自动化组件本地项目调试搭建

上面的方案我们发现还是需要更改一些配置,或者每次都要进行一些没必要的操作。那么有没有什么方法可以自动监测文件的改动并且执行这些过程,让开发和调试的流程变得透明呢,只负责关注代码部分即可。在我们说其中一些细节之前,我们先介绍两个社区开源库,nodemon 和 yalc,我将它们用于我的自动化流程中了。

5.1 文件监控开源库 nodemon

nodemon 是一个用来监视 Node.js 应用程序中文件更改并自动重启服务的开源库,仅用于开发环境(推荐)。

使用上不需要对项目代码做任何操作,命令也只是简单将 node 替换为 nodemon,你可以用如下命令安装它:

npm i -g nodemon

然后配置一下自定义参数,比如观察的文件类型(是只观察 .ts 文件还是 HTML/CSS/TypeScript 的文件变更都需要被监控)、需要观察的文件路径、需要忽略的路径(比如 node_modules)以及自定义命令等。

虽然 nodemon 被设计用来监控重启 Node 应用,但是也支持监控执行自定义命令,比如在我的项目中我通过如下命令使用 nodemon 来监控我的代码变更:

nodemon 
    --ignore dist/  # 忽略目录
    --ignore node_modules/ 
    --watch BiliCharts # 观察目录
    -C  # 只在变更后执行,首次启动不执行命令
    -e ts,html,less,scss,svelte  # 监控指定后缀名的文件
    --debug  # 调试
    -x "npm run build && cd dist && yalc push"  # 自定义命令

5.2 本地依赖管理开源库 yalc

如果你在本地调试过外部依赖库,那么一定对 npm link 不会陌生,通过 link 命令可以将我们要使用的外部依赖从本地链接到全局 node_modules,之后在具体项目中我们再把他 link 进来,则完成了一次操作。但如果我们的项目和 library 共同维护了一份框架代码副本,那么 link 可能还会有一些其他意想不到的错误。

yalc 是一个类似于本地化 npm 的解决方案,它在本地环境中创建了一个共享的 library 存储库,使得你在需要使用本地依赖时可以快速从这个存储库拉取资源进行消费。当在指定 library 中运行 yalc publish 时,它会将本来发布到 npm 上的相关文件存储在本地这个共享的全局存储中,而在项目中通过 yalc 添加依赖时, yalc add @fudao/hello 会从全局存储拉入信息到项目根目录的 .yalc 文件夹,并将一个文件 "file:.yalc/@fudao/hello" 注入 package.json

yalc 比较诱人的一点在于他还有一个命令叫 yalc publish --push 或者简称 yalc push,他会将你的依赖发布到本地存储库(更新状态),并将所有更改传播到现有通过 yalc安装的依赖中,这个操作实际上进行了一次 update 操作,此处不再展开,感兴趣的同学可以移步官方文档查看更多。

如此一来,你可以完全按照 npm install 从远程 registry 拉取依赖的方式安装和消费一个本地依赖,Cool。

5.3 自动化流程搭建

暂时无法在飞书文档外展示此内容

暂时无法在飞书文档外展示此内容

5.3.1 组件库项目中搭建nodemon+yalc

Makefile文件

init: #初始化依赖
    npm install
    npm install -g nodemon yalc
push: #发布并推送到yalc仓库
        yalc publish --push

watch: #监测文件改动并且调用push
          nodemon \
                          --ignore dist/ \
                          --ignore node_modules/ \
                          -C -e ts,html,less,scss,svelte,js \
                          --debug -x "npm run build && make push"    

当组件库更新时,会自动更新yacl仓库,无需在run build。

5.3.2 在项目中订阅yalc仓库中的组件

add-biz-chart:
    yalc add @bilibili-business/BiliCharts
remove-yalc:
    yalc remove --all
git-commit:
    make remove-yalc
    git add .
    git commit -m $(m)
git-commit-push:
    make remove-yalc
    git add .
    git commit -m $(m)
    make push
git-push:
    git push

注意:vite 无法检测到 yalc 安装的包的变化,因此虽然每次项目里的依赖会自动更新,但是页面并不会刷新,此时使用的还是缓存内的包的内容。解决方法是:

  1. 禁止vite对本地这个包进行缓存,并且将需要调试的包排除在优化之外。配置如下⬇️

  2. 强制刷新浏览器。

export default defineConfig({
  server: {
    watch: {
      ignored: ['! /node_modules/ @bilibili-business/BiliCharts/ ']
    }
  },
  // 被监听的包必须被排除在优化之外,
  // 以便它能出现在依赖关系图中并触发热更新。
  optimizeDeps: {
    exclude: [' @bilibili-business/BiliCharts']
  }
})

如果是vue-cli,配置为

  configureWebpack: async config => {
    if (inProduction) {
      // 线上配置
    } else {
      // 开发环境
      config.watch = true // 文件更改将触发整个页面重新加载
      config.watchOptions = {
        ignored: ['! /node_modules/@bilibili-business/BiliCharts/ ']
      }
    }
  },