一文帶你了解npm的原理
npm 是 JavaScript世界的套件管理工具,並且是 Node.js平台的預設套件管理工具。透過 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:
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約定的指定所需依賴套件的版本號碼或範圍。
常用的規則如下圖:
semver語意化版本
1、任兩條規則,用空格連結起來,表示「與」邏輯,即為兩個規則的交集。
如 >=2.3.1 <=2.8.0 可解讀為: >=2.3.1 且 <=2.8.0
- # 可配對 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的具体内容为:
[ '/usr/local/Cellar/node/7.7.1_1/bin/node', '/Users/mac/Vue-projects/hao-cli/node_modules/.bin/vue-cli-service', 'serve', '--mode=dev', '--mobile', '-config', 'build/example.js' ]
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 'npm run build:css' assets/styles/", // 只要 HTML 文件有变动,就重新执行构建 "watch:html": "watch 'npm run build:html' 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中文網其他相關文章!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

npm react安裝錯誤的解決方法:1、開啟專案中的「package.json」文件,找到dependencies物件;2、將其中的「react.json」移到「devDependencies」;3、在終端機中執行「npm audit --production”即可修復警告。

nvm刪除node的方法:1、下載「nvm-setup.zip」並將其安裝在C碟;2、設定環境變量,並透過「nvm -v」指令查看版本號;3、使用「nvm install」指令安裝node;4、透過「nvm uninstall」指令刪除已安裝的node即可。

怎麼處理文件上傳?以下這篇文章為大家介紹一下node專案中如何使用express來處理文件的上傳,希望對大家有幫助!

這篇文章跟大家分享Node的進程管理工具“pm2”,聊聊為什麼需要pm2、安裝和使用pm2的方法,希望對大家有幫助!

PiNetwork節點詳解及安裝指南本文將詳細介紹PiNetwork生態系統中的關鍵角色——Pi節點,並提供安裝和配置的完整步驟。 Pi節點在PiNetwork區塊鏈測試網推出後,成為眾多先鋒積極參與測試的重要環節,為即將到來的主網發布做準備。如果您還不了解PiNetwork,請參考Pi幣是什麼?上市價格多少? Pi用途、挖礦及安全性分析。什麼是PiNetwork? PiNetwork項目始於2019年,擁有其專屬加密貨幣Pi幣。該項目旨在創建一個人人可參與

如何用pkg打包nodejs可執行檔?以下這篇文章跟大家介紹一下使用pkg將Node專案打包為執行檔的方法,希望對大家有幫助!

npm node gyp失敗是因為“node-gyp.js”跟“Node.js”版本不匹配,其解決辦法:1、透過“npm cache clean -f”清除node快取;2、透過“npm install -g n”安裝n模組;3、透過「n v12.21.0」指令安裝「node v12.21.0」版本即可。

身份驗證是任何網路應用程式中最重要的部分之一。本教程討論基於令牌的身份驗證系統以及它們與傳統登入系統的差異。在本教程結束時,您將看到一個用Angular和Node.js編寫的完整工作演示。傳統身份驗證系統在繼續基於令牌的身份驗證系統之前,讓我們先來看看傳統的身份驗證系統。使用者在登入表單中提供使用者名稱和密碼,然後點擊登入。發出請求後,透過查詢資料庫在後端驗證使用者。如果請求有效,則使用從資料庫中獲取的使用者資訊建立會話,然後在回應頭中傳回會話訊息,以便將會話ID儲存在瀏覽器中。提供用於存取應用程式中受
