搜尋
首頁web前端js教程一文帶你了解npm的原理

一文帶你了解npm的原理

Aug 09, 2022 am 09:23 AM
nodejs​nodenpm

npm 是 JavaScript世界的套件管理工具,並且是 Node.js平台的預設套件管理工具。透過 npm可以安裝、共享、分發程式碼,管理專案依賴關係。這篇文章帶大家了解npm的原理,希望對大家有幫助!

一文帶你了解npm的原理

npm的原理

npm據稱成為世界最大的套件管理器?原因真的只是用戶友好?

#一、npm init

是用來初始化一個簡單的package.json檔。 package.json檔案用來定義一個package的描述檔。

1、npm init的執行的預設行為

執行npm init --yes,全部使用預設的值。

2、 自訂npm init行為

npm init指令的原理是:呼叫腳本,輸出一個初始化的package.json檔案。

取得使用者輸入使用prompt()方法。

二、依賴套件安裝

npm的核心功能:依賴管理。執行npm i從package.json中dependencies和devDependencies將依賴套件安裝到目前目錄的node_modules資料夾中。

2.1、package定義

npm i 就可以安裝一個套件。通常package就是我們需要安裝的套件名稱,預設配置下npm會從預設的來源(Registry)中找出該套件名稱的對應的套件位址,並且下載安裝。也可以是一個指向有效套件名稱的http url/git url/資料夾路徑。

package的準確定義,符合下列a)到g)其中一個條件,他就是一個package:

一文帶你了解npm的原理

package的準確定義

2.2、安裝本地包/遠端git倉庫包

共享依賴包,並非要將包發佈到npm來源才能使用。

1)、場景1:本地模組引用

開發中避免不了模組之間調用,開發中,我們把頻繁調用的配置模組放在根目錄,然後如果有很多層級目錄,後來引用

const config = require(''../../../../..config)

這樣的路徑引用不利於程式碼重構。這時候我們需要考慮把這個模組分離出來讓其他模組分享。例如config.js可以封裝成一個package放到node_modules目錄下。

不需要手動拷貝或建立軟連接到node_modules目錄,npm 有自己的解決方案:

方案:

1、新增config資料夾,將config. js移入資料夾,名字修改為index.js,建立package.json定義config包

{ 
    "name": "config", 
    "main": "index.js", 
    "version": "0.1.0" 
}

2、在專案的package.json新增依賴項,然後執行npm i。

{ 
  "dependencies": { 
    "config":"file: ./config" 
  } 
}

查看 node_modules 目錄我們會發現多出來一個名為 config,指向上層 config/ 資料夾的軟連結。這是因為 npm 識別 file: 協定的url,得知這個套件需要直接從檔案系統中獲取,會自動建立軟連結到 node_modules 中,完成「安裝」過程。

2)、場景2:私有git共享package

團隊內部會有一些程式碼/公用程式庫需要在團隊內不同專案間共享,但可能由於包含了敏感內容。

我們可以簡單的將被依賴的套件託管到私有的git倉庫中,然後將git url儲存到dependencies中。 npm會直接呼叫系統的git指令從git倉庫拉取套件的內容到node_modules。

npm支援的git url格式:

<protocol>://[<user>[:<password>]@]<hostname>[:<port>][:][/]<path>[#<commit-ish> | #semver:<semver>]

git 路徑後可以使用# 指定特定的git branch/commit/tag, 也可以#semver: 指定特定的semver range.

例如:

git+ssh://git@github.com:npm/npm.git#v1.0.27 
git+ssh://git@github.com:npm/npm#semver:^5.0 
git+https://isaacs@github.com/npm/npm.git 
git://github.com/npm/npm.git#v1.0.27

3)、場景3:開源package問題修復

#此時我們可以手動進入node_modules 目錄下修改對應的套件內容,也許修改了一行程式碼就修復了問題。但是這種做法非常不明智!

方案:

fork原作者的git庫,在自己的repo修復問題,然後將dependencies中的相應依賴改為自己修復後版本的git url就可以解決問題。

三、npm install如何運作

npm i執行完畢,node_modules看到所有的依賴套件。開發人員無關注node_modules資料夾的結構細節,關注業務程式碼中引用依賴套件。

理解node_modules結構幫助我們更好地理解npm如何運作。 npm2到npm5變化和改進。

3.1 npm2

npm2在安裝依賴套件,採用的是簡單的遞迴安裝方法。每一個套件都有自己的依賴套件,每個套件的依賴都安裝在自己的node_modules中,依賴關係層層遞進,構成整個依賴樹,這個依賴樹與檔案系統中的檔案結構樹一一對應。

最方便的依賴樹的方式在根目錄下執行npm ls

