發布、提供及安裝新式 JavaScript,加快應用程式速度

開啟新型 JavaScript 依附元件和輸出內容,藉此提升效能。

超過 90% 的瀏覽器能執行新式 JavaScript,但 舊版 JavaScript 的盛行仍是效能問題的一大來源 上網

新版 JavaScript

現代 JavaScript 並非以特定 ECMAScript 編寫的程式碼 而是所有新型系統支援的語法 。Chrome、Edge、Firefox 和 Safari 等新式網路瀏覽器 超過90% 的瀏覽器市場,而 不同的瀏覽器採用相同的基礎轉譯引擎 額外增加 5%換句話說,95% 的全球網路流量來自瀏覽器 支援過去 10 種最常使用的 JavaScript 語言功能 年份,包含:

  • 類別 (ES2015)
  • 箭頭函式 (ES2015)
  • 發電機 (ES2015)
  • 區塊範圍設定 (ES2015)
  • 解構 (ES2015)
  • 休息及分散參數 (ES2015)
  • 簡寫物件 (ES2015)
  • 非同步/await (ES2017)

較新版本的語言規格中的功能一般較少 以一致的方式支援各種新式瀏覽器例如許多 ES2020 和 ES2021 功能也受到瀏覽器市場的 70% 支援,至今仍為多數 不過,直接依賴這些功能還不夠安全這個 意思是「現代風格」JavaScript 是持續變動的目標,ES2017 則是 與瀏覽器相容 同時包含最常用的現代語法功能。 換句話說,ES2017 是現今最接近現代語法的頁面

舊版 JavaScript

舊版 JavaScript 是特別避免使用上述所有語言的程式碼 接著介紹網際網路通訊層 包括兩項主要的安全防護功能大多數開發人員都使用新型語法編寫原始碼,但 將所有內容編譯為舊版語法,以提升瀏覽器支援程度。編譯 舊版語法確實能增加瀏覽器的支援性,不過效果通常 遠大於我們的預期在多數情況下 用量大幅提高至 98%,但成本卻高昂:

  • 舊版 JavaScript 的大小通常比舊版 JavaScript 大上 20% 左右 提供對等的新式程式碼工具常有缺陷和設定錯誤 又能拉近彼此的距離

  • 在一般正式版環境中,已安裝的程式庫佔了 90% 的比例 JavaScript 程式碼。程式庫程式碼產生的舊版 JavaScript 更高 造成的負擔 發布新式程式碼

npm 上的新型 JavaScript

Node.js 最近已將 "exports" 欄位標準化 包裹的進入點

{
  "exports": "./index.js"
}

