當前位置: 妍妍網 > 碼農

在前端中,什麽是幽靈依賴?

2024-04-21碼農

前言

大家好,我是林三心, 用最通俗易懂的話講最難的知識點 是我的座右銘, 基礎是進階的前提 是我的初心。

幽靈依賴?

前幾天在公司的技術分享會上,我總是聽到大佬們在提起一個名詞—— 幽靈依賴 ,起初我沒有太在意,以為這個不太重要,所以就沒怎麽去了解這個名詞。

直到我在做計畫 pnpm遷移 的時候,我突然很想知道它跟 幽靈依賴 到底有什麽關系呢?

其實在了解什麽關系之前,我應該去了解一下什麽是 幽靈依賴 ,我們接著聊!!!

什麽是幽靈依賴?

比如我現在,我在開發一個計畫A,計畫A中我裝了 npm-lsx 這個包,而這個 npm-lsx 的包依賴了 npm-test ,咱們來看看這兩處 packages.json

依賴關系是:A <- npm-lsx <- npm-test

// A/packages.json
{
"name""A",
"dependencies": {
"npm-lsx""^1.0.0"
}
}
// A/node_modules/npm-lsx/packages.json
{
"name""npm-lsx",
"dependencies": {
"npm-test""^1.0.0"
}
}

node_modules規則

如果按照 node_modules 的規則的話,那麽目錄的結構應該是這樣的

node_modules
├── npm-lsx 
| └── node_modules
| └── npm-test

但是如果依賴關系很長的話,那麽會導致目錄深度非常深,所以我們常用的 npm、yarn 解決了這個問題

npm、yarn

它們是怎麽解決這個問題的呢? npm、yarn 為了解決依賴關系過長時,導致的目錄結構過深,采用了 扁平化 ,也就是所有依賴都被拍平到 node_modules 目錄下。這樣的好處就是,不再有層級過深的問題。

現在目錄結構變成這樣了

// A/node_modules
node_modules
├── npm-lsx 
├── npm-test

幽靈依賴

接著上面的範例,繼續聊,請看下面的程式碼

const lsx = require('npm-lsx')
const test = require('npm-test')
lsx()
test()

你們覺得這段程式碼有問題嗎?其實執行起來是沒問題的。但是問題來了,我們計畫中居然能直接參照 npm-test 這個包!!!

我們都知道依賴關系是:

A <- npm-lsx <- npm-test

按理說, A 是不能直接參照 npm-test 的,因為沒有直接依賴關系啊!!!但是因為前面說了, npm、yarn 會將依賴拍平在 A的node_modules 中,這導致了 A 可以直接 require('npm-test')

我們稱這個 npm-test 幽靈依賴 !!!

幽靈依賴的壞處?

某天 npm-lsx 不依賴 npm-test 了

已知你現在程式碼是這樣

const lsx = require('npm-lsx')
const test = require('npm-test')
lsx()
test()

某天 npm-lsx 升級了!它不再依賴 npm-test 了!那麽此時 A node-modules 中變了!

// 以前
node_modules
├── npm-lsx 
├── npm-test
// 現在
node_modules
├── npm-lsx

那麽你的程式碼會報錯!

const lsx = require('npm-lsx')
const test = require('npm-test'// 沒有
lsx()
test() // 報錯!!!

其實這個情況還好,因為這種情況在打包上線過程中就會報錯依賴找不到了,所以不太會造成線上的報錯崩潰

多計畫參照同一個幽靈依賴

我現在有兩個計畫 A B

A 中的 node_modules 目錄為,現階段 npm-test 的版本為 1.0.0

// A/node_modules
node_modules
├── npm-lsx 
├── npm-test 版本號:1.0.0

A 中某個檔的程式碼為

const test = require('npm-test')
test()

B 中某個檔的程式碼為

const test = require('npm-test')
test()

當有一天 npm-lsx 所依賴的 npm-test 升級了!版本升級為了 2.0.0

// A/node_modules
node_modules
├── npm-lsx 
├── npm-test 版本號:2.0.0

此時 test 的用法也變了~而因為 A 計畫已經回歸過了,所以他知道,也改了對應的程式碼

const test = require('npm-test')
test.run() // 修改程式碼

B 計畫就沒那麽好運了,它並沒有進行回歸,所以並沒有去改程式碼!!!!

const test = require('npm-test'// 有
test() // 直接報錯

這就慘了, B 計畫在打包階段並不會因為依賴不到 npm-test 而報錯,所以它會順利上線。。然後,等到了線上執行起來,直接報錯!!!這是非常嚴重的的事故!

結語

點個【贊】和【在看】是對林三心最大的鼓勵,林三心會非常開心的~~~

關註公眾號【前端之神】,回復【加群】,即可獲得加入【千人前端學習大群】的方式,交流找工作,摸魚,吹水~