優點:

  • 層級結構明顯,便於傻瓜式管理。

缺點:

  • 複雜工程,目錄結構可能太深,深層的檔案路徑過長觸發window檔案系統中檔案路徑不能超過260個字元長。

  • 部分被多個套件依賴的套件在許多地方重複安裝,造成大量的冗餘。

3.2 npm3

npm3的node_modules目錄改為更扁平狀層級結構。 npm3在安裝的時候遍歷整個依賴樹,計算最合理的資料夾安裝方式,所有被重複依賴的套件都可以去重安裝。

npm來說,同名不同版本的套件是兩個獨立的套件。

npm3的依賴樹結構不再與資料夾層級一一對應。

3.3 npm5

沿用npm3的扁平化依賴套件安裝方式。最大的變更時增加package-lock.json檔案。

package-lock.json作用:鎖定依賴安裝結構,發現node_modules目錄檔案層級結構是與json的結構一一對應。

npm5預設會在執行npm i後產生package-lock.json文件,提交到git/svn程式碼庫。

要升級,不要使用 5.0版本。

注意:在npm 5.0 中,如果已有package-lock 檔案存在,若手動在package.json 檔案新增一依賴,再執行npm install, 新增的依賴並不會被安裝到node_modules中, package-lock.json 也不會做對應的更新。

四、依賴套件版本管理

介紹依賴套件升級管理相關知識。

4.1 語意化版本semver

npm依賴管理的一個重要特性採用語意化版本(semver)規範,作為版本管理方案。

語意化版本號碼必須包含三個數字,格式:major.minor.patch。意思是:主版本號.小版本號.修改版本號。

我們需要在dependencies中使用semver約定的指定所需依賴套件的版本號碼或範圍。

常用的規則如下圖:

一文帶你了解npm的原理

semver語意化版本

1、任兩條規則,用空格連結起來,表示「與」邏輯,即為兩個規則的交集。

如 >=2.3.1 =2.3.1 且

  • #    可配對 2.3.1, 2.4.5, 2.8.0
  •     但不符合1.0.0, 2.3.0, 2.8.1, 3.0.0

2、任兩條規則,用||連接起來,表示「或」邏輯,即為兩條規則的並集。

如 ^2 >=2.3.1 || ^3 >3.2

  •     可配對 2.3.1, 2,8.1, 3.3.1
  •     但不符 1.0.0, 2.2.0, 3.1.0, 4.0.0

3、更直觀的表示版本號範圍的寫法

  • #    或 x 符合所有主版本
  •     1 或 1.x 符合 主版本號為 1 的所有版本
  •     1.2 或1.2.x 匹配版本號為1.2 開頭的所有版本

4、在MAJOR.MINOR.PATCH 後追加- 後跟點號分隔的標籤,作為預發布版本標籤通常被視為不穩定、不建議生產使用的版本。

  •     1.0.0-alpha
  •     1.0.0-beta.1
  •     1.0.0-rc.3

4.2 依賴版本升級

在安裝完一個依賴套件之後有新的版本發布了,如何使用npm進行版本升級呢?

  •     npm i或npm update,但是不同的npm版本,不同的package.json和package-lock.json文件,安裝和升級表現是不同的。

使用npm3的結論:

  •     如果本機 node_modules 已安裝,再次執行 install 不會更新套件版本, 執行 update 才會更新; 而如果本機 node_modules 為空時,執行 install/update 都會直接安裝更新套件。
  •     npm update 總是會把套件更新到符合 package.json 中指定的 semver 的最新版本號——本例中符合 ^1.8.0 的最新版本為 1.15.0
  •     一旦給定package.json, 無論後面執行npm install 還是update, package.json 中的webpack 版本一直頑固地保持一開始的^1.8.0 巋然不動

#使用npm5的結論:

  •     無論何時執行 install, npm 都會優先按照 package-lock 中指定的版本來安裝 webpack; 避免了 npm 3 表中情形 b) 的狀況;
  •     無論何時完成安裝/更新, package-lock 檔案總是會跟著 node_modules 更新 ——(因此可以視 package-lock 檔案為 node_modules 的 JSON 陳述)
  •     已安裝node_modules 後若執行npm update,package.json 中的版本號碼也會隨之更改為^1.15.0

4.3 最佳實踐

#我常用的node是8.11.x,npm是5.6.0。

  •     使用npm >= 5.1 版本,保持package-lock.json文件默认开启配置。
  •     初始化,npm i 安装依赖包,默认保存^X.Y.Z,项目提交package.json和package-lock.json。
  •     不要手动修改package-lock.json

