RequireJS Optimizer

RequireJS 有最佳化工具,可執行下列動作

  • 將相關指令碼組合到建置層中,並透過 UglifyJS(預設)或 Closure Compiler(使用 Java 時的選項)將它們壓縮。
  • 透過內嵌 @import 參照的 CSS 檔案和移除註解來最佳化 CSS。

最佳化程式是 Node 和 Nashorn 的 r.js 介接程式 的一部分,設計為在開發完成且準備為使用者佈署程式碼後,作為建置或封裝步驟的一部分執行。

最佳化程式只會組合傳遞給頂層 require 和 define 呼叫的字串文字陣列中指定的模組,或 簡化的 CommonJS 封裝 中的 require('name') 字串文字呼叫。因此,它不會找到透過變數名稱載入的模組

var mods = someCondition ? ['a', 'b'] : ['c', 'd'];
require(mods);

但如果像這樣指定,則會包含 'a' 和 'b'

require(['a', 'b']);

define(['a', 'b'], function (a, b) {});

這種行為允許在最佳化後動態載入模組。您始終可以使用 include 選項,明確加入最佳化程式靜態分析找不到的模組。

需求 § 1

最佳化程式可以使用 Node、Java 搭配 Rhino 或 Nashorn,或在瀏覽器中執行。每個選項的需求

  • Node:(建議)Node 0.4.0 或更新版本。
  • Java:Java 1.6 或更新版本。
  • 瀏覽器:從 2.1.2 開始,最佳化程式可以在具有 陣列額外功能 的網路瀏覽器中執行。儘管最佳化程式選項與下方所示相同,但它透過 JavaScript 呼叫,而不是命令列選項。它也只適用於產生最佳化的單一檔案,而不是目錄最佳化。請參閱 瀏覽器範例。此選項實際上只適用於提供您程式庫的基於網路的客製化建置。

對於命令列使用,Node 是首選執行環境。使用 Node,最佳化器執行速度快很多

此頁面中的所有範例命令皆假設使用 Node,並在 Linux/OS X 命令列上執行。請參閱 r.js README,了解如何在 Java 中執行。

下載§ 2

1) 您可以在 下載頁面 上下載工具。

2) 如果您使用帶有 NPM 的 Node,您可以將 r.js 全域安裝為 NPM 中「requirejs」套件的一部分

> npm install -g requirejs
> r.js -o app.build.js

如果在 Windows 上,您可能需要輸入 r.js.cmd 而不是 r.js。或者,您可以使用 DOSKEY

DOSKEY r.js=r.js.cmd $*

如果您想將 requirejs 本機安裝在專案中作為 npm 套件,而不是全域安裝

> npm install requirejs

透過此本機安裝,您可以透過執行專案的 node_modules/.bin 目錄中找到的 r.jsr.js.cmd 檔案來執行最佳化器。

透過本機安裝,您也可以 在節點程式中透過函式呼叫使用最佳化器

此頁面的其餘部分假設 r.js 僅從下載頁面手動下載。這通常是最清楚、最便攜的方式來使用最佳化器。

範例設定§ 3

此頁面中的範例將假設您已下載並將 r.js 儲存在與專案目錄平行的目錄中。r.js 中的最佳化器可以放在您想要的任何位置,但您可能需要相應地調整這些範例中的路徑。

範例設定

  • appdirectory
    • main.html
    • css
      • common.css
      • main.css
    • scripts
      • require.js
      • main.js
      • one.js
      • two.js
      • three.js
  • r.js(下載頁面 中的 r.js 最佳化器)

main.html 有 require.js 的指令碼標籤,並透過 require 呼叫載入 main.js,如下所示

<!DOCTYPE html>
<html>
    <head>
        <title>My App</title>
        <link rel="stylesheet" type="text/css" href="css/main.css">
        <script data-main="scripts/main" src="scripts/require.js"></script>
    </head>
    <body>
        <h1>My App</h1>
    </body>
</html>

main.js 透過 require 呼叫載入 one.js、two.js 和 three.js

require(["one", "two", "three"], function (one, two, three) {
});

main.css 有以下內容

@import url("common.css");

.app {
    background: transparent url(../../img/app.png);
}

基礎 § 4

命令列引數可以與建置設定檔屬性交換

您可以在命令列上指定選項

node r.js -o baseUrl=. paths.jquery=some/other/jquery name=main out=main-built.js

或在建置設定檔中。在 build.js 中,可以像這樣指定相同的命令列引數

({
    baseUrl: ".",
    paths: {
        jquery: "some/other/jquery"
    },
    name: "main",
    out: "main-built.js"
})

然後,只要將建置設定檔的檔案名稱傳遞給最佳化器即可

node r.js -o build.js

命令列引數優先於建置設定檔設定,而且您可以將它們混合在一起

node r.js -o build.js optimize=none

命令列引數語法有一個限制。點被視為物件屬性分隔符號,以允許將類似 paths.jquery=lib/jquery 的內容轉換為最佳化器中的以下內容

paths: {
    jquery: 'lib/jquery'
}

但這表示您無法將「core/jquery.tabs」路徑屬性的值設定為值。這無法運作:paths.core/jquery.tabs=empty:,因為它會導致這個不正確的結構

paths: {
    'core/jquery': {
        tabs: 'empty:'
    }
}

如果您需要設定一個路徑,例如「core/jquery.tabs」,請使用一個 build.js 檔案,並將建置選項指定為 JavaScript 物件,而不是使用命令列引數。

如需所有選項的清單,請參閱 所有組態選項

相對路徑解析規則:

一般來說,如果是一個路徑,它會相對於用於存放建置選項的 build.js 檔案,或者如果僅使用命令列引數,則相對於目前的作業目錄。檔案路徑屬性的範例:appDirdirmainConfigFileoutwrap.startFilewrap.endFile

對於 baseUrl,它相對於 appDir。如果沒有 appDir,則 baseUrl 相對於 build.js 檔案,或者如果僅使用命令列引數,則相對於目前的作業目錄。

對於 pathspackages,它們相對於 baseUrl,就像它們對於 require.js 一樣。

對於是模組 ID 的屬性,它們應該是模組 ID,而不是檔案路徑。範例包括 nameincludeexcludeexcludeShallowdeps

在執行時期載入瀏覽器的主要 JS 模組中的組態設定預設不會由最佳化程式讀取

這是因為建置的組態設定可能非常不同,具有多個最佳化目標。因此,需要為最佳化程式指定一組獨立的組態選項。

在最佳化程式的版本 1.0.5+ 中,mainConfigFile 選項可用於指定執行時期組態的位置。如果指定為主要 JS 檔案的路徑,則會解析出該檔案中找到的第一個 requirejs({}), requirejs.config({}), require({}), 或 require.config({}),並用作傳遞給最佳化程式的組態選項的一部分

mainConfigFile: 'path/to/main.js'

組態的優先順序:命令列、建置設定檔、mainConfigFile。換句話說,mainConfigFile 組態的優先順序最低。

最佳化一個 JavaScript 檔案 § 5

使用上述範例設定,如果您只想最佳化 main.js,您可以使用這個命令,從 appdirectory/scripts 目錄中

node ../../r.js -o name=main out=main-built.js baseUrl=.

這將建立一個名為 appdirectory/scripts/main-built.js 的檔案,其中將包含 main.js、one.js、two.js 和 three.js 的內容。

通常,您不應將最佳化檔案儲存到原始專案原始碼中。通常,您會將它們儲存到專案的副本中,但為了簡化此範例,它會與原始碼一起儲存。將out=選項變更為您喜歡的任何目錄,其中包含原始碼的副本。然後,您可以將 main-built.js 檔案名稱變更為 main.js,以便 HTML 頁面載入檔案的最佳化版本。

如果您想將 require.js 納入 main.js 原始碼,可以使用此類型的指令

node ../../r.js -o baseUrl=. paths.requireLib=../../require name=main include=requireLib out=main-built.js

由於「require」是保留的依賴項名稱,因此您建立一個「requireLib」依賴項,並將它對應到 require.js 檔案。

最佳化完成後,您可以將指令碼標籤變更為參考「main-built.js」,而不是「require.js」,而您的最佳化專案只需進行一次指令碼要求。

如果您想包裝您的建置檔案,以便可以在沒有 AMD 載入器(例如 RequireJS)的頁面中使用,請參閱最佳化常見問題集

快速開發的淺層排除§ 6

您可以使用單一 JavaScript 檔案最佳化方法來加快您的開發體驗。透過將專案中的所有模組最佳化到一個檔案中(目前正在開發的模組除外),您可以在瀏覽器中快速重新載入專案,但仍提供您在模組中進行細緻除錯的選項。

您可以透過使用excludeShallow選項來執行此操作。使用上述範例設定,假設您目前正在建置或除錯 two.js。您可以使用此最佳化指令

node ../../r.js -o name=main excludeShallow=two out=main-built.js baseUrl=.

如果您不希望壓縮 main-build.js 檔案,請在上述指令中傳遞optimize=none

然後,將 HTML 頁面設定為載入 main-built.js 檔案,而不是 main.js,方法是將用於「main」的路徑設定為「main-built」

<!DOCTYPE html>
<html>
    <head>
        <title>My App</title>
        <link rel="stylesheet" type="text/css" href="css/main.css">
        <script src="scripts/require.js"></script>
        <script>
            require.config({
                paths: {
                    //Comment out this line to go back to loading
                    //the non-optimized main.js source file.
                    "main": "main-built"
                }
            });
            require(["main"]);
        </script>
    </head>
    <body>
        <h1>My App</h1>
    </body>
