包管理基礎

在本文中,我們將詳細瞭解包管理器,以便理解如何在自己的專案中使用它們——安裝專案工具依賴項、保持它們更新等等。

先決條件 熟悉核心 HTMLCSSJavaScript 語言。
目標 瞭解什麼是包管理器和包儲存庫,為什麼需要它們以及如何使用它們的基本知識。

專案中的依賴項

**依賴項**是指可能由其他人編寫且理想情況下為您解決單個問題的第三方軟體。一個 Web 專案可以有任意數量的依賴項,從零到多個,並且您的依賴項可能包含您沒有明確安裝的子依賴項——您的依賴項可能有自己的依賴項。

專案可能需要的一個有用依賴項的簡單示例是一些程式碼,用於計算相對日期作為人類可讀的文字。您當然可以自己編寫此程式碼,但很有可能其他人已經解決了此問題——為什麼要浪費時間重新發明輪子呢?此外,可靠的第三方依賴項可能已經在許多不同的情況下進行了測試,使其比您自己的解決方案更健壯且更相容跨瀏覽器。

專案依賴項可以是整個 JavaScript 庫或框架(例如 React 或 Vue),也可以是非常小的實用程式(如我們的人類可讀日期庫),或者可以是命令列工具(如 Prettier 或 ESLint),我們在之前的文章中討論過這些工具。

如果沒有現代構建工具,此類依賴項可能會使用簡單的 <script> 元素包含在您的專案中,但這可能無法立即使用,並且您可能需要一些現代工具來捆綁您的程式碼和依賴項在 Web 上釋出時。捆綁是一個術語,通常用於指代 Web 伺服器上的單個檔案,其中包含軟體的所有 JavaScript 程式碼——通常儘可能地壓縮以幫助減少下載軟體並顯示在訪問者瀏覽器中所需的時間。

此外,如果您發現一個更好的工具想要使用而不是當前的工具,或者您的依賴項釋出了一個新版本想要更新怎麼辦?對於幾個依賴項來說,這並不是太痛苦,但在依賴項較多的較大專案中,這種事情可能變得非常難以跟蹤。使用 **包管理器**(例如 npm)更有意義,因為它可以保證程式碼被幹淨地新增和刪除,以及其他許多優點。

什麼是包管理器?

我們已經遇到過 npm,但從 npm 本身退一步來看,包管理器是一個管理專案依賴項的系統。

包管理器將提供一種方法來安裝新的依賴項(也稱為“包”),管理包在檔案系統中的儲存位置,併為您提供釋出自己的包的功能。

理論上,您可能不需要包管理器,您可以手動下載和儲存專案依賴項,但包管理器將無縫處理安裝和解除安裝包。如果您不使用它,則必須手動處理

  • 查詢所有正確的包 JavaScript 檔案。
  • 檢查它們以確保它們沒有任何已知的漏洞。
  • 下載它們並將它們放在專案中的正確位置。
  • 編寫程式碼以在應用程式中包含包(這通常使用 JavaScript 模組 完成,這是另一個值得閱讀和理解的主題)。
  • 對所有包的子依賴項執行相同的操作,這些子依賴項可能數十個或數百個。
  • 如果要刪除包,請再次刪除所有檔案。

此外,包管理器處理重複的依賴項(這在前端開發中變得重要且常見)。

在 npm(以及基於 JavaScript 和 Node 的包管理器)的情況下,您有兩個選項可以安裝依賴項的位置。正如我們在上一篇文章中所提到的,依賴項可以全域性安裝或本地安裝到您的專案中。雖然全域性安裝往往有更多優點,但本地安裝的優點更重要——例如程式碼可移植性和版本鎖定。

例如,如果您的專案依賴於具有特定配置的 Webpack,您需要確保如果您將該專案安裝到另一臺機器上或稍後返回到該專案,該配置仍然有效。如果安裝了不同版本的 Webpack,它可能不相容。為了減輕這種情況,依賴項會本地安裝到專案中。

要檢視本地依賴項的真正優勢,您只需嘗試下載並執行現有專案即可——如果它可以工作並且所有依賴項都可以立即使用,那麼您應該感謝本地依賴項使程式碼可移植。

