背景
本文接上两篇:
「 面试三板斧 」之 代码分割(上)
「 面试三板斧 」之 代码分割(中)
在上两篇文章中, 我们了解了 splitChunks
三个字段的含义。
分析了每个字段对应的行为,最后了解了分包的原理
。
今天是实践篇。
看看如何修改短短几行配置, 就达到了数百毫秒的优化效果。
正文
我的这个项目, 迭代一年多了, 中间打包配置也没没怎么改过, 毕竟也没什么问题, 速度也还可以。
刚好最近要搞优化,就顺带看了看。
不分析不知道, 这一分析, 很快啊!
马上就看出了问题。
看包分析结果:
脑海里瞬间闪过一张图:
几乎所有的三方依赖都打在了一起, 写好的页面按路由加载也都打到了一起...
简直辣眼睛...
于是就去看了一下代码配置:
修正前
原始配置:
代码语言:javascript复制
const OnBoard = React.lazy(() => import('@/pages/onboard'));
const menuData = MenuItemTypes[] = [
{
title: 'onboard',
path: '/onboard',
meta: { showInMenu: false },
children: [
{
component: OnBoard,
// ...
},
// ...
]
},
// ...
];
代码语言:javascript复制const AppRouter = () => {
// ...
const { el, routes } = getRoutes(menuData);
// ...
return (
<BasicLayout {...matchedRoute.meta}>
<Suspense fallback={<Spin />}>
<Route path="/" exact component={MyDashboard} />
{el}
</Suspense>
// ...
</BasicLayout>
);
};
代码语言:javascript复制const App: React.FC<> = () => {
// ...
return <AppRouter />;
};
const AppContainer = () => (
<Router history={history}>
<Provider store={store}>
<Locale>
<App />
</Locale>
</Provider>
</Router>
);
看起来没什么问题。
看了一下 webpack 配置:
代码语言:javascript复制 optimization: {
splitChunks: {
chunks: 'all',
minSize: 30000,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
cacheGroups: {
vendor: {
test: /[\/]node_modules/,
enforce: true,
priority: 5,
},
antd: {
test: /[\/]node_modules[\/]antd[\/]/,
priority: 10,
},
antdIcons: {
test: /[\/]node_modules[\/]@ant-design[\/]/,
priority: 15,
},
styles: {
test: /.(scss|css)$/,
minChunks: 1,
reuseExistingChunk: true,
enforce: true,
priority: 20,
},
},
},
},
代码语言:javascript复制
看起来貌似也没什么问题。。。
build 之后 html 中的脚本, 乍一看好像也没毛病...
代码语言:javascript复制<script type="text/javascript" src="/main.75a8d9f8.js"></script>
<script type="text/javascript" src="/chunk.styles~main.eaa8f358.js"></script>
<script type="text/javascript" src="/chunk.antdIcons~main.6ee35491.js"></script>
<script type="text/javascript" src="/chunk.vendor~main.aa82abbc.js"></script>
<script type="text/javascript" src="/chunk.main.db1b67a1.js"></script>
这种情况下, 修改 chunks
配置的对比:
chunks: all
包分析:
加载时间以及入口文件初始加载的脚本文件:
chunks: async
:
代码语言:javascript复制 <script type="text/javascript" src="/main.64245819.js"></script>
<script type="text/javascript" src="/chunk.main.d6a
代码语言:javascript复制
几乎没有什么变化, 一时间, 开始怀疑是不是受了其他配置的影响。。。
就去仔细去找了一下, 果然:
啊这。。。。 我倒要看看是谁:
算了算了。。。
然后速度修改了配置。
修正后:
代码语言:javascript复制
optimization: {
runtimeChunk: {
name: 'manifest',
},
splitChunks: {
chunks: 'all',
minSize: 30000,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
cacheGroups: {
vendor: {
test: /[\/]node_modules/,
enforce: true,
priority: 5,
},
antd: {
test: /[\/]node_modules[\/]antd[\/]/,
priority: 15,
enforce: true,
},
antdIcons: {
test: /[\/]node_modules[\/]@ant-design[\/]/,
priority: 15,
enforce: true,
},
antdV: {
test: /[\/]node_modules[\/]@antv[\/]/,
priority: 30,
enforce: true,
},
bizcharts: {
test: /[\/]node_modules[\/]bizcharts[\/]/,
priority: 20,
enforce: true,
},
dplayer: {
test: /[\/]node_modules[\/]dplayer[\/]/,
priority: 25,
enforce: true,
},
styles: {
test: /.(scss|css|less})$/,
minChunks: 1,
reuseExistingChunk: true,
enforce: true,
priority: 20,
},
'react-dom': {
test: /[\/]node_modules[\/]react-dom[\/]/,
priority: 25,
enforce: true,
},
'rc-components': {
test: /([\/]node_modules[\/]rc-[a-zA-Z-] [\/])/,
priority: 25,
enforce: true,
},
},
},
},
代码语言:javascript复制
很快啊!
马上就有了效果:
chunks: async
入口文件初始加载的脚本:
除了入口脚本数量的变化, 总体积, 加载时长, 几乎没有变化。
脚本数量的不同:
all
: 8async
: 4
区别就是, 大文件的体积不同, 对这个大文件的加载时间有影响。
回头看, 这是一个 maxChunks
配置错误引发的血案。
修正配置之后, 立竿见影。
根据不同场景合理的拆分
根据你的情况, 可以选择更适合的打包策略。
all
的优势:
Providing
all
can be particularly powerful, because it means that chunks can be shared even between async and non-async chunks.
选择这个模式, 如果你用的协议是 h2 , 并行下载,可能有比较好的效果。
async
会帮你合并一些包,但产生的请求也会减少。
需要根据实际情况做测试, 选择最适合的打包策略。
还有一种分割策略:
基于路由的分割 vs 基于组件的分割
打包的情况也会不同, 对比如下两幅图:
和:
实际的场景中, 不会严格的区分这两种, 可以一起用。
比如, 一般情况下, 一个页面就是一个模块, 它的子页面, 也是一个模块, 而这两者是分开的。
也就是更贴近这个模型:
当然一些特殊的场景下, 也可以对某些功能组件去分割。
比如播放器组件, 代码高亮组件等。
这个时候的组件, 会单独成包, 使用的时候才去加载。
当然也有一些别的策略, 比如:
- 把一些基础包, 不常变化的, 单独打包, 提高缓存命中率。
- 字体等资源拿出去, 走CDN。
- 国际化资源做成线加载, 不要一起打包,减少总体积。
- 图片自动压缩等。
这其中有很多细节, 本篇就不过多介绍, 后续的文章中会有涉及。
总结
具体, 还是要根据不同的场景,选择不同的打包策略, 来达到最有效果。
webpack 也提供了详细的文档:
https://webpack.docschina.org...
实际用到的时候可以去看看。
内容就这么多,希望对大家有所启发。
关注我