</html>

現在,當載入此頁面時,「main」的 require() 會載入 main-built.js 檔案。由於 excludeShallow 告訴它只排除 two.js,因此 two.js 仍會作為一個獨立檔案載入,讓您可以在瀏覽器的除錯程式中將它視為一個獨立檔案,以便您可以設定中斷點並更好地追蹤它的個別變更。

empty:網路/CDN 資源路徑§ 7

您可能有一個指令碼,您想從內容傳遞網路 (CDN)或不同網域上的任何其他伺服器載入。

最佳化器無法載入網路資源,因此如果您希望將它包含在建置中,請務必建立路徑設定,將檔案對應到模組名稱。然後,在執行最佳化器時,下載 CDN 指令碼,並將路徑設定傳遞給最佳化器,將模組名稱對應到本機檔案路徑。

然而,您很可能不希望將該資源包含在建置中。如果腳本沒有任何依賴項,或者您不想要包含其依賴項或將以其他方式包含它們,則可以使用路徑設定中的特殊「empty:」架構,在進行最佳化時略過該檔案。

在您的 main.js 檔案中,建立一個路徑設定,為腳本提供一個模組名稱。即使腳本未透過呼叫 define() 來定義模組,也可以執行此操作。路徑設定僅用於將簡短的模組/腳本 ID 對應到 URL。這允許您為最佳化使用不同的路徑設定。在 main.js 中

requirejs.config({
    paths: {
        'jquery': 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min'
    }
});

require(['jquery'], function ($) {
});

然後,在執行最佳化器時,對路徑設定使用「empty:」

node ../../r.js -o name=main out=main-built.js baseUrl=. paths.jquery=empty:

或者,在 建置設定檔

({
    baseUrl: ".",
    name: "main",
    out: "main-built.js",
    paths: {
        jquery: "empty:"
    }
})

最佳化一個 CSS 檔案§ 8

使用上述範例設定,如果您只想最佳化 main.css,您可以從 appdirectory/css 目錄中使用這個指令

node ../../r.js -o cssIn=main.css out=main-built.css

這將建立一個名為 appdirectory/css/main-build.css 的檔案,其中將包含 main.css 的內容,並適當地調整 url() 路徑,以及移除註解。

請參閱 最佳化一個 JavaScript 檔案 的注意事項,以避免在您的原始來源樹中儲存最佳化的檔案。這裡僅執行此操作以簡化範例。

注意:url() 路徑修正將始終修正相對於 cssIn 建置選項路徑的路徑,而不是 out 建置選項。

最佳化整個專案§ 9

最佳化器可以使用建置設定檔來處理最佳化專案中所有 CSS 和 JS 檔案。

建立一個建置設定檔,將其命名為 app.build.js,並將其放在 scripts 目錄中。app.build.js 檔案可以放在任何地方,但請務必相應地調整以下範例中的路徑——所有路徑都將相對於 app.build.js 所在的位置。範例 app.build.js

({
    appDir: "../",
    baseUrl: "scripts",
    dir: "../../appdirectory-build",
    modules: [
        {
            name: "main"
        }
    ]
})

此建置設定檔告訴 RequireJS 將所有 appdirectory 複製到名為 appdirectory-build 的同層目錄,並套用 appdirectory-build 目錄中的所有最佳化。強烈建議您使用與來源目錄不同的輸出目錄——否則,由於最佳化器會覆寫您的來源,可能會發生不好的事情。

RequireJS 將使用 baseUrl 來解析任何模組名稱的路徑。baseUrl 應相對於 appDir

modules 陣列中,指定您想要最佳化的模組名稱,在範例中為「main」。「main」將對應到專案中的 appdirectory/scripts/main.js。然後,建置系統將追蹤 main.js 的依賴項,並將它們注入到 appdirectory-build/scripts/main.js 檔案中。

它也會最佳化在 appdirectory-build 中找到的任何 CSS 檔案。

若要執行建置,請在 appdirectory/scripts 目錄中執行此命令

node ../../r.js -o app.build.js

建置完成後,您可以將 appdirectory-build 用作已最佳化的專案,準備部署。

最佳化多頁面專案§ 10

requirejs/example-multipage 是多頁面專案的範例,但共用一個常見的組態和一個常見的最佳化建置層。

Turbo 選項§ 11