**注意:**npm 不是唯一可用的包管理器。一個成功且流行的替代包管理器是 Yarn。Yarn 使用不同的演算法解析依賴項,這意味著可以獲得更快的使用者體驗。還有一些其他新興的客戶端,例如 pnpm

包登錄檔

為了使包管理器能夠工作,它需要知道從哪裡安裝包,這以包登錄檔的形式出現。登錄檔是一箇中心位置,包在其中釋出,因此可以從中安裝。npm 既是包管理器,也是 JavaScript 包最常用的包登錄檔名稱。npm 登錄檔位於 npmjs.com

npm 不是唯一的選擇。您可以管理自己的包登錄檔——像 Microsoft Azure 這樣的產品允許您建立到 npm 登錄檔的代理(以便您可以覆蓋或鎖定某些包),GitHub 也提供包登錄檔服務,並且隨著時間的推移,可能會出現更多選項。

重要的是要確保您選擇了最適合您的登錄檔。許多專案將使用 npm,並且在模組的其餘部分中,我們的示例將堅持使用它。

使用包生態系統

讓我們透過一個示例來開始使用包管理器和登錄檔安裝命令列實用程式。

我們將使用 Vite 建立一個空白網站。在下一篇文章中,我們將擴充套件工具鏈以包含更多工具,並向您展示如何部署網站。

Vite 提供了一些 初始化模板,其中包含所有必要的依賴項和配置,以便您在實際專案中快速入門。為了演示,我們將從頭開始配置一個,並參考 React 模板

將應用程式設定為 npm 包

首先,建立一個新目錄來儲存我們的實驗應用程式,放在一個您以後可以找到的合理位置。我們將它命名為 npm-experiment,但您可以隨意命名。

bash
mkdir npm-experiment
cd npm-experiment

接下來,讓我們將我們的應用程式初始化為 npm 包,這將建立一個配置檔案——package.json——允許我們儲存配置詳細資訊,以防我們以後想要重新建立此環境,或者甚至將包釋出到 npm 登錄檔(儘管這與我們的文章無關,因為我們正在開發應用程式,而不是可重用庫)。

鍵入以下命令,確保您在 npm-experiment 目錄中

bash
npm init

現在將向您提出一些問題;然後,npm 將根據答案建立一個預設的 package.json 檔案。請注意,這些與我們的目的無關,因為它們僅在您將包釋出到登錄檔並且其他人想要安裝和匯入它時才使用。

  • name:用於識別應用程式的名稱。只需按 Return 接受預設值 npm-experiment
  • version:應用程式的起始版本號。同樣,只需按 Return 接受預設值 1.0.0
  • description:應用程式目的的簡要說明。我們在這裡將省略它,但您也可以輸入任何您喜歡的內容。按 Return
  • entry point:當其他人匯入您的包時,將執行此 JavaScript 檔案。這對我們沒有用,因此只需按 Return
  • test commandgit repositorykeywords:按 Return 將這些都留空。
  • author:專案的作者。鍵入您自己的姓名,然後按 Return
  • license:釋出包所依據的許可證。按 Return 暫時接受預設值。

再次按 Return 接受這些設定。

進入您的 npm-experiment 目錄,您現在應該會發現您有一個 package.json 檔案。開啟它,它應該如下所示

json
{
  "name": "npm-experiment",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Your name",
  "license": "ISC"
}

我們將在 package.json 中新增兩行

  • "type": "module",這會導致 Node 將所有 .js 檔案解釋為 ES 模組 而不是舊的 CommonJS 模組。養成這個習慣通常是一個好習慣。
  • "private": true,這可以防止您意外地將包釋出到 npm 登錄檔。

將這些行新增到 "name" 正下方

json
"name": "npm-experiment",
"type": "module",
"private": true,

所以這是定義您的包的配置檔案。這對現在來說已經足夠了,所以讓我們繼續。

安裝 Vite

我們首先安裝 Vite,這是我們網站的構建工具。它負責將我們的 HTML、CSS 和 JavaScript 檔案捆綁成瀏覽器最佳化的捆綁包。

bash
npm install --save-dev vite

完成後,再看看您的 package.json 檔案。您會看到 npm 添加了一個新欄位 devDependencies

