close
一. 包管理工具 1.1. 認識npm

我們已經學習了在JavaScript中可以通過模塊化的方式將代碼劃分成一個個小的結構:

在以後的開發中我們就可以通過模塊化的方式來封裝自己的代碼,並且封裝成一個工具;
這個工具我們可以讓同事通過導入的方式來使用,甚至你可以分享給世界各地的程序員來使用;

如果我們分享給世界上所有的程序員使用,有哪些方式呢?

方式一:上傳到GitHub上、其他程序員通過GitHub下載我們的代碼手動的引用;

缺點是大家必須知道你的代碼GitHub的地址,並且從GitHub上手動下載;

需要在自己的項目中手動的引用,並且管理相關的依賴;

不需要使用的時候,需要手動來刪除相關的依賴;

當遇到版本升級或者切換時,需要重複上面的操作;

顯然,上面的方式是有效的,但是這種傳統的方式非常麻煩,並且容易出錯;

方式二:使用一個專業的工具來管理我們的代碼

我們通過工具將代碼發布到特定的位置;
其他程序員直接通過工具來安裝、升級、刪除我們的工具代碼;

顯然,通過第二種方式我們可以更好的管理自己的工具包,其他人也可以更好的使用我們的工具包。

包管理工具npm:

Node Package Manager,也就是Node包管理器;
但是目前已經不僅僅是Node包管理器了,在前端項目中我們也在使用它來管理依賴的包;
比如express、koa、react、react-dom、axios、babel、webpack等等;

npm管理的包可以在哪裡查看、搜索呢?

https://www.npmjs.com/
這是我們安裝相關的npm包的官網;

npm管理的包存放在哪裡呢?

我們發布自己的包其實是發布到registry上面的;
當我們安裝一個包時其實是從registry上面下載的包;
1.2. 項目配置文件

事實上,我們每一個項目都會有一個對應的配置文件,無論是前端項目還是後端項目:

這個配置文件會記錄着你項目的名稱、版本號、項目描述等;
也會記錄着你項目所依賴的其他庫的信息和依賴庫的版本號;

這個配置文件在Node環境下面(無論是前端還是後端)就是package.json。

我們以vue cli4腳手架創建的項目為例:

{"name":"my-vue","version":"0.1.0","private":true,"scripts":{"serve":"vue-cli-serviceserve","build":"vue-cli-servicebuild","lint":"vue-cli-servicelint"},"dependencies":{"core-js":"^3.6.5","vue":"^2.6.11"},"devDependencies":{"@vue/cli-plugin-babel":"~4.5.0","@vue/cli-plugin-eslint":"~4.5.0","@vue/cli-service":"~4.5.0","babel-eslint":"^10.1.0","eslint":"^6.7.2","eslint-plugin-vue":"^6.2.2","vue-template-compiler":"^2.6.11"},"browserslist":[">1%","last2versions","notdead"]}

事實上Vue ClI4腳手架創建的項目相對進行了簡化,我們來看一下CLI2創建的項目:

{"name":"vuerouterbasic","version":"1.0.0","description":"AVue.jsproject","author":"'coderwhy'<'coderwhy@gmail.com'>","private":true,"scripts":{"dev":"webpack-dev-server--inline--progress--configbuild/webpack.dev.conf.js","start":"npmrundev","build":"nodebuild/build.js"},"dependencies":{"vue":"^2.5.2","vue-router":"^3.0.1"},"devDependencies":{"autoprefixer":"^7.1.2","babel-core":"^6.22.1","babel-helper-vue-jsx-merge-props":"^2.0.3","babel-loader":"^7.1.1","babel-plugin-syntax-jsx":"^6.18.0","babel-plugin-transform-runtime":"^6.22.0","babel-plugin-transform-vue-jsx":"^3.5.0","babel-preset-env":"^1.3.2","babel-preset-stage-2":"^6.22.0","chalk":"^2.0.1","copy-webpack-plugin":"^4.0.1","css-loader":"^0.28.0","extract-text-webpack-plugin":"^3.0.0","file-loader":"^1.1.4","friendly-errors-webpack-plugin":"^1.6.1","html-webpack-plugin":"^2.30.1","node-notifier":"^5.1.2","optimize-css-assets-webpack-plugin":"^3.2.0","ora":"^1.2.0","portfinder":"^1.0.13","postcss-import":"^11.0.0","postcss-loader":"^2.0.8","postcss-url":"^7.2.1","rimraf":"^2.6.0","semver":"^5.3.0","shelljs":"^0.7.6","uglifyjs-webpack-plugin":"^1.1.1","url-loader":"^0.5.8","vue-loader":"^13.3.0","vue-style-loader":"^3.0.1","vue-template-compiler":"^2.5.2","webpack":"^3.6.0","webpack-bundle-analyzer":"^2.9.0","webpack-dev-server":"^2.9.1","webpack-merge":"^4.1.0"},"engines":{"node":">=6.0.0","npm":">=3.0.0"},"browserslist":[">1%","last2versions","notie<=8"]}

