博客 / 詳情

返回

結合實踐解讀 package.json

前言

平時大家在公司接手一個已有項目的時候,首先會看的是什麼呢?我的習慣是先看 README.mdpackage.json

通過 README 瞭解項目是做什麼和注意點,通過package.json瞭解項目涉及的技術棧和 npm 庫等等。

今天就來深入瞭解下package.json這個文件,不僅是解釋詳細字段含義與運用(忽略部分第三方字段本文就不介紹了),更重要的是想借此擴展總結下涉及工作中與社區知名庫的一些實踐,對我們自己做開源項目也有一定幫助。

本文同步於我的 Github 個人博客

常見配置字段

name

項目的名稱,該字段決定了你發佈的包在 npm 的名字,也就是平時安裝庫的包名了 npm i 包名

該字段也是有命名規範的,如下:

  • 名稱的長度必須小於或等於 214 個字符,不能以._開頭。不要使用空格<>[]{}|\^% 等。
  • 不能使用大寫字母命名
  • 如果要發佈到 npm 上,名稱不能和社區已有的重複,可以使用npm view命令查詢,或直接上npm查。比如隨機想一個包名,jacky-summer-utils
npm view jacky-summer-utils

# 報 404,證明該名稱可用
npm ERR! code E404

除了常規命名,我們還會見到社區有@開頭的命名,格式如:@[scope]/[name]

例子:@ant-design/icons@babel/preset-env,這代表一個組織下的庫。

如果你也想使用這樣的結構,比如用自己名字@開頭的話,需要在自己 npm 上建立組織(Add Organization),不這麼做的話包名帶@則發佈時會不通過。

比如我創建了個組織 @summer-toolkit,包名是config,則我的這個包和name值就命名為 @summer-toolkit/config

"name": "@summer-toolkit/config"

version

項目版本號,當發佈 npm 包時nameversion這兩個字段是必須的,兩個共同構成唯一的項目標識,通過更改 version 來對你的 npm 包進行發佈更新。

"version": "1.1.0"

通常推薦使用 semver 版本控制策略,開源項目也通常遵循這個語義化規範

版本格式:主版本號.次版本號.修訂號,版本號遞增規則如下:
  1. 主版本號 Major,當你做了不兼容的 API 修改,通常在涉及重大功能更新,產生了破壞性變更時會更新此版本號
  2. 次版本號 Minor,引入了新功能,但未產生破壞性變更,依然可以向下兼容時會更新此版本號,可理解為 Feature 版本
  3. 修訂號 Patch,修復了一些 bug,也未產生破壞性變更時會更新此版本號,可理解為 Bug Fix

當要發佈大版本或者核心的功能時,無法確定該版本功能穩定,可能無法滿足預期的兼容性需求,這個時候就需要通過發佈先行版本。先行版本通過會加在版本號的後面,通過-號連接以.分隔的標識符和版本編譯信息:

  • 內部版本(alpha):通常該版本軟件的 Bug 較多,需要持續修改
  • 公測版本(beta):相對於 alpha 版已有很大改進,會繼續加新特性,修復了較嚴重的錯誤,但依然存在一些缺陷
  • 候選版本(rc,即 release candiate):正式版本的候選版本,該版本一般可以説錯誤較少了,基本是修復而不是再加新特性了
react:16.3.0-alpha.0
vue:3.2.34-beta.1、3.0.0-rc.13

比如想查看 vue 的歷史 Tag 版本,可看到 vue 是比較嚴格遵循 semver 版本規範的:

image.png

# 查看 vue 歷史版本
npm view vue versions
# 查看 vue 最新版本
npm view vue version

一些問題解答:

在庫初始開發階段,該如何進行版本控制?

最簡單的做法是以 0.1.0 作為你的初始化開發版本,並在後續的每次發行時遞增次版本號。當最終完成用於正式線上環境了,這時就可以改為 1.0.0,之後就都按照 Semver 規範走了

公司一些較小的公共庫版本,怎麼維護?