json
"devDependencies": {
  "vite": "^5.2.13"
}

這是 npm 魔法的一部分——如果將來您將程式碼庫移動到另一個位置、另一臺機器上,您可以透過執行命令 npm install 來重新建立相同的設定,npm 將檢視依賴項併為您安裝它們。

一個缺點是 Vite 僅在我們的 npm-experiment 應用程式內部可用;您無法在不同的目錄中執行它。但優點大於缺點。

請注意,我們選擇將 vite 安裝為開發依賴項。對於應用程式來說,這種差異很少重要,但對於庫來說,這意味著當其他人安裝您的包時,他們不會隱式地安裝 Vite。通常,對於應用程式,在原始碼中匯入的任何包都是真正的依賴項,而用於開發的任何包(通常作為命令列工具)都是開發依賴項。透過刪除 --save-dev 標誌來安裝真正的依賴項。

您還會發現建立了許多新檔案

  • node_modules:執行 Vite 所需的依賴項檔案。npm 已為您下載了所有這些檔案。

  • package-lock.json:這是一個鎖定檔案,儲存了重現node_modules目錄所需的確切資訊。這確保只要鎖定檔案不變,node_modules目錄在不同的機器上就會相同。

您無需擔心這些檔案,因為它們由 npm 管理。如果您使用 Git,則應將node_modules新增到您的.gitignore檔案中,但通常應保留package-lock.json,因為如前所述,它用於在不同的機器之間同步node_modules的狀態。

設定我們的示例應用

無論如何,讓我們繼續設定。

在 Vite 中,index.html 檔案處於中心位置。它定義了應用程式的起點,Vite 將使用它來查詢構建應用程式所需的其它檔案。在您的npm-experiment目錄中建立一個index.html檔案,並賦予其以下內容

html
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="UTF-8" />
    <title>My test page</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>

請注意,<script> 元素建立了對名為src/main.jsx的檔案的依賴關係,該檔案聲明瞭應用程式 JavaScript 邏輯的入口點。建立src資料夾並在該資料夾中建立main.jsx,但現在將其留空。

注意:type="module" 屬性非常重要。它告訴瀏覽器將指令碼視為 ES 模組,這使我們能夠在 JavaScript 程式碼中使用importexport語法。副檔名為.jsx,因為在下一篇文章中,我們將向其中新增 React JSX 語法。瀏覽器不理解 JSX,但 Vite 會將其轉換為常規 JavaScript,就像瀏覽器理解一樣!

使用 Vite 盡情玩耍

現在我們將執行我們新安裝的 Vite 工具。在您的終端中,執行以下命令

bash
npx vite

您應該會看到類似以下內容列印在您的終端中

VITE v5.2.13  ready in 326 ms

➜  Local:   https://:5173/
➜  Network: use --host to expose
➜  press h + enter to show help

現在我們已準備好從完整的 JavaScript 包生態系統中受益。首先,現在有一個本地 Web 伺服器在https://:5173上執行。您現在還看不到任何內容,但很酷的是,當您對應用程式進行更改時,Vite 將重新構建它並自動重新整理伺服器,以便您可以立即看到更新的效果。

您可以隨時使用Ctrl + C停止開發伺服器,並使用相同的命令重新啟動它。如果您決定保持其執行,則可以開啟一個新的終端視窗來執行其他命令。

現在新增一些頁面內容。作為演示,讓我們向頁面新增一個圖表。我們將使用plotly.js包,這是一個數據視覺化庫。透過執行以下命令安裝它

bash
npm install plotly.js-dist-min

請注意,我們是在沒有--save-dev標誌的情況下安裝的。如前所述,這是因為我們實際上將在原始碼中使用此包,而不僅僅是作為命令列工具。此命令會向您的package.json檔案新增一個新的"dependencies"物件,其中包含plotly.js-dist-min

注意:在這裡,我們為您選擇了包以完成我們的任務。當您編寫自己的程式碼時,在查詢和安裝依賴項時,請考慮以下問題

  • 我是否需要依賴項?是否可以使用內建功能來實現,或者它是否足夠簡單,可以自己編寫?
  • 我到底需要做什麼?您描述得越詳細,就越有可能找到一個完全滿足您需求的包。您可以在 npm 或 Google 上搜索關鍵字。此外,優先選擇小型包而不是大型包,因為後者在安裝、執行等方面可能會導致效能問題。
  • 該依賴項是否值得信賴且維護良好?檢查上次釋出版本的時間、作者是誰以及該包每週的下載量。確定包的可信度是一項需要經驗的技能,因為您必須考慮諸如包需要更新的可能性或可能需要它的人數等因素。

src/main.jsx檔案中,新增以下程式碼並儲存

js
import Plotly from "plotly.js-dist-min";

const root = document.getElementById("root");
Plotly.newPlot(
  root,
  [
    {
      x: [1, 2, 3, 4, 5],
      y: [1, 2, 4, 8, 16],
    },
  ],
  {
    margin: { t: 0 },
  },
);

返回https://:5173,您將在頁面上看到一個圖表。更改不同的數字,並在每次儲存檔案時檢視圖表更新。

構建我們的生產程式碼

但是,此程式碼尚未準備好用於生產。大多數構建工具系統(包括 Vite)都具有“開發模式”和“生產模式”。重要的區別在於,您在開發中使用的許多有用的功能在最終站點中不需要,因此將在生產中被剝離,例如“熱模組替換”、“即時重新載入”和“未壓縮且帶註釋的原始碼”。雖然遠非詳盡無遺,但這些是在開發階段非常有幫助但在生產中不太有用的常見 Web 開發功能。在生產中,它們只會使您的網站膨脹。

現在使用Ctrl + C停止執行的 Vite 開發伺服器。

現在我們可以為一個假設的部署準備我們最基本的示例站點。Vite 提供了一個額外的build命令來生成適合釋出的檔案。

執行以下命令

bash
npx vite build

您應該會看到如下輸出

vite v5.2.13 building for production...
✓ 6 modules transformed.
dist/index.html                    0.32 kB │ gzip:     0.24 kB
dist/assets/index-BlYAJQFz.js  3,723.18 kB │ gzip: 1,167.74 kB

(!) Some chunks are larger than 500 kB after minification. Consider:
- Using dynamic import() to code-split the application
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/configuration-options/#output-manualchunks
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.
✓ built in 4.36s

Vite 將建立一個名為dist的目錄。如果您檢視它,它包含一個index.html,它看起來與根目錄中的非常相似,只是script的源現在被替換為指向assets資料夾的路徑。assets資料夾包含轉換後的 JavaScript 輸出,該輸出現在已縮小並針對生產進行了最佳化。

注意:您可能擔心有關某個塊太大警告。這是預期的,因為我們正在載入一個在幕後執行許多操作的庫(想象一下自己編寫所有程式碼來繪製相同的圖表)。現在,我們無需擔心它。

包管理器客戶端簡要指南

本教程使用 npm 安裝了 Vite 包,但如前所述,也有一些替代方案。至少了解它們的存在並對這些工具的常用命令有一些模糊的概念是值得的。您已經看到了一些實際應用,但讓我們看看其他一些。

隨著時間的推移,此列表會不斷增長,但在撰寫本文時,以下主要包管理器可用

從命令列角度來看,npm 和 pnpm 非常相似——事實上,pnpm 的目標是完全相容 npm 提供的引數選項。它的不同之處在於它使用不同的方法在您的計算機上下載和儲存包,旨在減少所需的總磁碟空間。

在下面的示例中,如果顯示 npm,則可以替換為 pnpm,並且命令將起作用。

通常認為 Yarn 在安裝過程中比 npm 快(儘管您的里程可能會有所不同)。這對開發人員來說很重要,因為可能會有大量時間浪費在等待依賴項安裝(並複製到計算機上)。

但是,值得注意的是,npm 包管理器**不是**安裝 npm 登錄檔中的包所必需的。pnpm 和 Yarn 可以使用與 npm 相同的package.json格式,並且可以從 npm 和其他包登錄檔安裝任何包。

讓我們回顧一下您希望使用包管理器執行的常見操作。

注意:我們將演示 npm 和 Yarn 命令。它們並非旨在在同一個專案中執行。您應該使用 npm 或 Yarn 設定您的專案,並始終使用該包管理器的命令。

