-
React代码分割 基于路由的代码分割 组件懒加载
2019-07-29 10:00:23大多数 React 应用都会使用Webpack或Browserify这类的构建工具来打包文件。打包是一个将文件引入并合并到一个单独文件的过程,最终形成一个 “bundle”。接着在页面上引入该 bundle,整个应用即可一次性加载。 示例...打包
大多数 React 应用都会使用 Webpack 或 Browserify 这类的构建工具来打包文件。打包是一个将文件引入并合并到一个单独文件的过程,最终形成一个 “bundle”。接着在页面上引入该 bundle,整个应用即可一次性加载。
示例
App文件:
// 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
注意:
最终你的打包文件看起来会和上面的例子区别很大。
如果你正在使用 Create React App,Next.js,Gatsby,或者类似的工具,你会拥有一个可以直接使用的 Webpack 配置来进行打包工作。
如果你没有使用这类工具,你就需要自己来进行配置。例如,查看 Webpack 文档上的安装和入门教程。
代码分割
打包是个非常棒的技术,但随着你的应用增长,你的代码包也将随之增长。尤其是在整合了体积巨大的第三方库的情况下。你需要关注你代码包中所包含的代码,以避免因体积过大而导致加载时间过长。
为了避免搞出大体积的代码包,在前期就思考该问题并对代码包进行分割是个不错的选择。代码分割是由诸如 Webpack(代码分割)和 Browserify(factor-bundle)这类打包器支持的一项技术,能够创建多个包并在运行时动态加载。
对你的应用进行代码分割能够帮助你“懒加载”当前用户所需要的内容,能够显著地提高你的应用性能。尽管并没有减少应用整体的代码体积,但你可以避免加载用户永远不需要的代码,并在初始加载的时候减少所需加载的代码量。
import()
在你的应用中引入代码分割的最佳方式是通过动态
import()
语法。使用之前:
import { add } from './math'; console.log(add(16, 26));
使用之后:
import("./math").then(math => { console.log(math.add(16, 26)); });
注意:
动态
import()
语法目前只是一个 ECMAScript (JavaScript) 提案, 而不是正式的语法标准。预计在不远的将来就会被正式接受。当 Webpack 解析到该语法时,它会自动地开始进行代码分割。如果你使用 Create React App,该功能已配置好,你能立刻使用这个特性。Next.js 也已支持该特性而无需再配置。
如果你自己配置 Webpack,你可能要阅读下 Webpack 关于代码分割的指南。你的 Webpack 配置应该类似于此。
当使用 Babel 时,你要确保 Babel 能够解析动态 import 语法而不是将其进行转换。对于这一要求你需要 babel-plugin-syntax-dynamic-import 插件。
React.lazy
注意:
React.lazy
和 Suspense 技术还不支持服务端渲染。如果你想要在使用服务端渲染的应用中使用,我们推荐 Loadable Components 这个库。它有一个很棒的服务端渲染打包指南。React.lazy
函数能让你像渲染常规组件一样处理动态引入(的组件)。使用之前:
import OtherComponent from './OtherComponent'; function MyComponent() { return ( <div> <OtherComponent /> </div> ); }
使用之后:
const OtherComponent = React.lazy(() => import('./OtherComponent')); function MyComponent() { return ( <div> <OtherComponent /> </div> ); }
这个代码将会在渲染组件时,自动导入包含
OtherComponent
组件的包。React.lazy
接受一个函数,这个函数需要动态调用import()
。它必须返回一个Promise
,该 Promise 需要 resolve 一个defalut
export 的 React 组件。Suspense
如果在
MyComponent
渲染完成后,包含OtherComponent
的模块还没有被加载完成,我们可以使用加载指示器为此组件做优雅降级。这里我们使用Suspense
组件来解决。const OtherComponent = React.lazy(() => import('./OtherComponent')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> </div> ); }
fallback
属性接受任何在组件加载过程中你想展示的 React 元素。你可以将Suspense
组件置于懒加载组件之上的任何位置。你甚至可以用一个Suspense
组件包裹多个懒加载组件。const OtherComponent = React.lazy(() => import('./OtherComponent')); const AnotherComponent = React.lazy(() => import('./AnotherComponent')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <section> <OtherComponent /> <AnotherComponent /> </section> </Suspense> </div> ); }
异常捕获边界(Error boundaries)
如果模块加载失败(如网络问题),它会触发一个错误。你可以通过异常捕获边界(Error boundaries)技术来处理这些情况,以显示良好的用户体验并管理恢复事宜。
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> );
基于路由的代码分割
决定在哪引入代码分割需要一些技巧。你需要确保选择的位置能够均匀地分割代码包而不会影响用户体验。
一个不错的选择是从路由开始。大多数网络用户习惯于页面之间能有个加载切换过程。你也可以选择重新渲染整个页面,这样您的用户就不必在渲染的同时再和页面上的其他元素进行交互。
这里是一个例子,展示如何在你的应用中使用
React.lazy
和 React Router 这类的第三方库,来配置基于路由的代码分割。import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import React, { Suspense, lazy } from 'react'; 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> );
命名导出(Named Exports)
React.lazy
目前只支持默认导出(default exports)。如果你想被引入的模块使用命名导出(named exports),你可以创建一个中间模块,来重新导出为默认模块。这能保证 tree shaking 不会出错,并且不必引入不需要的组件。// 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"));
-
React 代码分割 & loading 页面的实现
2020-06-02 15:24:43React.lazy 和 Suspense const Component = React.lazy(() => import('./Component)); React.lazy函数可以实现动态引入组件,它...在路由进行代码分割 原先页面加载时,默认会把路由上的所有组件一起加载过来(比如React.lazy 和 Suspense
const Component = React.lazy(() => import('./Component));
React.lazy函数可以实现动态引入组件,它会在组件首次渲染时,自动导入Component。
渲染lazy组件需要借助Suspense组件,它有一个fallback属性,可以传入在加载过程中想要展示的元素。
Suspence可以放置在懒加载组件之上的任何位置。
在路由进行代码分割
原先页面加载时,默认会把路由上的所有组件一起加载过来(比如Home、Detail、Login等页面),虽然这样能够让
页面切换时间变短,但会严重影响首屏的加载时间,因此有必要对路由中的组件进行代码分割,实现懒加载:import React, { Suspense, lazy } from 'react'; //懒加载 const Header = lazy(()=>import('./common/header')); const Detail = lazy(()=>import('./pages/detail')); const Login = lazy(()=>import('./pages/login')); const Register = lazy(()=>import('./pages/register')); const Footer = lazy(()=>import('./common/footer'));
<BrowserRouter> <Suspense fallback={<div>loading...</div>}> <Route path={["/detail/:id", "/"]} exact component={Header}/> <Route path='/' exact component={Home}/> <Route path='/detail/:id' component={Detail}/> <Route path='/login' component={Login}/> <Route path='/register' component={Register}/> <Route path={["/detail/:id", "/"]} exact component={Footer}/> </Suspense> </BrowserRouter>
如此编写后,我们发现页面在加载和切换时会加载fallback中的loading,切换所需时间明显延长,但用户是可以接受的。
loading 美化
<Suspense fallback={<Loading><Spin size="large" /></Loading>}>
其中Spin是AntD引入的组件,Loading则封装了容器的样式(Styled-Component):
export const Loading = styled.div` width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; `;
这样我们就可以实现一个在屏幕中央的loading效果。
-
react 代码分割 export && export default
2020-08-03 11:29:51代码分割 其实就是为了避免打包时候的代码体积过大而导致加载时间过长出现的一种优化手段吧.简单来说也就是引入并使用外部js文件的方法,使用代码分割有两种写法,推荐第二种. 第一种:我在math.js里面export了一个add...代码分割
其实就是为了避免打包时候的代码体积过大而导致加载时间过长出现的一种优化手段吧.简单来说也就是引入并使用外部js文件的方法,使用代码分割有两种写法,推荐第二种.
第一种使用方式,调用import():
// 前提:我在math.js里面export了一个add函数 import("./math.js").then(math => { console.log(math.add(1, 2)) // 3 });
第二种使用方式,头部引入文件:
import { add } from './math'; //使用如下: console.log(add(12, 12)) //24
这里踩到了一个坑,在math.js中导出函数时我写了export default,在外部调用的时候报错:math.add is not a function.
这就涉及到一个问题:export 和export default的区别
export:导出 ,在一个js文件里面可以多次使用,且可以导出多个函数,如:export {add,minus…}export default:在一个js里面只能使用一次,就只能导出一个默认函数
导出方式不一样,引入方式也不一样:(不可混用!!!)
export default: import minus from './math.js' // minus 可以自己修改命名 export: import {add} from './math.js'; // add是js内部的函数名称,不可修改
前者minus可以按照自己的意愿随便命名使用(不建议这么干),而后者花括号里面的内容必须要是引入文件内部存在的变量,名称不能随意改变 比如 里面存在的add函数;
使用export default 导出的函数,在import()中第一种使用方式为:
第二种使用方式(推荐):import minus, { add } from './math'; // 使用 console.log(add(12, 12)); console.log(minus(8, 6))
-
React 3.2代码分割
2020-05-10 22:22:18打包 大多数 React 应用都会使用 Webpack,Rollup 或 ...应用中引入代码分割的最佳方式是通过动态 import() 语法。 使用前: import { add } from './math'; console.log(add(16, 26)); 使用后: import("./math")打包
大多数 React 应用都会使用 Webpack,Rollup 或 Browserify 这类的构建工具来打包文件。 打包是一个将文件引入并合并到一个单独文件的过程,最终形成一个 “bundle”。 接着在页面上引入该 bundle,整个应用即可一次性加载
import
应用中引入代码分割的最佳方式是通过动态 import() 语法。
使用前:import { add } from './math'; console.log(add(16, 26));
使用后:
import("./math").then(math => { console.log(math.add(16, 26)); });
Webpack 解析到该语法时,会自动进行代码分割。
React.lazy
React.lazy 函数能让你像渲染常规组件一样处理动态引入(的组件)。
使用前:import OtherComponent from './OtherComponent';
使用后:
const OtherComponent = React.lazy(() => import('./OtherComponent'));
此代码将会在组件首次渲染时,自动导入包含
OtherComponent
组件的包。
React.lazy
接受一个函数,这个函数需要动态调用import()
。它必须返回一个Promise
,该Promise
需要resolve
一个defalut export
的 React 组件
然后应在Suspense
组件中渲染lazy
组件,如此使得我们可以使用在等待加载 lazy 组件时做优雅降级(如 loading 指示器等)import React, { Suspense } from 'react'; const OtherComponent = React.lazy(() => import('./OtherComponent')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> </div> ); }
基于路由的代码分割
如果说上边的例子是
React
和React组件的结合,那么这个就是通过React
和React Router
的结合
示例: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> );
-
react-代码分割作为一个组件
2019-08-14 22:45:22代码分割作为一个组件 -
react实战之代码分割
2021-02-21 16:27:36代码分割是由诸如Webpack,Rollup和 Browserify(factor-bundle)这类打包器支持的一项技术,能够创建多个包并在运行时动态加载。 对你的应用进行代码分割能够帮助你“懒加载”当前用户所需要的... -
React中的代码分割
2019-09-29 23:04:22代码分割想要解决的问题是:经打包工具????生成的bundle文件过大,特别是在我们引入第三方库的情况下。 在React中,我们有一下几种解决方案: 1. 动态加载 1 // math.js 2 exp... -
React Router之代码分割
2021-01-16 22:49:24您可以将代码拆分视为增量下载应用程序。要做到这一点,我们将使用的WebPack,@babel/plugin-syntax-dynamic-import和loadable-components。 webpack内置了对动态导入的支持;但是,如果您使用Babel(例如,将JSX... -
react 实现页面代码分割、按需加载的方法
2020-08-27 18:20:30本篇文章主要介绍了react 实现页面代码分割、按需加载的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 -
React高级指引:代码分割
2019-10-24 10:49:04代码分割打包 上一节:无障碍 下一节:Context 打包 -
React性能优化之代码分割
2019-05-16 10:20:35代码分割从两方面来讲:React Lazy 和 webpack两方面 每次单页应用打包出的文件又臭又长,是最蛋疼的事,浏览器刷个半天才出来网页让人恨不得找个地洞钻进去,这种事很尴尬,让人怀疑你这前端不专业 所以正题来了,... -
使用react-loadable实现代码分割
2020-03-01 22:10:19开发react单页应用的时候,我们打包后的代码会非常大,这会影响首页应用的加载速度,拉低用户体验,所以在开发工程中应该使用react-loadable来进行代码分割,将单个js文件切割成多个chunk.js,这样实现了代码的按需... -
react如何实现代码分割,路由动态加载
2018-05-30 10:26:48众所周知,在使用webpack打包...于是,webpack开发了代码分割的特性, 此特性能够把代码分割为不同的bundle文件,然后可以通过路由按需加载或并行加载这些文件。 代码分割可以用于获取更小的bundle,以及控制资源... -
React.js 实现页面代码分割、按需加载 —— react-loadable 实现路由代码分割
2018-12-21 14:44:31最近在学习react,之前做的一个项目首屏加载速度很慢,便搜集了一些优化方法,react-loadable这个库是我在研究路由组件按需加载的过程中发现的。 import() 是es6的一种异步加载的方法。 npm i react-loadable --... -
react 实现页面代码分割、按需加载
2018-04-03 10:50:25虽然一直有做 react 相关的优化,按需加载、dll 分离、服务端渲染,但是从来没有从路由代码分割这一块入手过,昨天在本地开发时没有测试成功,今天又搞了下,已经部署到线上环境了,今天就这个记录一下。 修改配置 ... -
使用webpack和react router 4实现代码分割
2019-09-11 21:13:24写在前面 众所周知,在使用webpack打包react应用时,webpack将整个应用打包成一个js文件,当用户访问首屏时,会一次性加载整个js文件,当应用...于是,webpack开发了代码分割的特性, 此特性能够把代码分割为不同的... -
React配合Webpack实现代码分割与异步加载
2017-05-21 21:29:00这是Webpack+React系列配置过程记录的第四篇。其他内容请参考: 第一篇:使用webpack、babel、react、antdesign配置单页面应用开发...第四篇:React配合Webpack实现代码分割与异步加载 自从前几篇文章介绍如何...