"exports" 欄位參照的模組隱含節點版本至少為 12.8,支援 ES2019。也就是說,凡是使用 "exports" 欄位可以新型 JavaScript 編寫。套件取用者必須 假設含有 "exports" 欄位的模組包含新式程式碼,並會進行轉譯 ( 無從得知

僅現代

如想發布包含現代化程式碼的套件,並留在 而將轉譯器做為依附元件使用時,使用者只能處理轉譯作業 - 只需使用 「"exports"」欄位。

{
  "name": "foo",
  "exports": "./modern.js"
}

以舊版備用方案取代現代設定

使用 "exports" 欄位和 "main" 來發布套件 使用新型程式碼,並納入適用於舊版程式碼的 ES5 + CommonJS 備用方案 。

{
  "name": "foo",
  "exports": "./modern.js",
  "main": "./legacy.cjs"
}

以舊版備用廣告和 ESM 套裝組合最佳化的方式進行現代化

除了定義備用 CommonJS 進入點之外,"module" 欄位還可以 用於指向類似的舊版備用套件,但使用 JavaScript 模組語法 (importexport)。

{
  "name": "foo",
  "exports": "./modern.js",
  "main": "./legacy.cjs",
  "module": "./module.js"
}

許多套裝組合工具 (例如 webpack 和 Rollup) 仰賴這個欄位,才能充分利用 並啟用模組功能 樹木搖動。 這仍是舊版套件,除了內含任何現代程式碼外, import/export 語法,因此請使用這個方法來發布具有 且仍處於最佳化狀態的舊版備用方案。

在應用程式中使用新型 JavaScript

絕大多數的一般實際工作環境中,大多是由第三方依附元件構成 JavaScript 程式碼。雖然 npm 依附元件一直以來都有 已發布為舊版 ES5 語法,不再是安全的假設, 風險依附更新導致應用程式的瀏覽器支援中斷。

隨著 npm 套件數量與日俱增,改用新型 JavaScript 請務必確保建構工具設定妥當來處理這些物件還有 很可能已採用的某些 npm 套件已採用新式版本 語言功能。使用新型程式碼的方式有很多種 而不在舊版瀏覽器中中斷應用程式,但 概念在於讓建構系統將依附元件轉譯成相同的語法 做為原始碼

Webpack

從 webpack 5 開始,現在可以設定 Webpack 要使用的語法 可大幅提高套件和模組程式碼的效率。這不會 程式碼或依附元件時,只會影響「glue」Webpack 產生的程式碼 如要指定瀏覽器支援目標,請加入 瀏覽器清單設定 新增至專案中,或是直接在 Webpack 設定中執行這項操作:

module.exports = {
  target: ['web', 'es2017'],
};

您也可以設定 Webpack 產生最佳化套裝組合, 指定現代 ES 模組時,省略不必要的包裝函式 環境。這也會將 webpack 設定為使用 <script type="module">

module.exports = {
  target: ['web', 'es2017'],
  output: {
    module: true,
  },
  experiments: {
    outputModule: true,
  },
};

有許多 Webpack 外掛程式 編譯及提供新型 JavaScript,同時仍支援舊版瀏覽器。 例如最佳化工具外掛程式和 BabelEsmPlugin

最佳化工具外掛程式

最佳化工具外掛程式是一種 Webpack 這個外掛程式能將最終封裝程式碼從現代 JavaScript 轉換為舊版 JavaScript 而非個別的來源檔案AI 是獨立的設定 您的 webpack 設定假設一切都是現代 JavaScript 適用於多種輸出或語法的特殊分支

最佳化工具外掛程式是在套件中運作,而非個別模組 平均處理應用程式的程式碼和依附元件。如此一來 能安全使用新型 JavaScript 依附元件,因為其程式碼會 組合並轉譯成正確的語法執行特定作業 包含兩個編譯步驟的傳統解決方案 新式和舊版瀏覽器的套件。這兩組套裝組合 是以使用 module/nomodulePattern (模組/無模組模式)。

// webpack.config.js
const OptimizePlugin = require('optimize-plugin');

module.exports = {
  // ...
  plugins: [new OptimizePlugin()],
};

與自訂 Webpack 相比,Optimize Plugin 的運作速度更快,效率更高 設定,後者通常會分開組合新式和舊版程式碼。這項服務 也可以代替您執行 Babel 使用 Terser 搭配個別最佳化設定的套裝組合 新式和舊版輸出內容最後,由生成式 AI 產生 舊版套件擷取到專屬指令碼中,因此一律不會 。

比較:對來源模組進行兩次轉譯與轉碼產生的套件。

BabelEsmPlugin

BabelEsmPlugin 是 Webpack 可搭配 @babel/preset-env 以產生現有套件的現代化版本,以減少轉移的程式碼至 新式瀏覽器。是 Google 最受歡迎的現成解決方案, 模組/nomodule,由 Next.jsPreact CLI)。

// webpack.config.js
const BabelEsmPlugin = require('babel-esm-plugin');

