淺析 package.json

混子的日常發表於2021-10-02

每個前端專案中都有一個 package.json 檔案,你瞭解它嗎?花幾分鐘再重新審視一下這個熟悉的陌生人。

如何生成 package.json

在專案資料夾下執行npm init -y快速生成。 -y代表一路 yes。開啟檔案我們看到以下資訊。

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

逐個介紹下上述欄位:

  • name包名稱,必填項
  • version包版本,必填項
  • description包描述資訊,一句話介紹這個包的用途
  • main包入口檔案。
    require('package-json'),相當於使用了包的index.js。 該欄位在開發 npm 包時較為常見,身為切圖仔的我們接觸的不多。
  • scripts包執行指令碼,常用的npm startnpm run devnpm run build都是註冊在這裡的。
  • keywords關鍵詞與 description 類似,用於介紹包的用途
  • author 包建立者
  • license 包協議,用於規定是否開源、是否付費

web 專案的 package.json

大部分開發者是圍繞 web 開發進行工作的。我們來看看 web 專案的 package.json 常見配置欄位 dependenciesdevDependenciesprivatescripts...

dependencies & devDependencies

面試官:請講講 dependenciesdevDependencies的區別?

簡單,dependencies是生產環境的依賴,安裝包時執行npm install -S xxx;devDependencies 是開發環境的依賴, 安裝包需要執行 npm install -D xxx

生產環境和開發環境指什麼?如果不小心將 react 或 vue 這種依賴安裝到 devDependencies列表中專案還能執行嗎?

就 web 專案而言,筆者認為dependenciesdevDependencies的本質差異並不大。包安裝在哪,專案都能正常的構建、執行。差異主要在於語義表達。

dependencies往往是指打包構建後依賴包的程式碼會被打進產物中,在生產環境執行中是不可缺少的。

devDependencies是指那些開發、構建過程中那些工具,如構建使用的webpack、程式碼檢查的 eslint、程式碼轉義的 babel 等都屬於開發環境依賴。他們存在的目的是:幫助我們將開發的程式碼安全、便捷的轉換成使用者瀏覽器可執行的程式碼。

還有一點差異, npm install --production=true 不會安裝 devDependencies下的依賴的,只會安裝dependencies的依賴。一般沒人會控制這個變數。

private

若package.json中設定了 "private": true,npm 將拒絕釋出它。
web 專案大多不需要提交到 npm 倉庫,建議將 private 設為 true。

順便一提 monorepo 熱潮下,大家會將 monorepo 專案根目錄的 private 設為 true,來避免哪個小夥伴誤將整個目錄發包

scripts

scripts控制專案生命週期的指令碼。想一下天天用的 npm run dev、npm run build、npm run lint都做了哪些事情。看看scripts配置便知。

如果想了解團隊專案工程化實現,那麼也建議從 scripts 配置入手,一點點讀懂命令對應的指令碼檔案,你就是工程大佬了。

scripts需要著重介紹的一點是命令鉤子prepost。鉤子可以註冊某命令的前置命令和後置命令。
寫個例子吧:

{
  "scripts": {
    "prexxx": "echo 'start~'",
    "xxx": "echo 'xxx running'",
    "postxxx": "echo 'end!'"
  }
}

當我們執行 npm run xxx時會看到下面結果。prexxxpostxxx被自動執行。

用途:在commit之前執行 lint ,npm run dev之前自動為使用者安裝包等等~

想想還可以做哪些事情,歡迎討論。

engines

我們很難保證同事間的開發環境統一,例如不同開發者的 node 版本是不一致的,有人是8.x, 有人是10.x 有人是14.x。來個新人問一下你們 node 用什麼版本,累不累。配置下 engines

"engines": {
  "node": ">=12.10.0 <15"
}

上述版本是我亂寫,如果開發者的版本不符合要求控制檯會報錯引導使用者去改正,避免了口口相傳

非 web 專案的 package.json

之前介紹的欄位,同樣適用。有幾個屬性是包專案常用且有用的。
mainfilesbin

main

前文已經介紹過, 包的入口檔案。預設是專案根目錄下的index.js。

"main":"./lib/index.js",

如果你的包名是package-json, 當使用者程式碼require('package-json')時,相當於require了你包目錄下的 ./lib/index.js檔案。

files

files用於決定哪些檔案被髮布到 npm 倉庫去。不在files中的檔案,包的使用者是無法訪問的,main指向的檔案也必須存在於這個列表範圍內。

"files": [
    "src",
    "dist/*.js",
    "types/*.d.ts"
  ],

bin

命令列工具入口。當你的包提供了一個命令列工具時,你需要為命令列工具指定一個入口。命令名稱和本地可指定檔案的對應關係。可以參考看看vue-cli-service的原始碼

"bin": {
    "vue-cli-service": "bin/vue-cli-service.js"
  }

如果你細心的話會發現我們們專案下的node_modules/bin資料夾裡有好多可執行檔案。

對使用者來說:本地安裝包的bin下的可執行檔案會被連結到 ./node_modules/.bin/;全域性安裝包的bin將會被軟鏈到 /usr/local/bin下。

dependencies & devDependencies

當我們的專案作為一個包提供給別人使用時,開發者執行npm install我們需要注意只有dependencies會作為包的依賴安裝,devDependencies則會被忽略掉,講到這裡相信大家終於能理解什麼是開發環境、什麼是生產環境了。

開發包是需要注意不要誤將生產依賴安裝到devDependencies中去,會導致你的使用者跑不起來。

其他

建議:有什麼工程上的疑問,自己先看專案配置檔案,還不懂再諮詢同事。不然可能會被噴~

關注我,不迷路

image.png