摘要:包與NPM Node組織了自身的核心子產品,也使得第三方檔案子產品可以有序的編寫和使用。
本文分享自華為雲社群《NodeJs深入淺出之旅:包與NPM》,作者:空城機。
包與NPM
Node組織了自身的核心子產品,也使得第三方檔案子產品可以有序的編寫和使用。
但是在第三方子產品中,子產品與子產品之間仍然是散列在各地的,互相之間不能直接引用
是以在子產品外,包和NPM是将子產品聯系起來的機制。
- 包組織子產品示意圖
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicGcq5ydwIzNfljY1EWN5I2MxUWMzMDZ5ITMxUjMjNWYyEGMjJzMhVmYtIjdvwFM48CXt92YucWbphmeuIzYpB3Lc9CX6MHc0RHaiojIsJye.jpg)
CommonJS 的包規範定義其實也很簡單,由包結構和包描述檔案兩部分組成。
包結構
用于組織包中的各種檔案,是一個存檔檔案,即一個目錄直接打包為.zip或tar.gz格式的檔案。
符合規範的包目錄:
- package.json: 包描述檔案
- bin: 用于存放可執行二進制檔案的目錄
- lib: 用于存放JavaScript代碼的目錄
- doc: 用于存放文檔的目錄
- test: 用于存放單元測試用例的代碼
package.json包描述檔案
NPM所有行為都與包描述檔案的字段息息相關
一些字段:
- name: 包名。 規範定義需要用小寫的字母和數字組成,不允許出現空格。 包名必須是唯一的,以免對外公布時産生重名沖突
- description: 包簡介
- version: 版本号,關于其介紹在《Node.js學習(一)——簡介》也有提及
- keywords: 關鍵字數組, NPM中主要用來作分類搜尋。
- maintainers: 包維護者清單。 每個維護者由name、email和web這3個屬性組成。 NPM通過這個屬性進行權限認證。
格式:
"maintainers":[{ "name":"kongchengji", "email":"[email protected]", "web":"[http:](https://blog.csdn.net/qq_36171287)" }]
contributors: 貢獻者清單,格式與維護者清單相同
- bugs: 一個可以回報bug的網頁位址或郵件位址
- licenses: 目前包所使用的許可證清單,表示包在哪些許可證下使用
"licenses":[{ "type": "GPLv2", "url":"" }]
// 或者
"license": "ISC"
- repositories: 托管源代碼的位置清單,表明可以通過哪些方式和位址通路包源代碼。
- "repository": {
- "type": "git",
- "url": "git+https://github.com/kongchengji/UiSelfMade.git"
- },
- dependencies: 使用目前包所需要依賴的包清單。 這個屬性非常重要
- homepage: 目前包的網站位址
- os: 作業系統支援清單, 如果清單為空,則不對作業系統做任何假設
- cpi: CPU架構支援清單
- engine:支援的JavaScript引擎清單
- directories:包目錄說明
- implements: 實施規範的清單。 标志目前包實作了CommonJS哪些規範
- scripts: 腳本說明對象。 主要用于被包管理器用來安裝、編譯、測試和解除安裝包
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"lint": "eslint --ext .js,.vue src",
"build": "node build/build.js"
},
NPM與包規範差別在于多了四個字段:
- author: 包作者 :ok_man:
- bin: 一些包作者希望包可以作為指令行工具使用。
- main: 子產品引入包時,會有限檢查這個字段,并将其作為包中其餘子產品的入口子產品。 如果不存在,require會查找包目錄下的index.js、index.node、index.json作為預設入口
- devDependencies: 一些子產品隻在開發時需要依賴。
devDependencies:開發環境使用
dependencies:生産環境使用
前後端共用子產品
JavaScript在Node出現後,有一項優勢 --> 一些子產品可以在前後端實作共用。
但是前後端上始終還是有一些差别的 :sweat_drops:
前後端子產品側重點
前後端JavaScript分别擱置在HTPP的兩端,扮演的角色并不同。
浏覽器端的JavaScript需要經曆從同一個伺服器端分發到多個用戶端執行,瓶頸是帶寬,從網絡加載代碼
伺服器端的JavaScript是相同代碼需要多次執行,瓶頸是CPU和記憶體等資源,從磁盤中加載
在前端JavaScript中,主要還是應用AMD規範。
CommonJS并不完全适用于前端JavaScript,比如Node的子產品引入基本是同步的,但是前端引入如果使用同步引入,UI在初始化過程中需要花費很多時間等待腳本加載完成。
AMD規範
AMD規範 是CommonJS規範的一個延伸,全稱:Asynchronous Module Definition。
是異步子產品定義
子產品定義:define(id?, dependencies?, factory);
id 是子產品的名字,它是可選的參數。
dependencies 指定了所要依賴的子產品清單,它是一個數組,也是可選的參數
AMD需要在聲明子產品時指定所有的依賴,通過形參傳遞依賴到子產品内容中:
define(['./a', './b'], function (dep1, dep2) {
a.doSomethimg()
b.doSomething()
});
CMD規範
與AMD規範相對的還有CMD規範,全稱:Common Module Definition。
是公共子產品定義
這是由國内的玉伯(也是一位大佬)提出的
子產品定義:define(factory)
CMD支援動态引入:
define(function(require, exports, module) {
var a=require('./a')
a.doSomethimg()
var b=require('./b')
b.doSomething()
})
在需要依賴子產品時, 随時調用require()引入即可
- CMD 推崇依賴就近; AMD 推崇依賴前置
- CMD 是延遲執行; AMD 是提前執行
- CMD性能好,因為隻有使用者需要的時候才執行; AMD使用者體驗好,因為沒有延遲,依賴子產品提前執行了
AMD和CMD最大的差別是對依賴子產品的執行時機處理不同
相容多種子產品規範
建立一個hello方法,讓hello方法能在不同運作環境中運作,相容Node、AMD、CMD和常見浏覽器
- 匿名函數前加一個;是個好習慣 name是方法名,definition是方法體
- 通過typeof檢測環境是否為AMD或CMD還是Node環境
- 可以将子產品執行結果挂載在window變量中,這樣可以直接調用
// 匿名函數前加一個;是個好習慣 name是方法名,definition是方法體
;(function (name, definition) {
//檢查環境是否是AMD或CMD
var hasDefine = typeof define === 'function',
// 檢查環境是否為Node
hasExports = typeof module !== 'undefined' && mudule.exports;
if(hasDefine) {
define(definition);
} else if (hasExports) {
module.exports = definition();
} else {
// 将子產品的執行結果挂在window變量中,在浏覽器中this指向window對象
this[name] = definition();
}
})('hello', function () {
var hello = function () {
console.log('hello');
}
return hello;
});
點選關注,第一時間了解華為雲新鮮技術~