這個可視乎庫規模和使用人數多少決定,像一般公司大部分私庫測試環境都可直接發佈 beta 版本,等 UAT/線上就是直接走的正式版本

description

項目的描述,信息會直接展示在 npm 官網,通過它能讓別人能快速你的項目。

dayjs庫的:

"description": "2KB immutable date time library alternative to Moment.js with the same modern API "

image.png

Webpack 的描述就相對長一些了:

"description": "Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.",

keywords

項目關鍵詞。關鍵詞填得準,可方便在 npm 上更好地檢索

如 Ant Design 的 keywords

"keywords": [
    "ant",
    "component",
    "components",
    "design",
    "framework",
    "frontend",
    "react",
    "react-component",
    "ui"
],

Redux 的:

"keywords": [
    "redux",
    "reducer",
    "state",
    "predictable",
    "functional",
    "immutable",
    "hot",
    "live",
    "replay",
    "flux",
    "elm"
],

repository

項目的倉庫地址以及版本控制信息,可通過該字段找到代碼託管地址

// Ant Design
"repository": {
    "type": "git",
    "url": "https://github.com/ant-design/ant-design"
}

license

項目的開源許可證,説明你的庫使用哪個許可證,用户保護你自己和貢獻者。

沒有 License 的內容是默認會被版權保護,如果你允許社區內開發者可基於你的項目二次改造等,需要選擇合適的許可證才能賦予任何人放心使用(改造、分享等)。

目前 Github 我們熟知的大部分項目都是 MIT 許可證

 "license": "MIT"
MIT 基本就是沒有任何限制,表示任何人都可以售賣我的軟件,甚至可以用作者的名字促銷。
項目的版權擁有人可以使用開源許可證來限制源碼的使用、複製、修改和再發布等行為,

通常開源項目都會在根目錄下新建 LICENSE 文件,並將許可證的文本複製到這裏。如看下 Vue的

對於公司不開源的項目,這個配置項一般可忽略。

瞭解詳細可閲讀:

  • 七種開源許可證
  • 如何為自己的 Github 項目選擇開源許可證?

private

設置為私有防止意外發布。如果你不希望把項目發佈到 npm 倉庫上,可以將 private 設為 true。

"private": true

當設置為 true 時,執行npm publish會報錯,npm 會拒絕發佈這個項目。

像公司的非開源項目就可以設置為 true,防止被無意間發佈出去

publishConfig

npm 包發佈使用的配置,通常publishConfig會配合private使用;如果只想讓模塊發佈到特定 npm 倉庫,就可以這樣來配置

"publishConfig": {
    "registry": "https://registry.npmjs.org", // 私源地址配置
    "tag": "beta", // 如果沒有指定tag,默認是 latest
    "access": "public"
}
  • registry:npm 私源地址
  • tag:指定當前版本對應的 tag
  • access:包的訪問級別。如果是 scoped 包(如 @babel/xxx,@ant-design/xxx),一定需要設置為 public(除非加入付費計劃)

bugs

bug 反饋地址,通過該鏈接向你的倉庫反饋 bug,github 上的一般都是 github issue 頁的鏈接

"bugs": "https://github.com/webpack/webpack/issues",

homepage

項目主頁地址,如:倉庫 Github 鏈接、官網地址、文檔地址等

// Ant Design:
"homepage": "https://ant.design"

// Redux:
"homepage": "http://redux.js.org"

homepage字段會展示在 npm 的這個地方:

image.png

homepage 還可設置應用的根路徑,詳細可見【小技巧】package.json 中 homepage 屬性的作用

author

項目的作者(信息)

  • 字符串形式
"author": "JackySummer"
  • 對象形式:包含必選的 name 屬性和可選的 url、email 屬性
"author": {
    "name": "JackySummer",
    "email": "xxxxx@qq.com",
    "url": "https://jackylin.vercel.app"
}

也可以用下面的字符串簡寫,npm 會幫我們解析:

"author": "JackySummer <xxxxx@qq.com> (https://jackylin.vercel.app)"

contributors

貢獻者信息。對象格式數組,對象的內容和author一樣

"contributors": [{
    "name": "JackySummer",
    "email": "xxxxx@qq.com",
    "url": "https://jackylin.vercel.app"
}]

通常對應的,Github 開源項目通常會有 /.github/CONTRIBUTING.md貢獻指南這個文件,裏面也可能有列出一些貢獻者簡要信息等,如 Vue 的 CONTRIBUTING.md

scripts

項目內置的腳本命令,這一字段下的東西是我比較感興趣的,通常可以看到項目的啓動方式、prettier/eslint 運行腳本,是否用了單元測試等等...

找到項目的/node_modules/.bin目錄,項目 npm run xx的底層調用命令在這裏都能找到

npm 腳本的原理:每當執行 npm run,就會自動新建一個 Shell,在這個 Shell 裏面執行指定的腳本命令。因此,只要是 Shell(一般是 Bash)可以運行的命令,就可以寫在 npm 腳本里面

比如我們安裝了 eslint,scripts裏面配置:

"eslint": "eslint --fix --ext .ts,.tsx ."

而不必寫成路徑的方式

"eslint": "./node_modules/.bin/eslint --fix --ext .ts,.tsx .",

npm scripts 鈎子

npm 腳本有 pre 和 post 兩個鈎子,如 運行 npm run install 的時候,分 3 個階段:

  1. 檢查 scripts 對象中是否存在 preinstall 命令,如果有,先執行該命令;
  2. 檢查是否有 install 命令,有的話運行 install 命令,沒有的話報錯;
  3. 檢查是否存在 postinstall 命令,如果有,執行 postinstall 命令

npm 默認提供下面這些鈎子。

prepublish,postpublish
preinstall,postinstall
preuninstall,postuninstall
preversion,postversion
pretest,posttest
prestop,poststop
prestart,poststart
prerestart,postrestart

另外,我們自定義的腳本命令也可以加上 pre 和 post 鈎子。

下面舉例我工作中使用到 npm 鈎子的場景:

  1. 所有項目都由 npm 遷移 pnpm,但有的人沒注意或忘了,拿到項目還是使用 npm 安裝,也產生了 package-lock.json 文件

解決方案:在 npm install 之前限制住只能使用 pnpm 安裝。.gitignore 添加 npm 和 yarn 的 lock 文件

"scripts": {
    "preinstall": "npx only-allow pnpm"
}

.gitignore

yarn.lock
package-lock.json
  1. 第三方庫有 Bug,如何臨時緊急修復

這個以前遇過,年代久遠了舉不出例子來了,找了別人的文章可以瞭解下:

patch-package 和 postinstall :【 非常實用】如何優雅地解決 npm 依賴 bug

瞭解更多 npm scripts 可參考學習:npm scripts 使用指南


建議 script 有約定俗成的規範腳本命令,提高可讀性與降低維護成本

來看下一些開源項目的 scripts 配置:

Vue:

 "scripts": {
    "dev": "rollup -w -c scripts/config.js --environment TARGET:full-dev",
    "dev:cjs": "rollup -w -c scripts/config.js --environment TARGET:runtime-cjs-dev",
    "dev:esm": "rollup -w -c scripts/config.js --environment TARGET:runtime-esm",
    "dev:ssr": "rollup -w -c scripts/config.js --environment TARGET:server-renderer",
    "dev:compiler": "rollup -w -c scripts/config.js --environment TARGET:compiler ",
    "build": "node scripts/build.js",
    "build:ssr": "npm run build -- runtime-cjs,server-renderer",
    "build:types": "rimraf temp && tsc --declaration --emitDeclarationOnly --outDir temp && api-extractor run && api-extractor run -c packages/compiler-sfc/api-extractor.json",
    "test": "npm run ts-check && npm run test:types && npm run test:unit && npm run test:e2e && npm run test:ssr && npm run test:sfc",
    "test:unit": "vitest run test/unit",
    "test:ssr": "npm run build:ssr && vitest run server-renderer",
    "test:sfc": "vitest run compiler-sfc",
    "test:e2e": "npm run build -- full-prod,server-renderer-basic && vitest run test/e2e",
    "test:transition": "karma start test/transition/karma.conf.js",
    "test:types": "npm run build:types && tsc -p ./types/tsconfig.json",
    "format": "prettier --write --parser typescript \"(src|test|packages|types)/**/*.ts\"",
    "ts-check": "tsc -p tsconfig.json --noEmit",
    "ts-check:test": "tsc -p test/tsconfig.json --noEmit",
    "bench:ssr": "npm run build:ssr && node benchmarks/ssr/renderToString.js && node benchmarks/ssr/renderToStream.js",
    "release": "node scripts/release.js",
    "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
  },

dayjs:

 "scripts": {
    "test": "TZ=Pacific/Auckland npm run test-tz && TZ=Europe/London npm run test-tz && TZ=America/Whitehorse npm run test-tz && npm run test-tz && jest",
    "test-tz": "date && jest test/timezone.test --coverage=false",
    "lint": "./node_modules/.bin/eslint src/* test/* build/*",
    "prettier": "prettier --write \"docs/**/*.md\"",
    "babel": "cross-env BABEL_ENV=build babel src --out-dir esm --copy-files && node build/esm",
    "build": "cross-env BABEL_ENV=build node build && npm run size",
    "sauce": "npx karma start karma.sauce.conf.js",
    "test:sauce": "npm run sauce -- 0 && npm run sauce -- 1 && npm run sauce -- 2  && npm run sauce -- 3",
    "size": "size-limit && gzip-size dayjs.min.js"
  },

config

用於添加命令行的環境變量,即我們腳本在運行時的參數。

"config" : { "port" : "8080" },
"scripts" : { "start" : "node server.js" }

在 server.js 腳本就可以引用 config 字段的值

http
  .createServer(...)
  .listen(process.env.npm_package_config_port) // 8080

執行 npm run start 命令時,這個腳本就可以得到值。

用户可以改變這個值

npm config set foo:port 80

這個字段沒用過,實戰中這些配置一般不會直接寫在 package.json 文件裏面

例子引用自 config 字段

engines

聲明項目需要在怎樣的 node 環境下運行,曾遇過比較老舊的項目,甚至可能要降級 node 版本才能跑起來。這時可以給項目添加字段,説明哪個版本下運行能跑起來項目,當然你現在正維護開發的項目也推薦補充下。

"engines": {
    "node": ">=14.16.0",
    "pnpm": ">=6 <7"
},

engines只是起一個説明的作用,即使版本不符合要求也絲毫不影響安裝使用。

但如果真的遇上對 node 版本要求比較嚴格的項目,就可以在 .npmrc文件設置

engine-strict = true

這時本地 node 版本不匹配的話就會報錯 Unsupported engine,要求你必須切換engines配置的對應版本才能正常安裝

workspaces

monorepo 項目的工作區配置,用於在本地的根目錄下管理多個子項目,可以自動地在 npm install 時將 workspaces 下面的包,軟鏈到根目錄的 node_modules 中,而不用手動執行 npm link 操作

workspaces 字段接收一個數組,數組裏可以是文件夾名稱或者通配符,通常子項目都會管理在 packages 目錄下。比如:

  "workspaces": [
    "packages/*"
  ]

Babel 的配置:

  "workspaces": [
    "codemods/*",
    "eslint/*",
    "packages/*",
    "test/esm",
    "test/runtime-integration/*",
    "benchmark"
  ],

files

項目發佈時包含的文件,配置格式為數組,可以指定單獨的文件或整個文件夾。

如 Ant Design:

"files": [
    "dist",
    "lib",
    "es"
]

聲明files字段後,當該 npm 包被安裝時,安裝的是files字段指定的內容,從而做到精準控制發佈內容,也控制了 npm 包大小。

如果有不想提交的文件,可以在項目根目錄中新建一個.npmignore文件進行配置,聲明不需要提交的文件;寫在這裏的文件即使 files 聲明瞭也不會被提交,這是為了防止垃圾無用文件被推到 npm 上

.vscode

sideEffects

聲明設置哪些模塊具有副作用,讓打包工具知道你的模塊是否是“純”的以此更好的 Tree Shaking。

首先要知道什麼會讓一個模塊有副作用?

例如修改一個全局變量,發送 API 請求,或導出 CSS,是否重寫了原生對象方法,總結起來就是函數可能對外部產生影響的行為

window.foo = 'global foo'

Tree Shaking 怎麼優化的

Webpack 的 Tree Shaking 機制由 optimization.usedExportssideEffects 共同承擔

  1. 通過設置 usedExports 為 true,表示模塊只導出被使用的成員,配合 terser 刪除項目所有模塊中未被引用的導出變量
module.exports = {
  optimization: {
    usedExports: true, // 作用於代碼語句層面,只導出(export)有使用的變量/方法
  },
}

當然這個 webpack 打包生產環境默認開啓的

  1. 通過 package.json 配置的 sideEffects,用於標記整個模塊的副作用。

sideEffects 設為 false,表示沒有任何模塊具有副作用,所有模塊都是"純"的,即打包的時候不管它是否有沒有副作用,只要它沒有被引用,整個模塊/包都會被完整的移除

"sideEffects": false

也可以使用字符串數組來列出哪些文件具有副作用

如 Ant Design 的sideEffects聲明如下 ,告知這些文件有副作用,引入後不能被刪除

"sideEffects": [
    "dist/*",
    "es/**/style/*",
    "lib/**/style/*",
    "*.less"
],

type

定義 package.json 文件和及其所在目錄根目錄中.js文件和沒有拓展名文件的處理方式

默認值為 commonjs

"type": "commonjs"

比如我們在項目根目錄下新建兩個文件:

// test.js
export const foo = 10

// index.js
import { foo } from './test.js'

console.log(foo)

然後在控制枱運行node index.js,這時會報錯

SyntaxError: Cannot use import statement outside a module

因為 Node 的模塊化方案採用的是 CommonJS,而代碼是 ES 語法,所以報錯;

而 Node 在 v13.2.0 已開始正式支持 ES Modules 特性,我們可在 package.json 設置:

"type": "module"

這樣子 Node 就會用 ES 規範進行解析,重新運行就不會報錯了

需要注意的是,無論package.json中的type字段設置為何值,只要文件後綴是 .mjs的文件都依然按照 ES 模塊規範來處理, .cjs的文件都按照 CommonJS 模塊規範來處理,不會受 type影響

types/typings

對外暴露相關的類型,指定 TypeScript 的類型定義的入口文件,前提是項目是用 TypeScript 寫的,用於方便 IDE 識別與智能提示。

"typings": "types/index.d.ts"

使用 typestypings都可以,作用相同

main

mainbrowsermodule三個字段都是用於 npm 包的,如果項目不是作為 npm 包發佈,這三個字段不需要寫。

main 字段指定加載的入口文件,指向一個兼容 CommonJS 格式的產出,這個文件名是項目作為 npm 包被打包時配置的,在 browser 和 node 環境中都可以使用。如使用require的方式導入該 npm 包時,返回的就是main字段指定文件的module.exports屬性。

當不設置該字段時,默認值是根目錄下的index.js 文件

"main": "./index.js"
// Vue
"main": "dist/vue.runtime.common.js"

browser

指向支持 UMD 模塊的入口文件,這個字段也會被一些公共 CDN 使用,比如 unpkgjsdelivr
也可以直接通過聲明 unpkgjsdelivr 字段來配置入口文件,下面再細説這兩個字段。

