升級Yarn 2,擺脫node_modules

前端晚間課 發佈 2022-02-17T01:17:16+00:00

node項目中最臭名昭著的莫過於node_modules文件夾,這個糟糕的結構動輒使你的文件數目增加幾萬甚至幾十萬,無論是安裝還是刪除,都要消耗大量時間,並且占據大量inode結點,我們隨便進入一個react項目文件夾,看一下由於有node_modules會使你的項目中的文件個數

node項目中最臭名昭著的莫過於node_modules文件夾,這個糟糕的結構動輒使你的文件數目增加幾萬甚至幾十萬,無論是安裝還是刪除,都要消耗大量時間,並且占據大量inode結點,我們隨便進入一個react項目文件夾,看一下由於有node_modules會使你的項目中的文件個數變成多少:

$ find . -type f | wc -l
223629

僅僅一個項目下面就有多達22萬個文件。

現在我們來看一下目前的yarn版本號是多少:

$ yarn --version
1.22.11

嗯,目前yarn的版本號是1.22.11,那我們如何安裝yarn 2呢?答案是不需要安裝,只需要設置就可以了。

$ yarn set version berry

設置完了之後,我們再來看一下yarn的版本號:

$ yarn --version
3.0.0

不是說好的升級到yarn 2嗎?怎麼變成3.0了?不用恐慌,越高越好。

然後我們來看一下項目文件夾下多了這麼幾個文件,首先就是根目錄下多了一個.yarnrc.yml,裡面只有一句話:

yarnPath: .yarn/releases/yarn-berry.cjs

相應的,還多了一個文件夾.yarn,裡面有一個子文件夾releases,裡面有一個文件yarn-berry.cjs,這幾個文件就是全部yarn 2增加的內容了,這些內容不要在.gitignore里忽略,其它的內容是需要忽略的,現在我們來在.gitignore里增加一些需要忽略的內容:

/node_modules
/.pnp
.pnp.js
.pnp.cjs
.yarn/cache
.yarn/unplugged
.yarn/install-state.gz

接下來,我們準備利用新版的yarn安裝我們的依賴文件,在此之前,我們需要先設置一下yarn庫的鏡像伺服器以加快整個下載過程:

$ yarn config set npmRegistryServer https://registry.npm.taobao.org

這時候,你再打開項目根目錄下的.yarnrc.yml文件,會發現裡面多了一行:

npmRegistryServer: 'https://registry.npm.taobao.org'
yarnPath: .yarn/releases/yarn-berry.cjs

所以我們知道其實這個yarn config命令也沒有什麼特別的地方,只是通過它來修改.yarnrc.yml文件而已,你也可以通過直接修改.yarnrc.yml文件來達到同樣的效果。

現在,我們開始刪除舊的node_modules文件夾和yarn.lock文件,並重建整個項目:

$ rm -rf node_modules
$ rm -f yarn.lock
$ yarn

整個下載過程應該還是比較順利的,我們來看一下項目文件夾中多了哪些文件:

.yarn/cache
.yarn/unplugged
.pnp

沒有了node_modules文件夾,我們來看一下.yarn/cache文件夾下有什麼內容,裡面有我們之前依賴的node_modules文件夾下的所有依賴包,但不再是以目錄的形式存在,而是變成了一個個zip文件,yarn 2就是利用項目根目錄下的.pnp.cjs文件定位到這些zip文件以達到取代node_modules的作用,這樣極大程度地減少了項目中的文件個數。

下面我們開始啟動項目:

yarn start

十有八九你的項目這時候是啟動不起來的,不要慌,這篇文章告訴你所有的解決方法。

首先,你遇到錯誤可能是這樣:

Error: Your application tried to access terser-webpack-plugin, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound.

具體內容可能不一樣,但你要注意這個關鍵詞Your application,這說明是你的代碼當中的某個位置引用了後面的插件,但你沒有在package.json文件中顯式聲明它,那為什麼之前用yarn 1或者npm的時候沒有這個問題呢?因為以前是有node_modules文件夾的,所有依賴包都被平攤在這個文件夾中,即使是被其它依賴的依賴引入的,它也會被釋放在node_modules根目錄下,所以node可以很輕鬆地找到它,而現在這個文件夾沒有了,我們必須顯式地在package.json文件中引用它,才能引導yarn找到這個依賴項。因此,解決這種Your application缺乏某個依賴項的方法很簡單,我們只需要用yarn安裝它就可以了:

yarn add -D terser-webpack-plugin

哦,又出錯誤了:

Invalid options object. Terser Plugin has been initialized using an options object that does not match the API schema.

這是因為我們在安裝的時候沒有指定版本,導致安裝的插件版本過高,我們在package.json里把版本降低一些:

"terser-webpack-plugin": "^4.2.3",

然後重新執行yarn進行安裝,運行yarn start再次啟動,終於啟動起來了!不過,不要高興得太早,又遇到了這樣的問題:

Error: Your application tried to access @babel/plugin-transform-async-to-generator, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound.

不要慌,既然還是Your application缺乏某個依賴包,那就還是我們的問題,停下來再安裝它,然後再啟動,直到解決完所有Your application引起的問題。

這時候,產生了新的錯誤:

Module not found: rc-bmap tried to access babel-runtime, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound.

雖然同樣是找不到依賴項,但這次的錯誤不是由於我們自己的應用導致的,而是由於依賴項自身導致的,這種問題該如何解決呢?不要急,我們打開.yarnrc.yml文件,按照錯誤提示增加以下設置:

packageExtensions:
  'rc-bmap@*':
    dependencies:
      'babel-runtime': '*'

缺什麼咱們就增加什麼,有時候還要注意版本號。同樣,這個問題不是由於yarn 2導致,而是因為我們的依賴項該增加的依賴沒有增加而已,我們這裡只是給它補全依賴,使它得以正常運行。

別忘了,每次修改完.yarnrc.yml之後,都需要重新執行yarn,然後再執行yarn start

至此為止,我們的項目終於能夠成功運行了!我們來看一下目前項目文件夾中的文件個數:

$ find . -type f | wc -l
17433

現在只有17000個文件了,比我們最開始的22萬個文件減少了20多萬,運行速度也成倍提升。

怎麼樣,是不是很值得一試呢?

文章來源於@張京老師,https://segmentfault.com/a/1190000040520326

關鍵字: