Node.js module system (三) - module 的三種類型

在 Node.js 中的模組有大三類型, 要如何區別他們, 以及它們是如何被運作的, 將是這篇的重點

Node.js 中模組的三大類型

  • 核心模組
    • 文件操作的 fs
    • http 服務的 http
  • 第三方模組
    • 需透過 npm 下載的第三方套件
  • 自己撰寫的模組
    • 自己撰寫的 JS 腳本

另外, 三大模組形態還可以將他們區分為兩種型態(標示符)

  1. 非路徑形式的模組
    • 核心模組
    • 第三方模組
  2. 路徑形式的模組
    • 自己撰寫的模組

路徑形式的模組

只有自己撰寫的模組被歸類在 路徑形式的模組 當中, 它的特性是 require 時必須添加路徑, 如:

1
let foo = require('./foo.js')

透過相對路徑的方式, 找到你自己撰寫的 JS 檔案, 並且引入使用

或者透過絕對路徑, 如:

1
let foo = require('/foo.js')

開頭直接為 / 代表的是該檔案所屬的硬碟根目錄, 在 windows 系統中, 如果檔案位在 C 槽下的話, 則 require('/foo.js') 代表載入 C:/foo.js, 不過這種方法幾乎不會使用, 只要了解就可以了。

.js 的後綴名可以省略

非路徑形式的模組

核心模組第三方模組 都是屬於這個分類, 共同點是他們都不需要加上路徑, 只需要單純用該模組的名字來引入就可以了, 如:

引入核心模組 http

1
let http = require('http')

引入第三方模組 art-template

1
let tpl = require('art-template')

核心模組

當引入自己撰寫的模組時, 我們都很清楚, 其實我們引入的就是自己寫好的 JS 檔案。那麼當我們像 let http = require('http') 引入 http 模組時, 它到底引入的是什麼東西呢?

一樣是 JS 檔案

沒錯, 它的本質一樣是 JS 檔案, 實際上它是真實存在的一支檔案, 由 Node.js 開發人員所撰寫, 並且被編譯成二進制文件中。在開發時我們只需要知道它的名字, 需要時引入就可以了。

Node.js 是開源的, 原始碼都可以在 Github 上找到, 我們可以來看看能不能找到 http.js 這隻檔案

原始碼連結

第三方模組

凡是第三方模組, 都必須透過 npm 套件管理工具下載, 例如:

1
npm install art-template

這時候檔案所在資料夾下多了一個 node_modules 資料夾, 裡面也會有一個 art-template 資料夾, 當中包含了這個套件的相關檔案。

現在就可以 require('套件名') 的方式來載入使用

1
let tpl = require('art-template')

第三方模組核心模組 在載入時, 都不需要路徑, 他們的載入方式是一樣的, 因此不可能有任何一個 第三方模組 的名字是和 Node.js 的核心模組相同的, 因為套件開發者將套件上傳到 npm 時, 若名稱與核心模組一樣, 是無法上傳的。


如何判斷是否為第三方模組

既然第三方模組核心模組載入的方式都不需要路徑, 那當 Node.js 引擎是如何判斷這個 require 是哪種類型呢? 以下用 第三方模組 art-template 當作範例來說明 Node.js 判斷模組類型的流程

  • Node.js 引擎讀取到 let tpl = require('art-template')
    1. 不具有路徑, 判斷它並非 自己撰寫的模組
    2. 核心模組並沒有一個名字叫做 art-template 的, 判斷它並非 核心模組
    3. 排除以上兩個可能, 確定它是一個 第三方模組

第三方模組查找規則

現在 Node.js 知道這個 art-template 是一個第三方模組了, 接著它是如何知道具體該去載入哪支 JS 檔呢?

  1. 首先 Node 會優先從當前檔案所處資料夾中, 尋找有沒有 node_modules 資料夾
    • 若沒有 node_modules 資料夾, 則執行 A. (↓)
  2. 尋找 node_modules 內, 有沒有 art-template 資料夾
    • 若沒有 art-template 資料夾, 則執行 A.
  3. 尋找 art-template 內, 有沒有 package.json 檔案
    • 若沒有 package.json, 預設會 require art-template/index.js。 若 index.js 也不存在, 執行 A.
  4. 尋找 package.json 內的 main 屬性, 而它的值將會是最終被 require 的檔案
    • 若沒有 main 屬性, 預設會 require art-template/index.js。若 index.js 也不存在, 執行 A.

A. 進入上一級資料夾找 node_modules, 直到找到該檔案硬碟根目錄為止, 若有找到則重複執行上述流程。若沒找到, 則報錯誤 can not find module xxx

上述的流程概念有點類似 JavaScript 的原型鏈作用域特性, 就是不斷地往外查找, 你可以以同樣的思路去理解。

延伸閱讀

深入淺出Node.js(三):深入Node.js 的模塊機制