Node.js[4] 第一個模塊


前面幾篇算是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是如何尋找到對應模塊的呢?簡明規則如下:

  1. 路徑為Y的module中使用 require(X)
  2. 如果是X為核心模塊,命中則結束
  3. 如果X以‘./’、‘/’、‘../’開頭時,加載第三方模塊,命中則結束
  4. 查找失敗拋出異常

這里能看到完整描述

require(X) from module at path Y
1. If X is a core module,
   a. return the core module
   b. STOP
2. 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.  STOP
2. If X.js is a file, load X.js as JavaScript text.  STOP
3. If X.node is a file, load X.node as binary addon.  STOP
LOAD_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.  STOP
3. If X/index.node is a file, load X/index.node as binary addon.  STOP
LOAD_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 0
3. let I = count of PARTS - 1
4. let DIRS = []
5. while I > ROOT,
   a. if PARTS[I] = "node_modules" CONTINUE
   c. DIR = path join(PARTS[0 .. I] + "node_modules")
   b. DIRS = DIRS + DIR
   c. let I = I - 1
6. 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

組里急招FE實習生,應聘條件請參考此處,工作地點是百度上海研發中心,有興趣的同學請將簡歷發給我


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM