- Node.js[5] connect & express簡介
- Node.js[4] 第一個模塊
- Node.js[3] 俯瞰API (整理中)
- Node.js[2] Hello Node
- Node.js[1] 俯瞰NPM
- Node.js[0] 簡介
前面幾篇算是node各種基礎,這篇向着創建第一個node模塊的目標邁進。之前的文章反復提及模塊在node中的重要性。正因為有了模塊,node才有了擴展性,才會有如此多的node社區成員參與進來,node才能如此迅速地發展。
NPM(Node Packaged Module,之后簡稱module或模塊)是node的內置功能,通過module的形式為node帶來更多的API。其實node原生API也是通過模塊的形式提供給開發者使用的。
模塊?
node實現了commonjs module規范。下面的例子來自Module規范,修改了require輸入參數以便能在node中運行,請參照注釋分別保存至3個文件中,或者下載完整示例代碼:
// 這段代碼保存為文件math.js
exports.add = function() {
var sum = 0, i = 0, args = arguments, l = args.length;while (i < l) {
sum += args[i++];}return sum;
};// 這段代碼保存為文件increment.js
var add = require('./math').add;
exports.increment = function(val) {
return add(val, 1);
};// 這段代碼保存為文件program.js
var inc = require('./increment').increment;
var a = 1;
inc(a); // 2
console.log('a=', inc(a));
模塊分類
node中模塊可分為核心模塊(Core Module)和第三方模塊,核心模塊是node內置模塊,通常存在於node安裝路徑lib目錄下;第三方模塊也就是本文討論並期望創建的模塊。
Require & Module path
上面的代碼中出現的require是node中加載模塊的全局函數,node是如何尋找到對應模塊的呢?簡明規則如下:
- 路徑為Y的module中使用 require(X)
- 如果是X為核心模塊,命中則結束
- 如果X以‘./’、‘/’、‘../’開頭時,加載第三方模塊,命中則結束
- 查找失敗拋出異常
這里能看到完整描述:
require(X) from module at path Y1. If X is a core module,a. return the core module
b. STOP2. If X begins with './' or '/' or '../'
a. LOAD_AS_FILE(Y + X)b. LOAD_AS_DIRECTORY(Y + X)3. LOAD_NODE_MODULES(X, dirname(Y))4. THROW "not found"
LOAD_AS_FILE(X)1. If X is a file, load X as JavaScript text. STOP2. If X.js is a file, load X.js as JavaScript text. STOP3. If X.node is a file, load X.node as binary addon. STOPLOAD_AS_DIRECTORY(X)1. If X/package.json is a file,
a. Parse X/package.json, and look for "main" field.b. let M = X + (json main field)c. LOAD_AS_FILE(M)2. If X/index.js is a file, load X/index.js as JavaScript text. STOP3. If X/index.node is a file, load X/index.node as binary addon. STOPLOAD_NODE_MODULES(X, START)1. let DIRS=NODE_MODULES_PATHS(START)2. for each DIR in DIRS:a. LOAD_AS_FILE(DIR/X)b. LOAD_AS_DIRECTORY(DIR/X)NODE_MODULES_PATHS(START)1. let PARTS = path split(START)2. let ROOT = index of first instance of "node_modules" in PARTS, or 03. let I = count of PARTS - 14. let DIRS = []5. while I > ROOT,
a. if PARTS[I] = "node_modules" CONTINUEc. DIR = path join(PARTS[0 .. I] + "node_modules")
b. DIRS = DIRS + DIRc. let I = I - 16. return DIRS
模塊結構
connect-header是筆者使用express期間寫的一個小模塊,足夠簡單且包含了第三方模塊的諸多元素,比較適合作為入門示例。
這里用connect-header作為示例,歡迎fork,同樣可用下面命令安裝:
$ npm install connect-header
文件結構
以下假設之前執行npm install的路徑為X,我們看到connect-header被安裝在X/node_modules/connect-header;X/node_modules是node安裝第三方模塊的默認位置;node已不推薦將模塊安裝至全局路徑下,更推薦本地安裝,可能是出於移植的考慮。
- lib 模塊代碼
- header.js 代碼寫在這里!
- index.js node默認加載模塊
- test Unit Test
- header.js
- .npmignore 模塊發布時本地文件忽略列表
- LICENSE 版權聲明
- package.json 模塊屬性聲明
- README.md 模塊介紹
- test.js UT啟動腳本
package.json
模塊中最為重要的文件,申明了各種模塊級別的屬性,或稱為元數據。這些元數據部分由npm程序讀取,部分是npmjs.org上模塊頁面的數據源。完整文檔請參考npm json,網上找到的一個交互文檔也可參考。首次接觸package.json可以使用”npm init”,這是個交互式package.json生成工具。
$ npm init
針對connect-header的package.json,我們分析每個字段的意義(見注釋):
{"name":"connect-header", //模塊名稱"version":"0.0.5", //模塊版本號"description":"General header middleware for Connect.","author":{ //模塊作者信息"name":"Luics","email":"luics.king@gmail.com","url":"http://github.com/luics"},"repository":{ //模塊代碼庫"type":"git","url":"https://github.com/luics/connect-header.git"},"bugs":{ //Bug提交頁面"url":"http://github.com/luics/connect-header/issues"},"main":"./lib", //模塊入口"dependencies":{
},"devDependencies":{ //開發依賴模塊"qunit":"*" //用於unit test},"scripts":{ //unit test腳本"test":"node test"},"engines":{ //依賴的node版本"node":">= 0.4.0"},"licenses":[ //版權信息{"type":"MIT","url":"http://www.opensource.org/licenses/MIT"}],"keywords":["connect", "express", "header", "general"]}
README
主要包括模塊背景介紹,使用說明,sample代碼,資源連接;是其他人了解模塊的主要途徑,一般高質量的模塊都會有一個結構清晰、介紹詳盡的README;npmjs和github上的都支持markdown格式的README,一般文件后綴為mk、markdown。
Unit Test
UT是其他開發者了解模塊的一個窗口,比起README,UT更加接近模塊的實現細節;通常高質量的模塊也會有高質量的UT代碼;UT的質量可以通過覆蓋率等衡量..
模塊發布
下面的命令用於發布模塊:
$ npm publish
首次使用“npm publish”會失敗,提示需要先使用“npm adduser”添加一個npmjs.org的賬號。之后每次使用“npm publish”需要手動更新package.json的version字段。
更多資源
markdown-util是筆者寫的另一個模塊,同樣比較簡單,用於將markdown源文件生成html文件,並提供了2套皮膚(github、default),支持自定義皮膚模板。更多優質資源自然都在NPM Registry中,日后也會挑出不同類型的典型模塊詳細分析。
$ npm install markdown-util