跳到主要內容
+

最小化套件大小

了解更多關於您可以利用哪些工具來減少套件大小。

套件大小很重要

Material UI 的維護者非常重視套件大小。每次提交都會針對每個套件和這些套件的關鍵部分進行大小快照。結合 dangerJS,我們可以檢查每個 Pull Request 上的詳細套件大小變更

何時以及如何使用 tree shaking?

Tree shaking Material UI 在現代框架中開箱即用。Material UI 在頂層 @mui 引入中公開其完整的 API。如果您使用 ES6 模組和支援 tree shaking 的打包工具 (webpack >= 2.x帶有 flag 的 parcel),您可以安全地使用具名引入,並且仍然可以自動獲得最佳化的套件大小

import { Button, TextField } from '@mui/material';

開發環境

開發套件可能包含完整的程式庫,這可能會導致啟動時間變慢。如果您從 @mui/icons-material 使用具名引入,這會特別明顯,這可能會比預設引入慢達六倍。例如,在以下兩個引入之間,第一個(具名)可能比第二個(預設)慢得多

// 🐌 Named
import { Delete } from '@mui/icons-material';
// 🚀 Default
import Delete from '@mui/icons-material/Delete';

如果這對您來說是個問題,您有兩個選項

選項一:使用路徑引入

您可以使用路徑引入來避免拉入未使用的模組。例如,使用

// 🚀 Fast
import Button from '@mui/material/Button';
import TextField from '@mui/material/TextField';

而不是頂層引入(沒有 Babel 外掛程式)

import { Button, TextField } from '@mui/material';

這是我們在所有範例中記錄的選項,因為它不需要任何設定。建議正在擴展組件的程式庫作者使用此選項。前往選項 2 以了解產生最佳 DX 和 UX 的方法。

雖然以這種方式直接引入不會使用 @mui/material 的主檔案中的導出,但此檔案可以作為方便的參考,了解哪些模組是公開的。

請注意,我們僅支援第一層和第二層引入。任何更深層次的引入都被視為私有,並可能導致問題,例如套件中的模組重複。

// ✅ OK
import { Add as AddIcon } from '@mui/icons-material';
import { Tabs } from '@mui/material';
//                         ^^^^^^^^ 1st or top-level

// ✅ OK
import AddIcon from '@mui/icons-material/Add';
import Tabs from '@mui/material/Tabs';
//                              ^^^^ 2nd level

// ❌ NOT OK
import TabIndicator from '@mui/material/Tabs/TabIndicator';
//                                           ^^^^^^^^^^^^ 3rd level

如果您使用 ESLint,您可以使用 no-restricted-imports 規則捕獲有問題的引入。以下 .eslintrc 設定將突出顯示來自 @mui 套件的有問題引入

{
  "rules": {
    "no-restricted-imports": [
      "error",
      {
        "patterns": ["@mui/*/*/*"]
      }
    ]
  }
}

選項二:使用 Babel 外掛程式

此選項提供最佳的使用者體驗和開發者體驗,除非您使用Next.js 13.5 或更高版本,在這些版本中,此最佳化會透過 Next.js 中的 optimizePackageImports 選項自動應用。在這種情況下,使用 Babel 外掛程式是不必要的。

  • 使用者體驗 (UX):即使您的打包工具不支援,Babel 外掛程式也能啟用頂層 tree shaking。
  • 開發者體驗 (DX):Babel 外掛程式使開發模式下的啟動時間與選項 1 一樣快。
  • 開發者體驗 (DX):此語法減少了程式碼的重複,僅需要單次引入即可引入多個模組。總體而言,程式碼更易於閱讀,並且在引入新模組時,您不太可能犯錯。
import { Button, TextField } from '@mui/material';

但是,您需要正確應用以下步驟。

1. 設定 Babel

使用 babel-plugin-import 以及以下設定

yarn add -D babel-plugin-import

在您的專案根目錄中建立一個 .babelrc.js 檔案

const plugins = [
  [
    'babel-plugin-import',
    {
      libraryName: '@mui/material',
      libraryDirectory: '',
      camel2DashComponentName: false,
    },
    'core',
  ],
  [
    'babel-plugin-import',
    {
      libraryName: '@mui/icons-material',
      libraryDirectory: '',
      camel2DashComponentName: false,
    },
    'icons',
  ],
];

module.exports = { plugins };

如果您使用 Create React App,您將需要使用幾個專案,讓您可以使用 .babelrc 設定,而無需 eject。

yarn add -D react-app-rewired customize-cra

在根目錄中建立一個 config-overrides.js 檔案

/* config-overrides.js */
/* eslint-disable react-hooks/rules-of-hooks */
const { useBabelRc, override } = require('customize-cra');

module.exports = override(useBabelRc());

如果您願意,可以使用此設定,透過 config-overrides.js 而不是 .babelrc 來設定 babel-plugin-import

修改您的 package.json 命令

   "scripts": {
-    "start": "react-scripts start",
-    "build": "react-scripts build",
-    "test": "react-scripts test",
+    "start": "react-app-rewired start",
+    "build": "react-app-rewired build",
+    "test": "react-app-rewired test",
     "eject": "react-scripts eject"
  }

享受顯著更快的啟動時間。

2. 轉換您的所有引入

最後,您可以使用此 top-level-imports codemod 將您現有的程式碼庫轉換為此選項。它將執行以下差異

-import Button from '@mui/material/Button';
-import TextField from '@mui/material/TextField';
+import { Button, TextField } from '@mui/material';

可用的套件

預設套件

在 npm 上發布的套件使用 Babel 進行轉譯,並針對支援的平台進行效能最佳化。

現代化套件也可用。

如何使用自訂套件?

使用這些套件的好方法是設定打包工具導出條件,例如使用 webpack 的 resolve.conditionNamesvite 的 resolve.conditions

// webpack.config.js
{
  resolve: {
    conditionNames: ['mui-modern', '...'],
  }
}

// vite.config.js
{
  resolve: {
    conditions: ['mui-modern', 'module', 'browser', 'development|production']
  }
}