webpack的code splitting和懒加载

两者的关系

原来一直以为 code splitting 了,就已经实现了懒加载了,但现在 react 又单独退出了懒加载功能,突然就迷茫了,webpack 已经实现懒加载了,为什么 react 还要单独实现这个功能呢?细心思考才明白两者之间的关系。


code splitting 实现了代码分割,就是不把所有的代码打包到一起,这只是解决了单个大文件加载慢的问题(因为浏览器现在可以同时多个线程下载文件),而不是懒加载的问题。


什么是懒加载?
懒加载就是没用到某个文件的时候,这文件不下载,用到的时候才下载加载,从而提高性能。

注意:懒加载时,如果文件没用到,连下载都不下载,而不是下载下来不加载。

而要实现懒加载,那首先各个文件是分开的,这就依赖 code splitting 功能,不然代码都在一个文件里,动态加载个屁。

react 懒加载

react 的懒加载,提供了 lazy 和 suspense,另外需要借助 js 的 import()“函数”(其实本质不是个函数)。

懒加载解决了页面首次加载的性能问题。

lazy

lazy 接收一个无参的函数,返回一个新的 react 组件

1
2
3
import React,{lazy} from 'react;

const About = lazy(() => import("./About"));

可以指定动态加载 chunk 的名字,通过在 import 里面加注释实现。

1
const About = lazy(() => import(/* webpackChunkName:"about" */ "./About"));

这在浏览器的 network 中,就可以看到 About 组件的 chunk 文件名叫about.chunk.js,如果不指定,则是 0.chunk.js 这样,用数字命名。

注意webpackChunkName:"about"两边要有空格,如果没有空格,也不报错,只是 chunk 文件中的代码以文本的方式显示,所有代码都是黑色的。带空格就会以代码的格式,字体有颜色。
另外注意 value 上的双引号。

Suspense

使用lazy必须使用Suspense组件,Suspensereact的一个内置组件。
suspense 是干什么的,因为 lazy 是动态加载,所以加载过程中会有一个空档期,Suspense 就是执行,这个空档期显示什么。
Suspense 的 fallback 属性执行了要显示的组件,fallback 接收的是一个组件的实例,而不是组件的类型(感觉一句废话)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React, { Component, lazy, Suspense } from "react";

const About = lazy(() => import("./About"));
export default class Main extends Component {
render() {
return (
<div>
<Suspense fallback={<div>loading,please wait……</div>}>
<About />
</Suspense>
</div>
);
}
}

错误处理

如果组件下载失败,会报错,Suspense 没有处理错误的能力。那错误如何处理呢?使用 ErrorBoundary(错误边界),其实就是利用了组件的componentDidCatch生命周期。
当 UI 渲染有错误时,就会触发 getDerivedStateFromError 和 componentDidCatch,可以在设置 state 的状态,然后根据 state 判断是否显示错误组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React, { Component, lazy, Suspense } from "react";

const About = lazy(() => import(/* webpackChunkName:"about" */ "./About"));
export default class Main extends Component {
state = {
hasError: false,
};
componentDidCatch(error) {
this.setState({ hasError: true });
}
render() {
const { hasError } = this.state;
if (hasError) {
return <h1>组件获取失败!</h1>;
}
return (
<div>
<Suspense fallback={<div>loading,please wait……</div>}>
<About />
</Suspense>
</div>
);
}
}

也可以使用getDerivedStateFromError返回一个新的 state 对象并合并到原来的 state 中。

1
2
3
4
5
6
7
static getDerivedStateFromError(error, info) {
// 更新 state 使下一次渲染能够显示降级后的 UI
return { hasError: true };
}
//componentDidCatch(error, info) {
//this.setState({ hasError: true });
//}

官方建议:当抛出错误后,请使用 static getDerivedStateFromError() 渲染备用 UI ,使用 componentDidCatch() 打印错误信息。
错误边界的介绍

文章作者: wenmu
文章链接: http://blog.wangpengpeng.site/2020/01/09/webpack%E7%9A%84code%20splitting%E5%92%8C%E6%87%92%E5%8A%A0%E8%BD%BD/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 温木的博客
微信打赏