我們已經學習了在JavaScript中可以通過模塊化的方式將代碼劃分成一個個小的結構:
如果我們分享給世界上所有的程序員使用,有哪些方式呢?
方式一:上傳到GitHub上、其他程序員通過GitHub下載我們的代碼手動的引用;
缺點是大家必須知道你的代碼GitHub的地址,並且從GitHub上手動下載;
需要在自己的項目中手動的引用,並且管理相關的依賴;
不需要使用的時候,需要手動來刪除相關的依賴;
當遇到版本升級或者切換時,需要重複上面的操作;
顯然,上面的方式是有效的,但是這種傳統的方式非常麻煩,並且容易出錯;
方式二:使用一個專業的工具來管理我們的代碼
顯然,通過第二種方式我們可以更好的管理自己的工具包,其他人也可以更好的使用我們的工具包。
包管理工具npm:
npm管理的包可以在哪裡查看、搜索呢?
npm管理的包存放在哪裡呢?
事實上,我們每一個項目都會有一個對應的配置文件,無論是前端項目還是後端項目:
這個配置文件在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
private屬性:
main屬性:

scripts屬性
dependencies屬性
devDependencies屬性
疑問:那麼在生成環境如何保證不安裝這些包呢?
版本管理的問題
我們會發現安裝的依賴版本出現:^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:
我們這裡解釋一下 ^和~的區別:
engines屬性
browserslist屬性
安裝npm包分兩種情況:
全局安裝
全局安裝是直接將某個包安裝到全局:
比如yarn的全局安裝:
npminstallyarn-g但是很多人對全局安裝有一些誤會:
項目安裝
項目安裝會在當前目錄下生產一個 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 的原理圖:

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文件解析:
我們這裡再介紹幾個比較常用的:
卸載某個依賴包:
npmuninstallpackagenpmuninstallpackage--save-devnpmuninstallpackage-D強制重新build
npmrebuild清除緩存
npmcachecleannpm的命令其實是非常多的:
另一個node包管理工具yarn:
這裡給出一張常用命令的對比

補充:cnpm
由於一些特殊的原因,某些情況下我們沒辦法很好的從 https://registry.npmjs.org下載下來一些需要的包。
查看npm鏡像:
npmconfiggetregistry#npmconfiggetregistry我們可以直接設置npm的鏡像:
npmconfigsetregistryhttps://registry.npm.taobao.org但是對於大多數人來說(比如我),並不希望將npm鏡像修改了:
這個時候,我們可以使用cnpm,並且將cnpm設置為淘寶的鏡像:
npminstall-gcnpm--registry=https://registry.npm.taobao.orgcnpmconfiggetregistry#https://r.npm.taobao.org/補充:npx
npx是npm5.2之後自帶的一個命令。
npx的作用非常多,但是比較常見的是使用它來調用項目中的某個模塊的指令。
我們以webpack為例:
如果我在終端執行 webpack --version使用的是哪一個命令呢?
那麼如何使用項目(局部)的webpack,常見的是兩種方式:
方式一:在終端中使用如下命令(在項目根目錄下)
./node_modules/.bin/webpack--version方式二:修改package.json中的scripts
"scripts":{"test":"echo\"Error:notestspecified\"&&exit1","webpack":"webpack--version"},終端中執行:
npmrunwebpack但是這兩種方式都有一點點麻煩,更好的辦法是直接使用npx:
npxwebpack--versionnpx的原理非常簡單,它會到當前目錄的node_modules/.bin目錄下查找對應的命令;