组件库本地调试自动化方案

背景

日常开发中,一个项目的代码往往不只在一个项目仓库下,一些功能独立、复用性强的组件或者工具函数等,可抽离成单独的通用组件,通过依赖包的形式安装进来,其他同学也可以很方便地在其他项目中调用。比如业务项目叫my-project,抽离的组件库@cute/hello发布到npm上,项目中通过npm install @cute/hello --save,就可以直接引用组件库了。

调用组件库是一件很快乐的事情,只需要调调API就能实现。但是如果组件库有bug,你想在组件库下调试完毕后,在真实有问题的项目环境去开发调试,却无从下手。有人想到可以先npm publish发布一个测试的beta包,再在项目中npm install,但这样一来一回频繁调试的时候就浪费了很多时间,况且第三方组件库不允许你去操作发布测试的。怎么能做到组件库开发和调试时像内嵌在项目的代码一样流畅,无额外感知成本呢?那么这就涉及到组件库的本地调试了。

image.png

下面会先介绍三种常见组件库本地调试方法,最后会总结一种自动化调试方案:使用nodemon+yalc实现自动化调试本地组件库。想直接看自动化调试的可以跳到最后面。

1、 常用的npm link方式

2、 修改项目package.json依赖路径

3、 复制构建的组件库产物到项目库的node_modules下

4、 自动化调试方案:nodemon+yalc

说明:文中所讲的组件库、library、依赖包、开源库等词汇在此均指同一概念,即抽象出来的通用组件。

以往的调试方式

大致来看,会有几种常见的调试方式,但是都有其局限性。

1. 常用的npm link方式

通过npm link的方式建立组件库和项目之间的联系,这也是较常用的方式。每当组件库代码变更后,通过在组件库发布代码所在目录执行以下

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

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

npm link @cute/hello
npm run start // 对应到具体执行脚本
image.png

npm link后输出和项目绑定link示例如下,通过执行发现,组件库npm link后会在发布代码目录下也生成一个node_modules会用来存放组件库自身依赖的dependencies。my-project执行npm link @cute/hello后会把组件库发布目录下的代码都同步到项目的node_modules下了。

➜  cute-hello git:(xxx) cd dist
➜  dist git:(xxx) npm link
npm notice created a lockfile as package-lock.json. You should commit this file.

added 4 packages from 6 contributors and audited 4 packages in 4.75s
found 0 vulnerabilities

/usr/local/lib/node_modules/@cute/hello -> /Users/user/cute-hello/dist

➜  my-project git:(xxx) npm link @cute/hello
/Users/user/my-project/node_modules/@cute/hello -> /usr/local/lib/node_modules/@cute/hello -> /Users/user/cute-hello/dist

my-project 与本地组件库 npm link 后,它的 node_modules 中的 @cute/hello 代码是本地组件库发布目录 link 后的代码。

每次组件库代码更改后,在组件库进行 npm run build 操作后,项目执行 npm link 后,它会去 link 的地址去找资源文件(也就是组件库),所以它的资源文件不在项目下,webpack不会对其做预编译,所以如果组件库本身还依赖其他的依赖库,需要每次构建后在组件库执行npm link,它才会自动生成组件库自身依赖并注入 node_modules 中 ,这样项目库才能找到组件库的依赖,不然会导致实际构建或者运行时报错,项目库会找不到组件库自身的依赖。

image.png

调试完毕后解除link操作,项目重新 npm install 依赖

npm uninstall -g @cute/hello // 解除组件全局link

整个调试流程如下图。

image.png

操作成本:

  • 每次组件库修改需要build构建
  • 组件库有自身依赖时构建后需执行npm link和项目重启服务
  • 结束调试后解除link,安装正确的生产依赖包
  • 组件库和项目库都有调试成本

适用场景:

  • 在一些命令行工具库里面尤其好用,完全零调试成本,全局的命令行工具甚至不需要在项目库安装依赖包就能调试;
  • 组件库自身没有依赖的简单情况下

2. 修改项目package.json依赖路径

修改 package.json 中组件库为本地组件库路径,需要在项目库重新执行 npm install 安装依赖。但是项目库中安装依赖,实际上是把依赖安装到组件库下了,项目下并没有把组件库自身依赖安装到项目下。

// package.json
"dependencies": {
    "@cute/hello": "file:/Users/user/cute-hello/dist",
}

