package.json 跟 package-lock.json 的知識點挺多的, 這裏只聊一聊部分知識點node
npm install 安裝依賴的時候,能夠經過以下方式,把依賴寫入package.jsonreact
npm install --save 或者 npm install -S npm install --save-dev 或者 npm install -D
dependencies與devDependencies的區別:npm
devDependencies下列出的模塊,是咱們開發時用的依賴項,像一些進行單元測試之類的包,好比jest,咱們用寫單元測試,它們不會被部署到生產環境。dependencies下的模塊,則是咱們生產環境中須要的依賴,即正常運行該包時所須要的依賴項。json
記着這句: "正常運行該包時所須要的依賴項"
後面的package-lock.json 中的 dependencies 對應的就是package.json中的 dependenciesredux
使用第三方依賴時,一般須要指定依賴的版本範圍,好比安全
"dependencies": { "antd": "3.1.2", "react": "~16.0.1", "redux": "^3.7.2", "lodash": "*" }
上面的 package.json 文件代表,項目中使用的 antd 的版本號是 3.1.2,可是 3.1.1 和 3.1.二、3.0.一、2.1.1 之間有什麼不一樣呢。antd
語義化版本規則規定,版本格式爲:主版本號.次版本號.修訂號,而且版本號的遞增規則以下:app
主版本號的更新一般意味着大的修改和更新,升級主版本後可能會使你的程序報錯,所以升級主版本號需謹慎,可是這每每也會帶來更好的性能和體驗。ide
次版本號的更新則一般意味着新增了某些特性,好比 antd 的版本從 3.1.1 升級到 3.1.2,以前的 Select 組件不支持搜索功能,升級以後支持了搜索。性能
修訂號的更新則每每意味着進行了一些 bug 修復。所以次版本號和修訂號應該保持更新,這樣能讓你以前的代碼不會報錯還能獲取到最新的功能特性。
可是,每每咱們不會指定依賴的具體版本,而是指定版本範圍,好比上面的 package.json 文件裏的 react、redux 以及 lodash,這三個依賴分別使用了三個符號來代表依賴的版本範圍。語義化版本範圍規定:
所以,上面的 package.json 文件安裝的依賴版本範圍以下:
react@~16.0.1:>=react@16.0.1 && < react@16.1.0 redux@^3.7.2:>=redux@3.7.2 && < redux@4.0.0 lodash@*:lodash@latest
語義化版本規則定義了一種理想的版本號更新規則,但願全部的依賴更新都能遵循這個規則,可是每每會有許多依賴不是嚴格遵循這些規定的。
所以,如何管理好這些依賴,尤爲是這些依賴的版本就顯得尤其重要,不然一不當心就會陷入因依賴版本不一致致使的各類問題中。
咱們都知道,執行 npm install 後,依賴包被安裝到了 node_modules ,下面咱們來具體瞭解下,npm 將依賴包安裝到 node_modules 的具體機制是什麼。
在 npm 的早期版本, npm 處理依賴的方式簡單粗暴,以遞歸的形式,嚴格按照 package.json 結構以及子依賴包的 package.json 結構將依賴安裝到他們各自的 node_modules 中。直到有子依賴包不在依賴其餘模塊。
舉個例子,咱們的模塊 my-app 如今依賴了兩個模塊:buffer、ignore:
{ "name": "my-app", "dependencies": { "buffer": "^5.4.3", "ignore": "^5.1.4", } }
ignore是一個純 JS 模塊,不依賴任何其餘模塊,而 buffer 又依賴了下面兩個模塊:base64-js 、 ieee754。
{ "name": "buffer", "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" } }
那麼,執行 npm install 後,獲得的 node_modules 中模塊目錄結構就是下面這樣的:
這樣的方式優勢很明顯, node_modules 的結構和 package.json 結構一一對應,層級結構明顯,而且保證了每次安裝目錄結構都是相同的。
可是,試想一下,若是你依賴的模塊很是之多,你的 node_modules 將很是龐大,嵌套層級很是之深:
爲了解決以上問題,NPM 在 3.x 版本作了一次較大更新。其將早期的嵌套結構改成扁平結構:
此時咱們若在模塊中又依賴了 base64-js@1.0.1 版本:
{ "name": "my-app", "dependencies": { "buffer": "^5.4.3", "ignore": "^5.1.4", "base64-js": "1.0.1", } }
此時,咱們在執行 npm install 後將獲得下面的目錄結構:
對應的,若是咱們在項目代碼中引用了一個模塊,模塊查找流程以下:
假設咱們又依賴了一個包 buffer2@^5.4.3,而它依賴了包 base64-js@1.0.3,則此時的安裝結構是下面這樣的:
因此 npm 3.x 版本並未徹底解決老版本的模塊冗餘問題,甚至還會帶來新的問題。
另外,爲了讓開發者在安全的前提下使用最新的依賴包,咱們在 package.json 一般只會鎖定大版本,這意味着在某些依賴包小版本更新後,一樣可能形成依賴結構的改動,依賴結構的不肯定性可能會給程序帶來不可預知的問題。
爲了解決 npm install 的不肯定性問題,在 npm 5.x 版本新增了 package-lock.json 文件,而安裝方式還沿用了 npm 3.x 的扁平化的方式。
package-lock.json 的做用是鎖定依賴結構,即只要你目錄下有 package-lock.json 文件,那麼你每次執行 npm install 後生成的 node_modules 目錄結構必定是徹底相同的。
例如,咱們有以下的依賴結構:
{ "name": "my-app", "dependencies": { "buffer": "^5.4.3", "ignore": "^5.1.4", "base64-js": "1.0.1", } }
在執行 npm install 後生成的 package-lock.json 以下:
{ "name": "my-app", "version": "1.0.0", "dependencies": { "base64-js": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.0.1.tgz", "integrity": "sha1-aSbRsZT7xze47tUTdW3i/Np+pAg=" }, "buffer": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" }, "dependencies": { "base64-js": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" } } }, "ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "ignore": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==" } } }
咱們來具體看看上面的結構:
最外面的兩個屬性 name 、version 同 package.json 中的 name 和 version ,用於描述當前包名稱和版本。
dependencies 是一個對象,對象和 node_modules 中的包結構一一對應,對象的 key 爲包名稱,值爲包的一些描述信息:
這裏注意,並非全部的子依賴都有 dependencies 屬性,只有子依賴的依賴和當前已安裝在根目錄的 node_modules 中的依賴衝突以後,纔會有這個屬性。
例如,回顧下上面的依賴關係:
咱們在 my-app 中依賴的 base64-js@1.0.1 版本與 buffer 中依賴的 base64-js@^1.0.2 發生衝突,因此 base64-js@1.0.1 須要安裝在 buffer 包的 node_modules 中,對應了 package-lock.json 中 buffer 的 dependencies 屬性。這也對應了 npm 對依賴的扁平化處理方式。
因此,根據上面的分析, package-lock.json 文件 和 node_modules 目錄結構是一一對應的,即項目目錄下存在 package-lock.json 可讓每次安裝生成的依賴目錄結構保持相同。
開發系統應用時,建議把 package-lock.json 文件提交到代碼版本倉庫,從而保證全部團隊開發者以及 CI 環節能夠在執行 npm install 時安裝的依賴版本都是一致的。
在開發一個 npm包 時,你的 npm包 是須要被其餘倉庫依賴的,因爲上面咱們講到的扁平安裝機制,若是你鎖定了依賴包版本,你的依賴包就不能和其餘依賴包共享同一 semver 範圍內的依賴包,這樣會形成沒必要要的冗餘。因此咱們不該該把package-lock.json 文件發佈出去( npm 默認也不會把 package-lock.json 文件發佈出去,固然若是非要用package-lock.json也是能夠的)。