最佳化器的預設值是執行最安全、最穩健的動作組合,以避免建置後出現意外狀況。不過,視您的專案設定而定,您可能想要關閉其中一些功能,以取得更快速的建置

  • 最耗時的動作是縮小化。如果您只是將建置當作開發工作流程的一部分,請將 optimize 設定為 "none"
  • 如果要執行整個專案最佳化,但只想要縮小化 modules 選項中指定的建置層,而不縮小建置輸出目錄中的其他 JS 檔案,您可以將 skipDirOptimize 設定為 true
  • 通常,每次執行整個專案最佳化時,都會刪除 dir 指定的輸出建置目錄,以保持乾淨。有些建置選項,例如 onBuildWrite,會以一種方式修改輸出目錄,這對於在同一個檔案上執行兩次來說是有害的。不過,如果您執行的是單純的建置,沒有除了建置層縮小化以外的其他額外檔案轉換,您可以將 keepBuildDir 設定為 true,以在執行之間保留建置目錄。然後,只有在建置執行之間變更的檔案才會被複製。

在版本 2.1.2 中,如果 optimize 設定為 "none",最佳化器會採取一些預設的加速捷徑。不過,如果您將 optimize 設定為 "none",而且您計畫在最佳化器執行後縮小化建置的檔案,您應該將 normalizeDirDefines 設定為 "all",以便正確正規化 define() 呼叫,以承受縮小化。如果您透過 optimize 選項執行縮小化,您就不用擔心設定這個選項。

與 has.js 整合§ 12

has.js 是個很棒的工具,可以為您的專案新增簡易的功能偵測。有些最佳化器支援最佳化 has.js 測試的程式碼路徑。

如果您的程式碼使用類似下列的測試


if (has("someThing")) {
    //use native someThing
} else {
    //do some workaround
}

您可以在建置設定中定義一個 has 物件,其中包含一些 has() 測試的 true 或 false 值,而最佳化器會將 has() 測試取代為 true 或 false 值。

如果您的建置設定檔看起來像這樣


({
    baseUrl: ".",
    name: "hasTestModule",
    out: "builds/hasTestModule.js",
    has: {
        someThing: true
    }
})

那麼最佳化程式會將上述程式碼範例轉換成


if (true) {
    //use native someThing
} else {
    //do some workaround
}

然後,如果您使用 r.js 0.26.0 或更新版本的預設最佳化設定「uglify」,或者將最佳化設定設為「closure」(在 Java 下執行時),縮小程式會最佳化無效的程式碼分支!因此,您可以對程式碼進行自訂建置,針對一組 has() 測試進行最佳化。

原始碼對應§ 13

2.1.6 及更新版本具有對 原始碼對應 的實驗性支援。它適用於將縮小的捆綁程式碼對應到未縮小的獨立模組,而且僅在將最佳化設為 "uglify2" 時才適用。將最佳化設為 "closure" 時,只允許將縮小的捆綁程式碼對應到未縮小的捆綁程式碼(closure 僅在使用 Rhino 在 Java 下執行時可用)。未縮小的檔案會以「.src.js」檔案副檔名顯示在開發人員工具中。

若要啟用原始碼對應產生,請將產生原始碼對應設為 true。由於縮小程式需要完全控制縮小的檔案才能產生原始碼對應,因此應將保留授權註解明確設為 false不過,有一種方法可以在縮小的原始碼中取得一些授權註解

最佳化程式已支援 原始碼網址(透過將使用原始碼網址設為 true),用於將合併的模組偵錯為個別檔案。不過,這只適用於未縮小的程式碼。原始碼對應會將縮小的檔案轉譯成未縮小的版本。由於 useSourceUrl 需要原始碼值為字串,因此會禁止與 generateSourceMaps 結合進行有用的縮小,所以不適合將 useSourceUrl 與 generateSourceMaps 一起使用。

所有組態選項§ 14

requirejs/build 目錄中有一個 example.build.js 檔案,其中詳細說明所有允許的最佳化組態選項。

部署技術§ 15

r.js 最佳化程式旨在提供一些基本元件,可透過在這些元件上新增其他程式碼,用於不同的部署情境。請參閱 部署技術 wiki 頁面,了解如何以這種方式使用最佳化程式。

常見陷阱§ 16

如果您在使用以下範例時遇到問題,以下是可能導致問題的一些常見陷阱

請勿將輸出目錄指定在 JavaScript 的原始碼區域內

例如,如果您的 baseUrl 是「js」,而您的建置輸出進入「js/build」,則在每次最佳化執行時,可能會產生額外的巢狀檔案,進而產生問題。此指導方針僅適用於非單一檔案最佳化。

避免使用位於 baseUrl 之外的最佳化名稱

例如,如果您的 baseUrl 是「js」,而您的最佳化目標

name: '../main'

最佳化可能會覆寫或將檔案置於輸出目錄之外。對於這些情況,請建立一個 路徑 組態,將該檔案對應到一個本機名稱,例如

paths: {
    main: '../main'
}

然後使用名稱

name: 'main'

作為最佳化目標。

請注意 shim 組態的建置限制。特別是,您無法從 CDN 載入 shimmed 函式庫的相依項。請參閱 shim 組態區段 以取得更多資訊。