可以看到 package-lock.json 中组件自动引用本地相对路径

// package-lock.json
"@cute/hello": {
      "version": "file:../cute-hello/dist",
      "requires": {
        ...
      },
  }

每次组件库代码更改后,在组件库进行npm run build构建,这里同样会面临像npm link那样的尴尬处境,项目会去组件库找组件的自身依赖,如果没有找到则会启动错误,所以组件库每次构建完你都需要在项目重新执行npm install安装组件库的自身依赖。

调试完毕提交代码及上线前需要手动把package.json更新回正确的依赖包地址。

整个调试流程如下图。

image.png

操作成本:

  • 每次组件库修改需要build构建

  • 项目重新执行npm install

  • 结束调试后重新安装正确的生产依赖包

  • 上线前需要手动修改package.json的正确依赖包地址

适用场景:
组件库自身没有依赖的简单情况下

3. 复制组件库产物到项目库node_modules下

在组件库构建后,将dist下的构建产物复制到项目 node_modules 的@cute/hello目录下,组件库下执行命令:

cp -r dist /Users/user/my-project/node_modules/@cute/hello

每次组件库代码更改后,都需要在组件库进行npm run build操作,而且项目的node_modules下组件库复制完可能不会触发热更新,需要删掉项目下组件库再执行cp命令,那么命令改成先删除再复制,这样就可触发项目的热更新了。

rm -rf /Users/user/my-project/node_modules/cute/hello && cp -r dist /Users/user/my-project/node_modules/@cute/hello

整个调试流程如下图。

image.png

操作成本:

  • 每次组件库修改需要build构建

  • 每次需要在组件库执行cp命令

  • 结束调试后重新安装正确的生产依赖包

  • 只需要在组件库下执行一些操作命令,项目库无额外操作成本

适用场景:

  • 基本都能适用

自动化调试流程:nodemon+yalc

自动化调试流程依赖【文件监控开源库 nodemon】和【本地依赖管理开源库 yalc】,大致思路是用nodemon监听文件修改,然后自动执行组件库打包,再使用yalc进行组件库发布。

nodemon 是一个用来监视应用程序中文件更改并自动重启服务的开源库,仅用于开发环境(推荐),他不影响项目代码,可以理解为是把node替换成nodemon执行命令。

yalc 是一个类似于本地化 npm 的解决方案,它在本地环境中创建了一个共享的 library 存储库( ~/.yalc ),当你需要本地依赖时可以快速从存储库中拉取资源进行使用。它与 npm link 不同就是 npm link 中组件库和项目引用的依赖是映射到一个地方的,当项目库启动时会在依赖下去寻找其他依赖,如果找不到相关依赖,应用就会异常;如果组件库的编译规则和项目的编译规则不匹配,也同样会出问题。而 yalc 就是相当于将文件复制进依赖目录从而能正常运行。


image.png

更多详情可以看以下链接

● yalc: https://github.com/whitecolor/yalc

● nodemon: https://github.com/remy/nodemon

自动化流程

自动化流程通过使用nodemon监听文件修改后,自动执行组件库打包,再使用 yalc push 进行组件库发布,项目只要 yalc add [package] 后,后续就能直接热更新下预览变更了。具体实现流程下面会介绍。

image.png

首先,全局安装nodemon和yalc:

npm install -g yalc  // 全局安装
npm install -D nodemon // 组件库安装
// 或
yarn global add yalc
yarn global add nodemon -D

组件库单独执行 yalc publish 时会把当前组件库下相关文件存储到本地共享的全局存储中,除了不会发布到真实远端仓库外,都和npm真实发包无异。更好用的是 yalc publish --push 或者简称 yalc push ,它会将你的依赖发布到本地存储库(更新状态),并将所有更改传播到现有通过 yalc 安装的依赖中,下面会用到。

dist git:(xxx) ✗ yalc push
@cute/hello@2.0.0-beta.2 published in store.

在组件库的 package.json 中添加 nodemon 脚本命令,这里可以新建一个 nodemon.json 的配置文件去配置详细的信息(具体配置可以去官网查看)。nodemon 启动监听,当监听文件变化时自动 build 构建,并将库 yalc push 发布到缓存中。

如果当前构建后,package.json 中 private: true 时,直接 yalc push 会报错:Will not publish package with private: true use --private flag to force publishing. 需要使用 yalc push --private 强制发布。

