Minimizing Bundle Size 最小化打包文件大小
了解有关可用于减少打包文件大小的工具的详细信息。
打包文件的大小是很重要的
Material-UI 的打包文件大小至关重要。 Size snapshots are taken on every commit for every package and critical parts of those packages (view the latest snapshot). 结合 dangerJS 一起,我们可以在每个 Pull Request 中都可以查看详细的打包文件的大小变化 。
When and how to use tree-shaking?
Tree-shaking of Material-UI works out of the box in modern frameworks. Material-UI exposes its full API on the top-level material-ui
import. If you're using ES6 modules and a bundler that supports tree-shaking (webpack
>= 2.x, parcel
with a flag) you can safely use named imports and still get an optimised bundle size automatically:
import { Button, TextField } from '@material-ui/core';
⚠️ The following instructions are only needed if you want to optimize your development startup times or if you are using an older bundler that doesn't support tree-shaking.
Development environment
Development bundles can contain the full library which can lead to slower startup times. This is especially noticeable if you import from @material-ui/icons
. 加载时间会大约比那些从顶层 API 的命名导入方式慢六倍。
如果您觉得这样不妥,您还有以下几个选择:
选项1
您可以使用路径导入,这样可以避免导入用不到的模块。 For instance, use:
// 🚀 Fast
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
instead of top level imports (without a Babel plugin):
import { Button, TextField } from '@material-ui/core';
This is the option we document in all the demos, since it requires no configuration. It is encouraged for library authors extending the components. Head to Option 2 for the approach that yields the best DX and UX.
尽管这样直接导入并不会使用 @material-ui/core/index.js
中的导出模式,但是对于那些公开的模块来说,此文件仍可以作为一个方便的参考。
请注意,我们只支持第一级和第二级的导入。 Anything deeper is considered private and can cause issues, such as module duplication in your bundle.
// ✅ OK
import { Add as AddIcon } from '@material-ui/icons';
import { Tabs } from '@material-ui/core';
// ^^^^ 1st or top-level
// ✅ OK
import AddIcon from '@material-ui/icons/Add';
import Tabs from '@material-ui/core/Tabs';
// ^^^^ 2nd level
// ❌ NOT OK
import TabIndicator from '@material-ui/core/Tabs/TabIndicator';
// ^^^^^^^^^^^^ 3rd level
选项2
This option provides the best User Experience and Developer Experience:
- UX: The Babel plugin enables top level tree-shaking even if your bundler doesn't support it.
- DX: The Babel plugin makes startup time in dev mode as fast as Option 1.
- DX: This syntax reduces the duplication of code, requiring only a single import for multiple modules. Overall, the code is easier to read, and you are less likely to make a mistake when importing a new module.
import { Button, TextField } from '@material-ui/core';
However, you need to apply the two following steps correctly.
1。 Configure Babel
请在以下插件中选择一个:
babel-plugin-import with the following configuration:
yarn add -D babel-plugin-import
Create a
.babelrc.js
file in the root directory of your project:const plugins = [ [ 'babel-plugin-import', { 'libraryName': '@material-ui/core', // Use "'libraryDirectory': ''," if your bundler does not support ES modules 'libraryDirectory': 'esm', 'camel2DashComponentName': false }, 'core' ], [ 'babel-plugin-import', { 'libraryName': '@material-ui/icons', // Use "'libraryDirectory': ''," if your bundler does not support ES modules 'libraryDirectory': 'esm', 'camel2DashComponentName': false }, 'icons' ] ]; module.exports = {plugins};
babel-plugin-transform-imports with the following configuration:
yarn add -D babel-plugin-transform-imports
Create a
.babelrc.js
file in the root directory of your project:const plugins = [ [ 'babel-plugin-transform-imports', { '@material-ui/core': { // Use "transform: '@material-ui/core/${member}'," if your bundler does not support ES modules 'transform': '@material-ui/core/esm/${member}', 'preventFullImport': true }, '@material-ui/icons': { // Use "transform: '@material-ui/icons/${member}'," if your bundler does not support ES modules 'transform': '@material-ui/icons/esm/${member}', 'preventFullImport': true } } ] ]; module.exports = {plugins};
If you are using Create React App, you will need to use a couple of projects that let you use .babelrc
configuration, without ejecting.
yarn add -D react-app-rewired customize-cra
Create a config-overrides.js
file in the root directory:
/* config-overrides.js */
const { useBabelRc, override } = require('customize-cra')
module.exports = override(
useBabelRc()
);
If you wish, babel-plugin-import
can be configured through config-overrides.js
instead of .babelrc
by using this configuration.
Modify your package.json
start command:
"scripts": {
- "start": "react-scripts start"
+ "start": "react-app-rewired start"
}
Note: You may run into errors like these:
Module not found: Can't resolve '@material-ui/core/makeStyles' in '/your/project'
This is because @material-ui/styles
is re-exported through core
, but the full import is not allowed.
You have an import like this in your code:
import { makeStyles, createStyles } from '@material-ui/core';
The fix is simple, define the import separately:
import { makeStyles, createStyles } from '@material-ui/core/styles';
Enjoy significantly faster start times.
2。 Convert all your imports
Finally, you can convert your existing codebase to this option with this top-level-imports codemod. It will perform the following diffs:
-import Button from '@material-ui/core/Button';
-import TextField from '@material-ui/core/TextField';
+import { Button, TextField } from '@material-ui/core';
ECMAScript
考虑到一些支持的平台,在 npm 上发布的包是和 Babel 一起被编译的。
A second version of the components is also published, which you can find under the /es
folder. 所有非官方的语义都被编译成ECMA-262 的标准,仅此而已。 这样一来,针对不同的浏览器,您可以编译出不同的打包文件。 一些旧的浏览器需编译一些 JavaScript 的功能,这样会增加打包文件的大小。 ES2015 运行的时候的功能中不包含垫片。 IE11+ 和一些长青浏览器会支持所有必要的功能。 如果您需要支持其他浏览器,请考虑使用 @ babel/polyfill
。
⚠️ In order to minimize duplication of code in users' bundles, library authors are strongly discouraged from using the /es
folder.