大多数 React 应用都会使用 Webpack,Rollup 或 Browserify 这类的构建工具来打包文件。打包是一个将文件引入并合并到一个单独文件的过程,最终形成一个 “bundle”。接着在页面上引入该 bundle,整个应用即可一次性加载。
// app.js import { add } from './math.js'; console.log(add(16, 26)); // 42 // math.js export function add(a, b) { return a + b; } //打包后的文件 function add(a, b) { return a + b; } console.log(add(16, 26)); // 42
打包是个非常棒的技术,但随着你的应用增长,你的代码包也将随之增长。
尤其是在整合了体积巨大的第三方库的情况下。你需要关注你代码包中所包含的代码,以避免因体积过大而导致加载时间过长。
为了避免搞出大体积的代码包,在前期就思考该问题并对代码包进行分割是个不错的选择。
代码分割是由诸如 Webpack,Rollup 和 Browserify(factor-bundle)这类打包器支持的一项技术,能够创建多个包并在运行时动态加载。
对你的应用进行代码分割能够帮助你“懒加载”当前用户所需要的内容,能够显著地提高你的应用性能。
尽管并没有减少应用整体的代码体积,但你可以避免加载用户永远不需要的代码,并在初始加载的时候减少所需加载的代码量。
//使用前 import { add } from './math'; console.log(add(16, 26)); //使用后 import("./math").then(math => { console.log(math.add(16, 26)); });
当 Webpack 解析到该语法时,会自动进行代码分割。如果你使用 Create React App,该功能已开箱即用,
你可以立刻使用该特性。Next.js 也已支持该特性而无需进行配置。
如果你自己配置 Webpack,你可能要阅读下 Webpack 关于代码分割的指南。
你的 Webpack 配置应该类似于此。
当使用 Babel 时,你要确保 Babel 能够解析动态 import 语法而不是将其进行转换。对于这一要求你需要 @babel/plugin-syntax-dynamic-import 插件。
三、React.lazy()
//使用前 import OtherComponent from './OtherComponent'; //使用之后 const OtherComponent = React.lazy(() => import('./OtherComponent'));
import React, { Suspense } from 'react'; const OtherComponent = React.lazy(() => import('./OtherComponent')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> </div> ); }
Suspense
组件包裹多个懒加载组件。
import React, { Suspense } from 'react'; const OtherComponent = React.lazy(() => import('./OtherComponent')); const AntherComponent = React.lazy(() => import('./AntherComponent')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> <AntherComponent /> </Suspense> </div> ); }
import React, { Suspense } from 'react'; import MyErrorBoundary from './MyErrorBoundary'; const OtherComponent = React.lazy(() => import('./OtherComponent')); const AnotherComponent = React.lazy(() => import('./AnotherComponent')); const MyComponent = () => ( <div> <MyErrorBoundary> <Suspense fallback={<div>Loading...</div>}> <section> <OtherComponent /> <AnotherComponent /> </section> </Suspense> </MyErrorBoundary> </div> );
import React, { Suspense, lazy } from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; const Home = lazy(() => import('./routes/Home')); const About = lazy(() => import('./routes/About')); const App = () => ( <Router> <Suspense fallback={<div>Loading...</div>}> <Switch> <Route exact path="/" component={Home}/> <Route path="/about" component={About}/> </Switch> </Suspense> </Router> );
// ManyComponents.js export const MyComponent = /* ... */; export const MyUnusedComponent = /* ... */; // MyComponent.js export { MyComponent as default } from "./ManyComponents.js"; // MyApp.js import React, { lazy } from 'react'; const MyComponent = lazy(() => import("./MyComponent.js"));