module.exports = {
  //...
  module: {
    rules: [
      // your existing babel-loader configuration:
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
  plugins: [new BabelEsmPlugin()],
};

BabelEsmPlugin 支援多種 Webpack 設定,因為 可以執行兩個大部分獨立的應用程式版本編譯兩次可能會需要 對大型應用程式而言,額外時間會比較多,但這項技術允許 BabelEsmPlugin,可完美整合至現有的 Webpack 設定 使其成為最便利的選擇

將 babel-loader 設為 transpile node_modules

如果您使用 babel-loader,而沒有前兩個外掛程式, 如要使用新版 JavaScript npm,必須完成一個重要步驟 模組。定義兩個獨立的 babel-loader 設定即可 ,自動編譯 node_modules 中的現代語言功能, ES2017,同時在 Babel 中轉譯自己的第一方程式碼 專案設定中定義的外掛程式和預設設定這並不 產生模組/非模組設定的新舊版套件,但實際上 讓您能安裝並使用包含新式 JavaScript 的 npm 套件 而不破壞舊版瀏覽器

webpack-plugin-modern-npm 使用這項技術編譯含有 "exports" 欄位的 npm 依附元件 package.json,因為該檔案可能包含現代語法:

// webpack.config.js
const ModernNpmPlugin = require('webpack-plugin-modern-npm');

module.exports = {
  plugins: [
    // auto-transpile modern stuff found in node_modules
    new ModernNpmPlugin(),
  ],
};

或者,您也可以在 webpack 中手動導入這項技術 方法是檢查 package.json"exports" 欄位 都會影響這些模組的運作為求簡潔,省略快取 導入過程可能會像這樣:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      // Transpile for your own first-party code:
      {
        test: /\.js$/i,
        loader: 'babel-loader',
        exclude: /node_modules/,
      },
      // Transpile modern dependencies:
      {
        test: /\.js$/i,
        include(file) {
          let dir = file.match(/^.*[/\\]node_modules[/\\](@.*?[/\\])?.*?[/\\]/);
          try {
            return dir && !!require(dir[0] + 'package.json').exports;
          } catch (e) {}
        },
        use: {
          loader: 'babel-loader',
          options: {
            babelrc: false,
            configFile: false,
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
};

使用這個方法時,請務必確保 。Terser 與 和 uglify-es 可以選擇指定 {ecma: 2017},以便保留,在某些情況下 會在壓縮和格式化的過程中產生 ES2017 語法。

匯總

Rollup 內建支援功能,可產生多個套件組合 並依據預設產生現代化程式碼因此,匯總作業可 設為使用官方外掛程式產生新型和舊版套件 你應該已在使用這項工具

@rollup/plugin-babel

使用 Rollup 時 getBabelOutputPlugin() 方法 (由 Rollup 的 官方 Babel 外掛程式) 轉換產生的套件 (而非個別來源模組) 中的程式碼。 Rollup 內建支援功能,可產生多個套件組合 和每個版本都各自有自己的外掛程式您可以用這個方法 分別傳送不同的 Babel 輸出外掛程式設定:

// rollup.config.js
import {getBabelOutputPlugin} from '@rollup/plugin-babel';

export default {
  input: 'src/index.js',
  output: [
    // modern bundles:
    {
      format: 'es',
      plugins: [
        getBabelOutputPlugin({
          presets: [
            [
              '@babel/preset-env',
              {
                targets: {esmodules: true},
                bugfixes: true,
                loose: true,
              },
            ],
          ],
        }),
      ],
    },
    // legacy (ES5) bundles:
    {
      format: 'amd',
      entryFileNames: '[name].legacy.js',
      chunkFileNames: '[name]-[hash].legacy.js',
      plugins: [
        getBabelOutputPlugin({
          presets: ['@babel/preset-env'],
        }),
      ],
    },
  ],
};

其他建構工具

Rollup 和 webpack 可高度設定,這代表每個專案 必須更新其設定,啟用依附元件中的新型 JavaScript 語法。 您也可以使用較高層級的建構工具,改用慣例模式和預設值,而非 例如 ParcelSnowpackViteWMR。其中大多數的工具 假設 npm 依附元件可能包含現代語法,並會將其轉譯為 提供適當語法等級

除了 webpack 和 Rollup 專用的外掛程式外,新版 JavaScript 您可以透過 。演變是 獨立工具,能轉換建構系統的輸出內容,以產生舊版 JavaScript 變數,可進行組合及轉換以假設現代 輸出目標