初始化新專案

bash
npm init
yarn init

如上所示,這將提示您並引導您完成一系列問題以描述您的專案(名稱、許可證、描述等),然後為您生成一個package.json,其中包含有關您的專案及其依賴項的元資訊。

安裝依賴項

bash
npm install vite
yarn add vite

我們還在上面看到了install的實際應用。這將直接將vite包新增到工作目錄中的名為node_modules的子目錄中,以及vite自己的依賴項。

預設情況下,此命令將安裝最新版本的vite,但您也可以控制它。您可以請求vite@4,它為您提供最新的 4.x 版本(即 4.5.3)。或者,您可以嘗試vite@^4.0.0,這意味著 4.0.0 及其之後的最新版本(與上述含義相同)。

更新依賴項

bash
npm update
yarn upgrade

這將檢視當前安裝的依賴項並在包中指定的範圍內更新它們(如果有可用更新)。

範圍在您package.json中依賴項的版本中指定,例如"vite": "^5.2.13"——在這種情況下,插入符號字元^表示 5.2.13 及其之後的全部次要和修補程式版本,直到但不包括 6.0.0。

這是使用稱為semver的系統確定的,從文件中看起來可能有點複雜,但可以透過僅考慮摘要資訊以及版本由MAJOR.MINOR.PATCH表示來簡化,例如 2.0.1 表示主版本為 2,修補程式版本為 1。嘗試 semver 值的一個好方法是使用semver 計算器

務必記住,npm update不會將依賴項升級到package.json中定義的範圍之外——要執行此操作,您需要專門安裝該版本。

更多命令

您可以在網上找到有關npmyarn各個命令的更多資訊。同樣,pnpm命令將與 npm 保持一致,並新增少量內容。

建立自己的命令

包管理器還支援建立您自己的命令並從命令列執行它們。例如,之前我們使用npx呼叫了vite命令來啟動 Vite 開發伺服器。我們可以建立以下命令

bash
npm run dev
# or yarn run dev

這將執行一個自定義指令碼以在“開發模式”下啟動我們的專案。事實上,我們經常在所有專案中包含它,因為本地開發設定的執行方式往往與在生產中的執行方式略有不同。

如果您嘗試在您之前的測試專案中執行它,它(可能)會聲稱“dev 指令碼丟失”。這是因為 npm、Yarn(以及類似工具)在您的package.json檔案的scripts屬性中查詢名為dev的屬性。因此,讓我們在我們的package.json中建立一個自定義快捷命令——“dev”。如果您按照之前的教程操作,則您的npm-experiment目錄中應該有一個package.json檔案。開啟它,它的scripts成員應該如下所示

json
"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
},

將其更新為如下所示,然後儲存檔案

json
"scripts": {
  "dev": "vite"
},

我們添加了一個自定義dev命令作為 npm 指令碼。

現在嘗試在您的終端中執行以下命令,確保您位於npm-experiment目錄中

bash
npm run dev

這應該會啟動 Vite 並啟動與之前相同的本地開發伺服器。

請注意,我們在此定義的指令碼不再需要 npx 字首。這是因為 npm(和 yarn)命令很智慧,它們會在嘗試透過常規方法(你的電腦通常儲存並允許找到軟體的方式)查詢它們之前,搜尋本地安裝到專案中的命令列工具。你可以詳細瞭解 run 命令的技術細節,儘管在大多數情況下,你自己的指令碼也能正常執行。

這個特定的命令可能看起來沒有必要——npm run devnpx vite 多輸入幾個字元,但它是一種抽象的形式。它允許我們將來在 dev 命令中新增更多工作,例如設定環境變數、生成臨時檔案等,而不會使命令變得複雜。

你可以向 scripts 屬性中新增各種有助於你完成工作的內容。例如,以下是 Vite 在模板中推薦的內容

json
"scripts": {
  "dev": "vite",
  "build": "vite build",
  "preview": "vite preview"
},

總結

這標誌著我們對包管理器的介紹結束。接下來,我們將構建一個示例工具鏈,將我們迄今為止學到的所有知識付諸實踐。

另請參閱