[部署翻车系列] Gitlab CI Runner npm build Cannot find module

这是一场生产环境部署过程的翻车现场分析。

翻车现场

这是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 (这是我第二次部署时的解决方案)

直接把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' 只是触发的地方不同了。

这个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)

2 Replies to “[部署翻车系列] Gitlab CI Runner npm build Cannot find module”

  1. 我也遇到了这个问题 我的方法是npm i gensync之后再用版本管理工具还原更改 再build就不会报错了。。。

    1. 我也试了你的方法,过了一段时间后又发生了类似的问题,最后发现原来是我在CI环境cache了node_modules。到目前Cannot find module这个问题再没出现过了。

Leave a Reply

Your email address will not be published. Required fields are marked *