Published on

Gitlab CI Runner npm build Cannot find module

Authors
  • avatar
    Name
    Adam Liu
    Twitter

翻车现场

null

这是 Gitlab Shared Runner CI 报告的错误,npm run build 的时候扑街了。Docker image base on image: node:10

背景交待

我这次改动是准备把query-string更新为>6.5 版本(之前是 4.3.4,看到这么大的升级我是有些忐忑的),这个版本有个新 feature 是支持arrayFormat: 'comma'。项目使用的 react-script(^3.0.1)全家桶版本内置的是query-string@4.3.4, 我是通过yarn why来得知的:

yarn why query-string

yarn why v1.17.3
\[1/4\] 🤔 Why do we have the module "query-string"...?
\[2/4\] 🚚 Initialising dependency graph...
\[3/4\] 🔍 Finding dependency...
\[4/4\] 🚡 Calculating file sizes...
=> Found "query-string@4.3.4"
info Reasons this module exists

- "react-scripts#mini-css-extract-plugin#normalize-url" depends on it
- Hoisted from "react-scripts#mini-css-extract-plugin#normalize-url#query-string"
  info Disk size without dependencies: "40KB"
  info Disk size with unique dependencies: "72KB"
  info Disk size with transitive dependencies: "72KB"
  info Number of shared dependencies: 2
  ✨ Done in 0.81s.

这个 bug 诡异的地方是,你 yarn install 或者 yarn.lock 重新生成之后,每次 Cannot found module 都是不一样的。

解决方案 tl;dr

long-term fix (这是我第二次部署时的解决方案)

null

直接把 node_modules 去掉,然后每个 job 重新 install,这样会牺牲 build 的速度。然后其实node_modules不应该去 cache,我们应该 cache yarn 或者 npm 的 cache,这也是官方推荐的做法。所以说,其实我之前的 cache node_modules并没有起到作用!!!!

我在本地环境用 docker 尝试去复现这个 bug,然后还是复现不了。所以我重新看了gitlab-ci.yml 发现 node_modules会被缓存,不同的 job 直接会直接 share 这个 folder。

直觉告诉我,node_modules在没有清空的清空下yarn install应该会让有些 package 变得不一致。而且node_modules是跟平台相关的,特别是有些 package 是 native addon 要是要用到 node-gyp 编译。

所以我让每个 CI/CD 的 job 都重新 yarn install 这样就保证每次 node_modules 都是最新和一致的。

不稳定的 fix(这是原来的做法)

基于重启一下试试的原则: 我删除了yarn.lock还有rm -rf node_modules然后在本地系统 yarn install,提交代码即可跑过。

过程

本地 Reproduce一下?

好吧,我本地既然重现不了这个问题。node.js 的 package 是深似海的,真不知道哪个 package 依赖了 OS 相关的东西,而且我本地的 macOS 和 Docker 环境差异这么大..

Image result for node.js package hell

Dependency Hell

Google 一下

我的代码是没有引用gensync的,因为我们有 eslint,如果引用了没有安装的 module,它会直接爆 error。

如上图所示,Cannot find module 'gensync'错误。我看到这个和babel-preset-react-app有关系我就直接搜索了关键字: babel-preset-react-app gensync

然而找到了一个比较吻合的stackoverflow 问题,然而并有人回答。

装一下 gensync?

gensync 现在最新是 1.0.0-beta.1,说实话我有点怕 npm 那些 beta 的东西,还有说好的 follow semver 怎么 patch version 更新有 breacking changes 呢?所以这个方法我直接跳过了。

更新一下 babel?

因为项目使用了 react-script 全家桶,内置了很多 package,这样贸然更新 babel 可能会直接导致版本冲突。

更新一下 react-script?

现在 react-script 最新版本是 3.4.1,和项目使用的差了 4 个 minor 版本。为了早点下班,真不想去处理那些兼容性的问题。况且,整个前端项目没有 cypress E2E 测试。手工测试就要我加班了。

降低一下 query-string?

好的,我就这样做了。这个 package 的 changelog 很不友好,要在 GitHub release page 翻页很多次。我直接找了中间不大不小的版本开始,最后找到了最小直接arrayFormat: 'comma'是 6.5。然而 CI pipeline 还是 failed 了,问题依旧是 Cannot find module 'gensync' 只是触发的地方不同了。

null

这个 gensync module 的问题更神秘了,然而为了下班我并不想怎么鸟它。

Search 一下 Gihub 的 issue?

找了babel还有query-string的 issue 都没有相关的。此时我心里已经在骂娘,一个破query-stringpackage 就是处理一下 query url 的,依赖这么多东西干嘛?

最后

最后我还是采用重启一下试试的方法。当然我可以深入挖掘一下问题所在,然后在 github report 一下 bug 啥的。但是我并没有这样做,因为我要下班做别的东西。如果你知道你可以留言告诉我。。。

问自己

问:不是有多环境 CI/CD 么?为什么部署到 testing 环境的时候,CI 没有 failed?

:因为 master branch 有新 feature 的代码,还不能直接 merge 到 production branch。此时又有 urgent 的 hot-fix,所以直接改了 production branch。然后 master branch 没有及时地 pull production branch 的 hot-fix。(我们这里是 master push 会 deploy 到 testing env,一打 tag 会部署 production branch 到 production env)