我們也可以手動創建一個package.json文件:

npminit#創建時填寫信息npminit-y#所有信息使用默認的

npm init -y生成文件的效果:

{"name":"learn-npm","version":"1.0.0","description":"","main":"main.js","scripts":{"test":"echo\"Error:notestspecified\"&&exit1"},"author":"","license":"ISC"}

我們會發現屬性非常的多,我們這裡對一些常見屬性進行一些解析。

必須填寫的屬性:name、version

name是項目的名稱;
version是當前項目的版本號;
description是描述信息,很多時候是作為項目的基本描述;
author是作者相關信息(發布時用到);
license是開源協議(發布時用到);

private屬性:

private屬性記錄當前的項目是否是私有的;
當值為true時,npm是不能發布它的,這是防止私有項目或模塊發布出去的方式;

main屬性:

設置程序的入口。
很多人會有疑惑,webpack不是會自動找到程序的入口嗎?
這個入口和webpack打包的入口並不衝突;
它是在你發布一個模塊的時候會用到的;
比如我們使用axios模塊 const axios = require('axios');
實際上是找到對應的main屬性查找文件的;
axios的入口

scripts屬性

scripts屬性用於配置一些腳本命令,以鍵值對的形式存在;
配置後我們可以通過 npm run 命令的key來執行這個命令;
npm start和npm run start的區別是什麼?
它們是等價的;
對於常用的 start、 test、stop、restart可以省略掉run直接通過 npm start等方式運行;

dependencies屬性

dependencies屬性是指定無論開發環境還是生成環境都需要依賴的包;
通常是我們項目實際開發用到的一些庫模塊;
與之對應的是devDependencies;

devDependencies屬性

一些包在生成環境是不需要的,比如webpack、babel等;
這個時候我們會通過 npm install webpack --save-dev,將它安裝到devDependencies屬性中;

疑問:那麼在生成環境如何保證不安裝這些包呢?

生成環境不需要安裝時,我們需要通過 npm install --production 來安裝文件的依賴;

版本管理的問題

我們會發現安裝的依賴版本出現:^2.0.3或~2.0.3,這是什麼意思呢?

npm的包通常需要遵從semver版本規範:

semver:https://semver.org/lang/zh-CN/

npm semver:https://docs.npmjs.com/misc/semver

semver版本規範是X.Y.Z:

X主版本號(major):當你做了不兼容的 API 修改(可能不兼容之前的版本);
Y次版本號(minor):當你做了向下兼容的功能性新增(新功能增加,但是兼容之前的版本);
Z修訂號(patch):當你做了向下兼容的問題修正(沒有新功能,修復了之前版本的bug);

我們這裡解釋一下 ^和~的區別:

^x.y.z:表示x是保持不變的,y和z永遠安裝最新的版本;
~x.y.z:表示x和y保持不變的,z永遠安裝最新的版本;

engines屬性

engines屬性用於指定Node和NPM的版本號;
在安裝的過程中,會先檢查對應的引擎版本,如果不符合就會報錯;
事實上也可以指定所在的操作系統 "os" : [ "darwin", "linux" ],只是很少用到;

browserslist屬性

用於配置打包後的JavaScript瀏覽器的兼容情況,參考;
否則我們需要手動的添加polyfills來讓支持某些語法;
也就是說它是為webpack等打包工具服務的一個屬性(這裡不是詳細講解webpack等工具的工作原理,所以不再給出詳情);
二. npm工具解析 2.1. npm install命令

安裝npm包分兩種情況:

全局安裝(global install):npm install yarn -g;
項目(局部)安裝(local install):npm install

全局安裝

全局安裝是直接將某個包安裝到全局:

比如yarn的全局安裝:

npminstallyarn-g

但是很多人對全局安裝有一些誤會:

通常使用npm全局安裝的包都是一些工具包:yarn、webpack等;
並不是類似於 axios、express、koa等庫文件;
所以全局安裝了之後並不能讓我們在所有的項目中使用 axios等庫;

項目安裝

項目安裝會在當前目錄下生產一個 node_modules 文件夾,我們之前講解require查找順序時有講解過這個包在什麼情況下被查找;

局部安裝分為開發時依賴和生產時依賴:

#安裝開發和生產依賴npminstallaxios--savenpminstallaxios-Snpminstallaxiosnpmiaxios#開發者npminstallaxios--save-devnpminstallaxios-Dnpmiaxios-D2.2. npm install原理

很多同學之情應該已經會了 npm install <package>,但是你是否思考過它的內部原理呢?

執行 npm install它背後幫助我們完成了什麼操作?

我們會發現還有一個成為package-lock.json的文件,它的作用是什麼?

從npm5開始,npm支持緩存策略(來自yarn的壓力),緩存有什麼作用呢?

這是一幅我畫出的根據 npm install 的原理圖:

npm install會檢測是有package-lock.json文件:
檢測lock中包的版本是否和package.json中一致(會按照semver版本規範檢測);
一致的情況下,會去優先查找緩存
查找到,會獲取緩存中的壓縮文件,並且將壓縮文件解壓到node_modules文件夾中;
不一致,那麼會重新構建依賴關係,直接會走頂層的流程;
沒有找到,會從registry倉庫下載,直接走頂層流程;
分析依賴關係,這是因為我們可能包會依賴其他的包,並且多個包之間會產生相同依賴的情況;
從registry倉庫中下載壓縮包(如果我們設置了鏡像,那麼會從鏡像服務器下載壓縮包);
獲取到壓縮包後會對壓縮包進行緩存(從npm5開始有的);
將壓縮包解壓到項目的node_modules文件夾中(前面我們講過,require的查找順序會在該包下面查找)
沒有lock文件
有lock文件
npm install原理圖

package-lock.json文件:

{"name":"learn-npm","version":"1.0.0","lockfileVersion":1,"requires":true,"dependencies":{"axios":{"version":"0.20.0","resolved":"https://registry.npmjs.org/axios/-/axios-0.20.0.tgz","integrity":"sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==","requires":{"follow-redirects":"^1.10.0"}},"follow-redirects":{"version":"1.13.0","resolved":"https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz","integrity":"sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA=="}}}

package-lock.json文件解析:

name:項目的名稱;
version:項目的版本;
lockfileVersion:lock文件的版本;
requires:使用requires來跟着模塊的依賴關係;
dependencies:項目的依賴
version表示實際安裝的axios的版本;
resolved用來記錄下載的地址,registry倉庫中的位置;
requires記錄當前模塊的依賴;
integrity用來從緩存中獲取索引,再通過索引去獲取壓縮包文件;
當前項目依賴axios,但是axios依賴follow-redireacts;
axios中的屬性如下:
2.3. 其他npm命令

我們這裡再介紹幾個比較常用的:

卸載某個依賴包:

npmuninstallpackagenpmuninstallpackage--save-devnpmuninstallpackage-D

強制重新build

npmrebuild

清除緩存

npmcacheclean

npm的命令其實是非常多的:

https://docs.npmjs.com/cli-documentation/cli
更多的命令,可以根據需要查閱官方文檔
2.4. yarn和cnpm

另一個node包管理工具yarn:

yarn是由Facebook、Google、Exponent 和 Tilde 聯合推出了一個新的 JS 包管理工具;
yarn 是為了彌補 npm 的一些缺陷而出現的;
早期的npm存在很多的缺陷,比如安裝依賴速度很慢、版本依賴混亂等等一系列的問題;
雖然從npm5版本開始,進行了很多的升級和改進,但是依然很多人喜歡使用yarn;

這裡給出一張常用命令的對比

npm和yarn常用命令對比

補充:cnpm

由於一些特殊的原因,某些情況下我們沒辦法很好的從 https://registry.npmjs.org下載下來一些需要的包。

查看npm鏡像:

npmconfiggetregistry#npmconfiggetregistry

我們可以直接設置npm的鏡像:

npmconfigsetregistryhttps://registry.npm.taobao.org

但是對於大多數人來說(比如我),並不希望將npm鏡像修改了:

第一,不太希望隨意修改npm原本從官方下來包的渠道;
第二,擔心某天淘寶的鏡像掛了或者不維護了,又要改來改去;

這個時候,我們可以使用cnpm,並且將cnpm設置為淘寶的鏡像:

npminstall-gcnpm--registry=https://registry.npm.taobao.orgcnpmconfiggetregistry#https://r.npm.taobao.org/

補充:npx

npx是npm5.2之後自帶的一個命令。

npx的作用非常多,但是比較常見的是使用它來調用項目中的某個模塊的指令。

我們以webpack為例:

全局安裝的是webpack5.1.3
項目安裝的是webpack3.6.0

如果我在終端執行 webpack --version使用的是哪一個命令呢?

顯示結果會是 webpack 5.1.3,事實上使用的是全局的,為什麼呢?
原因非常簡單,在當前目錄下找不到webpack時,就會去全局找,並且執行命令;

那麼如何使用項目(局部)的webpack,常見的是兩種方式:

方式一:明確查找到node_module下面的webpack
方式二:在 scripts定義腳本,來執行webpack;

方式一:在終端中使用如下命令(在項目根目錄下)

./node_modules/.bin/webpack--version

方式二:修改package.json中的scripts

"scripts":{"test":"echo\"Error:notestspecified\"&&exit1","webpack":"webpack--version"},

終端中執行:

npmrunwebpack

但是這兩種方式都有一點點麻煩,更好的辦法是直接使用npx:

npxwebpack--version

npx的原理非常簡單,它會到當前目錄的node_modules/.bin目錄下查找對應的命令;

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 鑽石舞台 的頭像
    鑽石舞台

    鑽石舞台

    鑽石舞台 發表在 痞客邦 留言(0) 人氣()