UMD:兼容 CommonJS 和 AMD 的模塊,既可以在 node 環境中被 require 引用,也可以在瀏覽器中直接用 CDN 被script標籤 引入

unpkg 和 jsDelivr 是開源 CDN 服務

main 字段裏指定的入口文件在 browser 和 node 環境中都可以使用。如果只想在 web 端使用,禁止在 server 端使用,可以通過 browser 字段指定入口。

"browser": "./browser/index.js"

module

  • module 指向支持 ESM 模塊的入口文件,browser 環境和 node 環境均可使用
"module": "./index.mjs"

如果一個項目同時定義了 mainbrowsermodule,Webpack 等構建工具打包的時候會根據環境以及不同的模塊規範來進行不同的入口文件查找。

// Vue:
"main": "dist/vue.runtime.common.js",
"module": "dist/vue.runtime.esm.js",

總結 npm 包 mainmodulebrowser

  • 導出包只在 web 端使用,並且禁止在 server 端使用,使用 browser
  • 導出包只在 server 端使用,使用 main
  • 導出 ESM 規範的包,使用 module
  • 導出包在 web 端和 server 端都允許使用,使用 modulemain

還有其他具體情況這裏就不展開了

exports

如果打包工具支持 exports 字段,則該字段優先級最高,會忽略 main/browser/module的配置。

比如同時使用 requireimport 字段定義模塊規範入口:

"exports": {
  "require": "./index.js",
  "import": "./index.mjs"
 }
}

// 上面寫法還等同於
"exports": {
  // 這裏路徑聲明在根目錄下,因為還支持配置包的子路徑
  ".": {
    "require": "./index.js",
    "import": "./index.mjs"
  }
 }
}

更多 exports 文檔可看 NodeJS 文檔説明

// Vue 的配置:
"exports": {
    ".": {
      "import": {
        "node": "./dist/vue.runtime.mjs",
        "default": "./dist/vue.runtime.esm.js"
      },
      "require": "./dist/vue.runtime.common.js",
      "types": "./types/index.d.ts"
    },
    "./compiler-sfc": {
      "import": "./compiler-sfc/index.mjs",
      "require": "./compiler-sfc/index.js"
    },
    "./dist/*": "./dist/*",
    "./types/*": "./types/*",
    "./package.json": "./package.json"
},

unpkg/jsdelivr

讓 npm 上所有的文件都開啓 cdn 服務。注意文件需要是 UMD 模塊規範格式

"unpkg": "dist/redux.js",

使用unpkg/jsdelivr字段可以讓 npm 上所有的文件都開啓 cdn 服務,比如當我們從 CDN 訪問使用 Redux時( https://unpkg.com/redux),

會重定向到 https://unpkg.com/redux@4.2.0/dist/redux.js (取最新Redux版本)獲取文件

dependencies

運行依賴,項目線上環境下需要用到的依賴。
使用 npm install xxxnpm install xxx --save 時,npm 包就會自動插入到該字段下。

"dependencies": {
  "react": "18.2.0",
  "react-dom": "18.2.0",
  "@ant-design/icons": "4.7.0",
}

在安裝之前就可以判斷 npm 包是否需要在線上運行,如不需要則不要放到該字段下。

在我經歷過的來看,建議一些重要且穩定的庫鎖死版本,防止意外升級導致生產 bug,因為升級庫的次版本,也有概率出現較嚴重 Bug。

"antd": "4.21.0",

找了篇文章可以看下:如何管理 npm 版本號:語義化版本策略 SemVer

devDependencies

開發依賴,項目開發環境需要用到而線上運行時不需要的依賴,用於輔助開發。

比如 webpackeslintjest、TS @types/xxx類型文件等等。

當打包上線時並不需要這些包,所以可以把這些依賴添加到 devDependencies 中,這些依賴依然會在本地指定 npm install 時被安裝和管理,但是不會被安裝到生產環境中。

使用 npm install xxx -D 或者 npm install xxx --save-dev 時,npm 包就會自動插入到該字段下。

peerDependencies

同伴依賴,防止包避免重複安裝,一般組件庫比較常見。

如 Ant Design 的配置:表示我們項目使用 antd npm 包還需安裝 reactreact-dom,且版本都要>=16.9.0

"peerDependencies": {
    "react": ">=16.9.0",
    "react-dom": ">=16.9.0"
},

peerDependenciesMeta

可選的同伴依賴

舉例:react-redux package.json

 "peerDependencies": {
    "@types/react": "^16.8 || ^17.0 || ^18.0",
    "@types/react-dom": "^16.8 || ^17.0 || ^18.0",
    "react": "^16.8 || ^17.0 || ^18.0",
    "react-dom": "^16.8 || ^17.0 || ^18.0",
    "react-native": ">=0.59",
    "redux": "^4"
  },
  "peerDependenciesMeta": {
    "@types/react": {
      "optional": true
    },
    "@types/react-dom": {
      "optional": true
    },
    "react-dom": {
      "optional": true
    },
    "react-native": {
      "optional": true
    },
    "redux": {
      "optional": true
    }
  },

上述指定了 5 個 npm 包在peerDependenciesMeta中,表示都為可選項,所以只安裝任意幾個可能不會報錯,當然也不需要全部安裝,因為這裏明顯看出這是區分 native 和 web 兩個環境的,使用的話就任選只在一種環境下。

bin

指定各個內部命令對應的可執行文件的位置,指定了 bin 字段的 npm 包,如果被全局安裝,就會被加載到全局環境中,可以通過別名來執行該文件。如帶有工具性質的 npm 包。

// webpack
"bin": {
    "webpack": "bin/webpack.js"
},

// eslint
"bin": {
    "eslint": "./bin/eslint.js"
},
node_modules/.bin/目錄下的命令,都可以用 npm run [命令] 的格式運行

拿 eslint 舉例,eslint 命令對應的可執行文件為 bin 子目錄下的 eslint.js。npm 會在node_modules/.bin/目錄下建立符號鏈接,由於node_modules/.bin/目錄會在運行時加入系統的 PATH 變量,所以在運行 npm 時,就可以不帶路徑,直接通過命令來調用這些腳本。

"eslint": "./node_modules/bin/eslint.js --fix --ext .ts,.tsx"

// 簡寫為
"eslint": "eslint --fix --ext .ts,.tsx"

overrides

重寫項目依賴的依賴,及其依賴樹下某個依賴的版本號,進行包的替換,支持任意深度的嵌套。。

這個拿我遇過的問題來解釋,比如ts-ebml庫,我們在項目中已經鎖死了版本,但是有次發現 lock 文件更新了,當然它還是保持原來版本不變,但是它的子依賴matroska被升級了小版本導致 bug。

由於matroska這個庫的場景在我們項目只有一處地方,為了解決這個問題,就需要把matroska版本鎖死,恢復到之前沒有 bug 的版本,所以可以用該字段

"overrides": {
  "matroska": "2.2.3"
}

此時查找 lock 文件依賴樹,會發現 lock 文件全部被安裝為我們指定的版本/matroska/2.2.3,當然你也可以針對單獨的庫進行版本重寫,如下:

"overrides": {
  "ts-ebml": {
    "matroska": "2.2.3"
  }
}
  • pnpm 需要使用字段:

    "pnpm": {
      "overrides": {
      }
    },
  • yarn 需要使用 resolution 字段

更多可瞭解: 前端依賴版本重寫指南

參考

  • 前端工程化基建探索:從內部機制和核心原理了解 npm
  • package.json 配置完全解讀
  • 關於前端大管家 package.json,你知道多少?
user avatar huishou 頭像 columsys 頭像 ailim 頭像 yilezhiming 頭像 liyl1993 頭像 lesini 頭像 niumingxin 頭像 79px 頭像 light_5cfbb652e97ce 頭像 dashnowords 頭像 warn 頭像 user_ze46ouik 頭像
20 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.