{
    "scripts": {
        "build": "node scripts/dist.js",
        "build:watch": "nodemon --config 'nodemon.json' -x 'npm run build && cd dist && yalc push --private'"
    },
}
// nodemon.json
{
  "restartable": "rs",
  "ignore": [
    ".git",
    "node_modules/**/node_modules",
    "package.json",
    "nodemon.json",
    "dist",
  ],
  "verbose": true,
  "execMap": {
    "js": "node --harmony"
  },
  "events": {
    "restart": "osascript -e 'display notification \"App restarted due to:\n'$FILENAME'\" with title \"nodemon\"'"
  },
  "watch": ["src"],
  "env": {
    "NODE_ENV": "development"
  },
  "ext": "js,json,css,scss,vue"
}

上面组件库的准备工作完成后,项目下只要执行 yalc add @cute/hello ,在项目根目录下就会自动生成一个 yalc.lock 文件和 .yalc 目录,.yalc 目录类似 node_modules 那样,它存放着从存储库中拉取下来的依赖,yalc.lock 记录当前被替换的组件库版本信息,这些信息用来后面还原依赖包用。同时 my-projecy 中的 node_modules 的组件库也被替换成 yalc 缓存中的组件库了。

my-project git:(xxx) yalc add @cute/hello
Package @cute/hello@2.0.0-beta.2 added ==> /Users/user/my-project/node_modules/@cute/hello

package.json的组件库地址自动注入了 file:.yalc/@cute/hello 。

"dependencies": {
    "@cute/hello": "file:.yalc/@cute/hello",
}

项目根目录下自动生成了 yalc.lock 文件和 .yalc 目录:

# yalc.lock
{
  "version": "v1",
  "packages": {
    "@cute/hello": {
      "signature": "519aa4086b04e080b8d9731188dd162d",
      "file": true,
      "replaced": "@cute/hello@2.0.0-beta.1"
    }
  }
}
image.png

此时,就可以快乐地进行组件库和项目库之间的调试了,不需要额外的操作成本,所改代码即所视。

调试完毕后,要提交代码部署到公测环境时,执行 yalc remove --all(如果只引了一个依赖包也可直接 yalc remove [package],yalc remove --all 会将当前所有从 yalc 存储中拉取的都还原),即可一键还原安装包现场,上面说到的package.json会自动还原了依赖包版本、.yalc、yalc/lock都自动去掉了,还原了开发调试前的现场,但是node_modules中的对应的组件库也去掉了,所以完成调试后本地只需要重新npm install安装正常版本即可后续开发。

➜ my-project git:(xxx) ✗ yalc remove --all
Removing installation of @cute/hello in /Users/user/my-project

总结

总结一下,自动化调试流程就是在组件库使用nodemon监听文件变更后,自动执行 build 构建和 yalc push,项目中通过 yalc add [package] 从本地存储中拉取依赖包进行调试,调试完成后 yalc remove --all 一键恢复调试前现场。

其实以往的调试方式都可以加 nodemon 命令去监听达到自动化调试的目的,但是却有一些局限性(如下表),纵观来看 yalc 的方式更加通用且逻辑清晰,组件库和项目库不需要花太多时间去理会中间的执行过程,只需要像 npm 安装依赖一样,在项目中通过 yalc 引入多个组件库进行调试,调试完毕后 yalc remove --all 即可清除所有调试库。

调试方式 \ 对比 nodemon改造 局限
npm link 组件库nodemon监听文件变化->build构建->npm link 项目需要重启服务;编译规则不匹配,也可能会出问题
cp复制构建产物 组件库nodemon监听文件变化->build构建->scripts中添加cp命令 如果有多个项目在用组件库,需要写多套cp命令调试
修改package.json依赖库地址 组件库nodemon监听文件变化->build构建->自动进入项目库执行npm install 项目库每次install很繁琐,调试完成后项目的依赖地址需要手动恢复,这样一点也不cool

更多阅读

● npm link:https://docs.npmjs.com/cli/v8/commands/npm-link

● yalc: https://github.com/whitecolor/yalc

● nodemon: https://github.com/remy/nodemon

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,406评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,976评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,302评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,366评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,372评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,457评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,872评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,521评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,717评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,523评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,590评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,299评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,859评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,883评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,127评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,760评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,290评论 2 342

推荐阅读更多精彩内容