如何與NPM package-lock.json愉快地玩耍

富途web開發團隊發表於2019-03-04

歡迎關注富途web開發團隊,php , 前端需要你。缺人從眾

富途一天天的在成長,小夥伴們也越來越多。前端的更新迭代,一直都在進行。Vue已經作為前端的主要開發框架,想想2年前,我還在寫JQ,後面寫angular.js。前端打包也從原來的打包檔案提交入Gitlab庫,到後來接入jenkins(打包檔案不入庫),再到今天的Gitlab CI。

敢於嘗試,推動落地執行。

今天給大家分享一下前端打包接入Gitlab CI遇到的坑。

另外附帶一個用於下載Gitlab CI 打包檔案的元件:檢視元件

背景

對的,最近寫文章都會交代一下背景。因為按標題的套路,這本應該是一篇教程類的文章,但這種文章其實挺無趣的。之所以想寫這篇,是因為確實碰到了一些很麻煩的事情。閒言少敘,我們進入正題。

最近我們前端程式碼打包正在接入Gitlab CI,使用Docker來作為Executor,也就是在Docker中進行前端程式碼打包,然後收集打包結果,以備釋出時使用。打包時Docker映象很自然地就選擇了官方Node映象,最新版本(Node 10)。

一開始我們嘗試性地接入了幾個專案,有使用NPM scripts進行打包的,也有使用Gulp進行打包的,一切都很正常。但是昨天在接入一個新專案,使用Gulp打包的時候,卻突然碰到了報錯:

$ gulp gitlab-ci
gulp[85]: ../src/node_contextify.cc:631:static void node::contextify::ContextifyScript::New(const v8::FunctionCallbackInfo<v8::Value>&): Assertion `args[1]->IsString()` failed.
Aborted
ERROR: Job failed: exit code 134
複製程式碼

看了一眼這個錯誤資訊,一下子就發現,這並不是來自JS層的錯誤,而是來自Node原生層,這就超出了我的理解範圍了。

模組版本相容問題

通過搜尋,首先找到一篇中文的解決方案:升級node10後gulp報錯的解決辦法。文中給出瞭如下解決辦法:

rm -fr node_modules
rm -fr package-lock.json
npm cache clean --force
npm install
複製程式碼

所以這是什麼原理呢?沒看到文章有解釋,另外這文章本身也寫得不是很清楚。抱著半信半疑的態度,在CI的指令碼中加上了npm cache clean --force,結果問題依舊。

接著搜尋了一下,很快發現一些和這個問題有關的issue:

通過npm ls,一下子就看到了natives模組的版本是1.1.1,於是定位到真正的問題:gulp依賴vinyl-fsvinyl-fs依賴graceful-fsgraceful-fs依賴natives,而natives在1.1.3之前都不相容Node 10。

那麼解決方案就簡單了,想辦法升級一下模組不就好了?

如何升級間接依賴

首先想到的是Gulp是否有解決這個問題,npm info gulp看了一下,發現最新版本是3.9.1,然後npm ls一下,發現本機裝的已經是3.9.1了,也就是說,Gulp根本沒有升級的可能。那要如何升級這個間接的依賴呢?

這裡我繞了個彎子,package.json中直接依賴的模組無法升級,npm update也不能搞定。於是想到,如果顯式安裝一下這個模組,是不是能解決問題?

npm install natives@1.1.3
複製程式碼

安裝完之後還要在package.json中將直接依賴natives刪除(因為我並不直接依賴它,留著沒用)。然後再次檢視依賴:

▶ npm ls natives
seed@1.0.0 /Users/TooBug/work/oa/learn/frontend
└─┬ gulp@3.9.1
  └─┬ vinyl-fs@0.3.14
    └─┬ graceful-fs@3.0.11
      └── natives@1.1.3
複製程式碼

這次對了。

但是,這個操作我是在本機進行的,這個操作到底改了什麼呢?如果去CI上再次執行npm install,會不會依然安裝到舊版本呢?畢竟package.json並沒有任何改動。

於是翻看了一下git diff,發現了本文的主角package-lock.json被修改了,其中的natives由1.1.1變成了1.1.3。

"natives": {
    "version": "1.1.3",
    "resolved": "http://registry.npm.oa.com/natives/download/natives-1.1.3.tgz",
    "integrity": "sha1-RKV5vmRQfqLW7RygSpQVkVz3VVg="
},
複製程式碼

於是怦然大悟:本來npm在安裝模組是是按語義化版本安裝最新版的,但是在CI上卻沒有安裝natives 1.1.3版本,而是安裝了natives 1.1.1版本,這正是因為package-lock.json裝版本鎖定了,從而導致了與Node 10的不相容問題。

這也能很好地解釋,為什麼其它專案沒有這樣的問題,因為其它的專案在程式碼倉庫中沒有包含package-lock.json,在安裝時自然就安裝了natives 1.1.3版本。

於是再回頭看一開始搜到的文章提出的解決辦法:

rm -fr node_modules
rm -fr package-lock.json
npm cache clean --force
npm install
複製程式碼

其實是非常有效的,因為它將package-lock.json直接刪除了,然後重新安裝一遍最新版本,生成新的package-lock.json,從而解決問題。

延伸:如何正確地在專案中使用package-lock.json

最後,也補充說明一下package-lock.json的正確用法。(雖然我知道,但還是不小心踩坑了。如果不清楚它的用法的話,可能會在坑裡待更長時間爬不出來。)

首先,需要確保npm的版本在5.6以上,因為在5.0 – 5.6中間,對package-lock.json的處理邏輯更新過幾個版本。5.6以上的才是符合認知的邏輯。

然後,在專案中如果沒有鎖版本的必要,可以不使用package-lock.json,在安裝模組時指定--no-lock即可。

如果專案中有package-lock.json,則安裝模組時會以這個檔案中指定的版本和地址為準,直接下載安裝。(除非它和package.json中指定的版本不相符。)

最後,如果已經鎖定了版本的情況下,需要更新直接依賴,則直接安裝指定版本,package.jsonpackage-lock.json都會同步更新。如果需要更新間接依賴的話,則需要像本文這樣,手工安裝一下,保證package-lock.json被更新到。或者如果其它模組的鎖定並不是那麼重要時,也可以直接刪除package-lock.json,然後重新安裝一遍,相當於把所有(直接依賴+間接依賴)模組全部更新一遍。

原文連結:檢視原文

相關文章