在 Node 中使用 RequireJS
Node 不是已經有模組載入器了嗎? § 1
是的,Node 有。該載入器使用 CommonJS 模組格式。CommonJS 模組格式不適合瀏覽器,而且我不同意CommonJS 模組格式中做出的部分取捨。透過在伺服器上使用 RequireJS,您可以為所有模組使用一種格式,無論它們是在伺服器端執行還是瀏覽器中執行。這樣,您可以保留在瀏覽器中使用 RequireJS 獲得的速度優勢和輕鬆除錯功能,而且不必擔心在兩種格式之間移動的額外轉換成本。
如果您想為模組使用 define(),但仍然在 Node 中執行它們,而不需要在伺服器上執行 RequireJS,請參閱以下區段,了解如何使用amdefine。
我可以使用已經以 CommonJS 模組格式撰寫的 Node 模組嗎? § 2
是的!RequireJS 的 Node 介面程式,稱為 r.js,如果使用 RequireJS 使用的組態找不到模組,將使用 Node 的 require 實作和 Node 的搜尋路徑,因此您可以繼續使用現有的基於 Node 的模組,而不需要對它們進行變更。
RequireJS 會先使用其組態選項來尋找模組。如果 RequireJS 無法使用其組態找到模組,則假設它是一個使用 Node 型態的模組和組態的模組。因此,僅當模組使用 RequireJS API 時,才使用 RequireJS 組態模組位置。對於預期 Node 的 API 和組態/路徑的模組,只需使用 Node 套件管理員(例如npm)安裝它們,並且不要使用 RequireJS 組態它們的位置。
最佳實務:使用 npm 將僅限 Node 的套件/模組安裝到專案的 node_modules 目錄中,但不要組態 RequireJS 以在 node_modules 目錄中尋找。此外,避免使用相對模組 ID 來參照僅限 Node 的模組。因此,不要執行類似 require("./node_modules/foo/foo") 的動作。
其他注意事項
- Node 中的 RequireJS 只能載入位於本機磁碟上的模組,例如,目前不支援透過 http 取得模組。
- 僅當 RequireJS 載入模組時,才會套用 RequireJS 組態選項,例如 map、packages、paths。如果 RequireJS 需要詢問 node 模組系統,原始 ID 會傳遞給 Node。如果您需要一個 node 模組與 map 組態搭配使用,內嵌 define() 呼叫會起作用,如此電子郵件串中所示。
如何使用? § 3
取得 Node 介面程式有兩種方法
npm
使用 npm 安裝
npm install requirejs
此選項會安裝最新版本。
下載 r.js
如果您不想使用 npm,您可以直接取得 r.js
用法
這些說明假設透過 npm 安裝「requirejs」。如果您直接使用 r.js 檔案,請將 require('requirejs') 替換為 require('./path/to/r.js')。基本用法為
- require('requirejs')
- 將主 js 檔案的「require」函式傳遞到 requirejs 的組態中。
範例
var requirejs = require('requirejs');
requirejs.config({
//Pass the top-level main.js/index.js require
//function to requirejs so that node modules
//are loaded relative to the top-level JS file.
nodeRequire: require
});
requirejs(['foo', 'bar'],
function (foo, bar) {
//foo and bar are loaded according to requirejs
//config, but if not found, then node's require
//is used to load the module.
});
務必閱讀 第 2 節中的注意事項,了解如何組態 RequireJS,以便它可以載入透過 npm 安裝的僅限 Node 模組。
若要查看更完整的範例,該範例會透過 RequireJS 載入模組,但對其他事項使用原生 Node 模組,請參閱 r.js repo 中的 嵌入式測試。
注意: requirejs([], function() {})
會在 RequireJS 2.1+ 中非同步呼叫函式 callback(在較早版本中,它是同步呼叫)。但是,在 Node 中執行時,模組載入將使用同步 IO 呼叫載入,而載入器外掛程式應同步解析其載入方法的呼叫。這允許透過 requirejs('stringValue') 呼叫,在 Node 中同步使用 requirejs 模組
//Retrieves the module value for 'a' synchronously
var a = requirejs('a')
使用 AMD 或 RequireJS 建置 Node 模組
如果您想要編寫一個模組,以便它可以在 RequireJS 和 Node 中運作,而不需要 Node 中的程式庫使用者使用 RequireJS,那麼您可以使用 amdefine 套件來執行此操作
if (typeof define !== 'function') {
var define = require('amdefine')(module);
}
define(function(require) {
var dep = require('dependency');
//The value returned from the function is
//used as the module export visible to Node.
return function () {};
});
RequireJS 最佳化器(版本 1.0.3)將移除上述「amdefine」的使用,因此也可以安全地將此模組用於您的網頁專案。只要確定使用 與上述所示完全相同的「amdefine」if() 測試和內容。允許空格/換行符號有差異。請參閱 amdefine 專案 以取得更多資訊。
如果您想要直接使用 RequireJS 來編寫您的模組,然後將模組值匯出到 Node,以便可以在其他 Node 程式中使用,而不需要該應用程式使用 RequireJS,您可以使用下一個範例中列出的方法。
最好將 baseUrl 特別設定為包含模組的目錄,以便在嵌套在 node_modules 階層中時正常運作。使用同步的 requirejs('moduleId')
使用 requirejs 中的組態和規則擷取模組,然後使用 Node 的 module.exports 匯出您的模組值
var requirejs = require('requirejs');
requirejs.config({
//Use node's special variable __dirname to
//get the directory containing this file.
//Useful if building a library that will
//be used in node but does not require the
//use of node outside
baseUrl: __dirname,
//Pass the top-level main.js/index.js require
//function to requirejs so that node modules
//are loaded relative to the top-level JS file.
nodeRequire: require
});
//foo and bar are loaded according to requirejs
//config, and if found, assumed to be an AMD module.
//If they are not found via the requirejs config,
//then node's require is used to load the module,
//and if found, the module is assumed to be a
//node-formatted module. Note: this synchronous
//style of loading a module only works in Node.
var foo = requirejs('foo');
var bar = requirejs('bar');
//Now export a value visible to Node.
module.exports = function () {};
使用最佳化器作為節點模組
節點模組也公開 RequireJS 最佳化器作為 最佳化 方法,以透過函式呼叫而非命令列工具來使用 RequireJS 最佳化器
var requirejs = require('requirejs');
var config = {
baseUrl: '../appDir/scripts',
name: 'main',
out: '../build/main-built.js'
};
requirejs.optimize(config, function (buildResponse) {
//buildResponse is just a text output of the modules
//included. Load the built file for the contents.
//Use config.out to get the optimized file contents.
var contents = fs.readFileSync(config.out, 'utf8');
}, function(err) {
//optimization err callback
});
這允許您建立其他最佳化工作流程,例如 網頁建構器,如果您偏好始終使用「在 </body> 標籤之前包含一個腳本檔案」方法進行開發,則可以使用此建構器。在 Node 中執行的最佳化器相當快速,但對於不想為每個瀏覽器要求重新產生建構,而只在您修改建構中包含的腳本時才重新產生建構的大型專案而言,您可以使用 Node 的 fs.watchFile() 來監控檔案,然後在檔案變更時觸發建構。
回饋
如果您發現問題並想要回報,請使用 r.js GitHub 問題頁面。