升级依赖包:

  •     升级小版本,执行npm update升级到新的小版本。
  •     升级大版本,执行npm install @ 升级到新的大版本。
  •     手动修改package.json中的版本号,然后npm i。
  •     本地验证升级新版本后没有问题,提交新的package.json和package-lock.json文件。

降级依赖包:

  •     正确:npm i @验证没有问题后,提交package.json和package-lock.json文件。
  •     错误:修改package.json中的版本号,执行npm i不会生效。因为package-lock.json锁定了版本。

删除依赖包:

  •     A计划:npm uninstall 。提交package.json和package-lock.json。
  •     B计划:在package.json中删除对应的包,然后执行npm i,提交package.json和package-lock.json。

五、npm的sctipts

5.1 基本使用

npm scripts是npm的一个重要的特性。在package.json中scripts字段定义一个脚本。

比如:

{ 
    "scripts": { 
        "echo": "echo HELLO WORLD" 
    } 
}

我们可以通过npm run echo 命令执行这段脚本,就像shell中执行echo HELLO WOLRD,终端是可以看到输出的。

总结如下:

  •     npm run 命令执行时,会把./node_modules/.bin目录添加到执行环境的PATH变量中。全局的没有安装的包,在node_modules中安装了,通过npm run 可以调用该命令。
  •     执行npm 脚本时要传入参数,需要在命令后加 -- 表明,比如 npm run test -- --grep="pattern" 可以将--grep="pattern"参数传给test命令。
  •     npm 还提供了pre和post两种钩子的机制,可以定义某个脚本前后的执行脚本。
  •     运行时变量:npm run 的脚本执行环境内,可以通过环境变量的方式获取更多的运行相关的信息。可以通过process.env对象访问获得:
  •     npm_lifecycle_event:正在运行的脚本名称
  •     npm_package_:获取当前package.json中某一个字段的匹配值:如包名npm_package_name
  •     npm_package__:package中的嵌套字段。

5.2 node_modules/.bin目录

保存了依赖目录中所安装的可供调用的命令行包。本质是一个可执行文件到指定文件源的映射。

例如 webpack 就属于一个命令行包。如果我们在安装 webpack 时添加 --global 参数,就可以在终端直接输入 webpack 进行调用。

上一节所说,npm run 命令在执行时会把 ./node_modules/.bin 加入到 PATH 中,使我们可直接调用所有提供了命令行调用接口的依赖包。所以这里就引出了一个最佳实践:

•将项目依赖的命令行工具安装到项目依赖文件夹中,然后通过 npm scripts 调用;而非全局安装

于是 npm 从5.2 开始自带了一个新的工具 npx.

5.3 npx

npx 的使用很简单,就是执行 npx 即可,这里的 默认就是 ./node_modules 目录中安装的可执行脚本名。例如上面本地安装好的 webpack 包,我们可以直接使用 npx webpack 执行即可。

5.4 用法

1、传入参数

"scripts": { 
  "serve": "vue-cli-service serve", 
  "serve1": "vue-cli-service --serve1", 
  "serve2": "vue-cli-service -serve2", 
  "serve3": "vue-cli-service serve --mode=dev --mobile -config build/example.js" 
}

除了第一个可执行的命令,以空格分割的任何字符串都是参数,并且都能通过process.argv属性访问。

比如执行npm run serve3命令,process.argv的具体内容为:

[ &#39;/usr/local/Cellar/node/7.7.1_1/bin/node&#39;, 
  &#39;/Users/mac/Vue-projects/hao-cli/node_modules/.bin/vue-cli-service&#39;, 
  &#39;serve&#39;, 
  &#39;--mode=dev&#39;, 
  &#39;--mobile&#39;, 
  &#39;-config&#39;, 
  &#39;build/example.js&#39; 
]

2、多命令运行 在启动时可能需要同时执行多个任务,多个任务的执行顺序决定了项目的表现。

1)串行执行

串行执行,要求前一个任务执行成功之后才能执行下一个任务。使用 && 服务来连接。

npm run scipt1 && npm run script2

串行执行命令,只要一个命令执行失败,整个脚本会中止的。

2)并行执行

并行执行,就是多个命令同时平行执行,使用 & 符号来连接。

npm run script1 & npm run script2

3、env 环境变量 在执行npm run脚本时,npm会设置一些特殊的env环境变量。其中package.json中的所有字段,都会被设置为以npm_package_ 开头的环境变量。

4、指令钩子 在执行npm scripts命令(无论是自定义还是内置)时,都经历了pre和post两个钩子,在这两个钩子中可以定义某个命令执行前后的命令。比如在执行npm run serve命令时,会依次执行npm run preserve、npm run serve、npm run postserve,所以可以在这两个钩子中自定义一些动作:

"scripts": { 
  "preserve": "xxxxx", 
  "serve": "cross-env NODE_ENV=production webpack", 
  "postserve": "xxxxxx" 
}

5、常用脚本示例

// 删除目录 
"clean": "rimraf dist/*", 

// 本地搭建一个http服务 
"server": "http-server -p 9090 dist/", 

// 打开浏览器 
"open:dev": "opener http://localhost:9090", 

// 实时刷新 
"livereload": "live-reload --port 9091 dist/", 

// 构建 HTML 文件 
"build:html": "jade index.jade > dist/index.html", 

// 只要 CSS 文件有变动,就重新执行构建 
"watch:css": "watch &#39;npm run build:css&#39; assets/styles/", 

// 只要 HTML 文件有变动,就重新执行构建 
"watch:html": "watch &#39;npm run build:html&#39; assets/html", 

// 部署到 Amazon S3 
"deploy:prod": "s3-cli sync ./dist/ s3://example-com/prod-site/", 

// 构建 favicon 
"build:favicon": "node scripts/favicon.js",

六.npm配置

6.1 npm config

  •     通过npm config ls -l 可查看npm 的所有配置,包括默认配置。
  •     通过npm config set ,常见配置:
  •     proxy,https-proxy:指定npm使用的代理
  •     registry:指定npm下载安装包时的源,默认是https://registry.npmjs.org。可以指定私有的registry源。
  •     package-lock.json:指定是否默认生成package-lock.json,建议保持默认true。
  •     save :true/false指定是否在npm i之后保存包为dependencies,npm5开始默认为true。
  •     通过npm config delete 删除指定的配置项。

6.2 npmrc文件

可以通过删除npm config命令修改配置,还可以通过npmrc文件直接修改配置。

npmrc文件优先级由高到低,包括:

  •     工程内配置文件:项目根目录下的.npmrc文件
  •     用户级配置文件:用户配置里
  •     全局配置文件
  •     npm内置配置文件 我们可以在自己的团队中在根目录下创建一个.npmrc文件来共享需要在团队中共享的npm运行相关配置。

比如:我们在公司内网下需要代理才能访问默认源:https://registry.npmjs.org源;或者访问内网的registry,就可以在工作项目下新增.npmrc文件并提交代码库。

示例配置:

proxy = http://proxy.example.com/ 
https-proxy = http://proxy.example.com/ 
registry = http://registry.example.com/

这种在工程内配置文件的优先级最高,作用域在这个项目下,可以很好的隔离公司项目和学习研究的项目两种不同环境。

将这个功能与 ~/.npm-init.js 配置相结合,可以将特定配置的 .npmrc 跟 .gitignore, README 之类文件一起做到 npm init 脚手架中,进一步减少手动配置。

6.3 node版本约束

一个团队中共享了相同的代码,但是每个人开发机器不一致,使用的node版本也不一致,服务端可能与开发环境不一致。

  •     这就带来了不一致的因素----方案:声明式约束+脚本限制。
  •     声明:通过package.json的engines属性声明应用运行所需的版本要求。例如我呢项目中使用了async,await特性,得知node查阅兼容表格[1]得知最低支持版本是7.6.0.因此指定engines配置为:
{ 
  "engines": {"node": ">=7.6.0"} 
}
  •     强约束(可选):需要添加强约束,需要自己写脚本钩子,读取并解析engines字段的semver range并与运行环境做比对校验并适当提醒。

总结

  •     npm init初始化新项目
  •     统一项目配置:需要团队共享npm config配置项,固化到.npmrc文件中
  •     统一运行环境:统一package.json,统一package-lock.json文件。
  •     合理使用多样化的源安装依赖包
  •     使用npm版本:>= 5.2版本
  •     使用npm scripts和npx管理相应脚本
  •     安全漏洞检查:npm audit fix修复安全漏洞的依赖包(本质:自动更新到兼容的安全版本)

引用链接

[1] node查阅兼容表格: https://node.green/

更多node相关知识,请访问:nodejs 教程

以上是一文帶你了解npm的原理的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:zzvips。如有侵權,請聯絡admin@php.cn刪除
Python vs. JavaScript:社區,圖書館和資源Python vs. JavaScript:社區,圖書館和資源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C到JavaScript:所有工作方式從C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript引擎:比較實施JavaScript引擎:比較實施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

如何使用Next.js(前端集成)構建多租戶SaaS應用程序如何使用Next.js(前端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:22 AM

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript:探索網絡語言的多功能性JavaScript:探索網絡語言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的演變:當前的趨勢和未來前景JavaScript的演變:當前的趨勢和未來前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具