【JS】「 面试三板斧 」代码分割(下)

背景

【JS】「 面试三板斧 」代码分割(下)

本文接上篇:

上文中, 我们了解了 chunks 三个字段的含义, 以及每个字段对应的行为。

今天是实践篇。

修改短短几行配置, 就达到了数百毫秒的优化效果。

正文

我的这个项目, 迭代一年多了, 中间打包配置也没没怎么改过, 毕竟也没什么问题, 速度也还可以。

刚好最近老板要搞指标, 让每个项目组分析性能数据, 给优化方案,做性能优化。

不分析不知道, 一分析, 很快啊, 马上就看出了问题, 看包分析结果:

【JS】「 面试三板斧 」代码分割(下)

脑海里瞬间闪过一张图:

【JS】「 面试三板斧 」代码分割(下)

几乎所有的三方依赖都打在了一起, 写好的页面按路由加载也都打到了一起, 简直辣眼睛...

于是就去看了一下代码配置:

修正前

原始配置:

const OnBoard = React.lazy(() => import('@/pages/onboard'));

const menuData = MenuItemTypes[] = [

{

title: 'onboard',

path: '/onboard',

meta: { showInMenu: false },

children: [

{

component: OnBoard,

// ...

},

// ...

]

},

// ...

];

const AppRouter = () => {

// ...

const { el, routes } = getRoutes(menuData);

// ...

return (

<BasicLayout {...matchedRoute.meta}>

<Suspense fallback={<Spin />}>

<Route path="/" exact component={MyDashboard} />

{el}

</Suspense>

// ...

</BasicLayout>

);

};

const App: React.FC<> = () => {

// ...

return <AppRouter />;

};

const AppContainer = () => (

<Router history={history}>

<Provider store={store}>

<Locale>

<App />

</Locale>

</Provider>

</Router>

);

看起来没什么问题。

看了一下 webpack 配置:

  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,

},

},

},

},

看起来貌似也没什么问题。。。

build 之后 html 中的脚本, 乍一看好像也没毛病...

<script type="text/javascript"></script>

<script type="text/javascript"></script>

<script type="text/javascript"></script>

<script type="text/javascript"></script>

<script type="text/javascript"></script>

这种情况下, 修改 chunks 配置的对比:

chunks: all

包分析:
【JS】「 面试三板斧 」代码分割(下)

加载时间以及入口文件初始加载的脚本文件:

【JS】「 面试三板斧 」代码分割(下)

chunks: async:

  <script type="text/javascript"></script>

<script type="text/javascript"img-wrap">【JS】「 面试三板斧 」代码分割(下)

几乎没有什么变化, 一时间, 开始怀疑是不是受了其他配置的影响,就去仔细去找了一下, 果然:

【JS】「 面试三板斧 」代码分割(下)

【JS】「 面试三板斧 」代码分割(下)

速度修改了配置。

【JS】「 面试三板斧 」代码分割(下)

修正后:

chunks:all

  optimization: {

runtimeChunk: {

name: 'manifest',

},

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: 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,

},

},

},

},

很快啊, 马上就有了变化:

【JS】「 面试三板斧 」代码分割(下)

【JS】「 面试三板斧 」代码分割(下)

【JS】「 面试三板斧 」代码分割(下)

chunks: async

入口文件初始加载的脚本:

【JS】「 面试三板斧 」代码分割(下)

  <script type="text/javascript"></script>

<script type="text/javascript"></script>

【JS】「 面试三板斧 」代码分割(下)

【JS】「 面试三板斧 」代码分割(下)

除了入口脚本数量的变化, 总体积, 加载时长, 几乎没有变化。

脚本数量的不同:

  • all: 8

  • async: 4

区别就是, 大文件的体积不同, 对这个大文件的加载时间有影响。

回头看, 这是一个 maxChunks 配置错误引发的血案。

修正配置之后, 立竿见影。


根据不同场景合理的拆分

根据你的情况, 可以选择更适合的打包策略。

all 的优势在于, 能共享代码。

选择这个模式, 如果你用的协议是h2, 并行下载,可能有比较好的效果。

async 会帮你合并一些包,但产生的请求也会减少。

需要根据实际情况做测试, 选择最适合的打包策略。

还有一种分割策略:

基于路由的分割 vs 基于组件的分割

打包的情况也会不同, 对比如下两幅图:

【JS】「 面试三板斧 」代码分割(下)

和:

【JS】「 面试三板斧 」代码分割(下)

实际的场景中, 不会严格的区分这两种, 可以一起用。

比如, 一般情况下, 一个页面就是一个模块, 它的子页面, 也是一个模块, 而这两者是分开的。

也就是更贴近这个模型:

【JS】「 面试三板斧 」代码分割(下)

当然一些特殊的场景下, 也可以对某些功能组件去分割, 比如播放器组件, 代码块组件等。
这个时候的组件, 会单独成包, 使用的时候才去加载。

这是另一个话题了, 也有很多细节在里面, 本篇就不过多介绍。

总结

具体, 还是要根据不同的场景,选择不同的打包策略, 来达到最有效果。

webpack 也提供了详细的文档:

https://webpack.docschina.org...

实际用到的时候可以去看看。

内容就这么多,希望对大家有所启发。

谢谢。

以上是 【JS】「 面试三板斧 」代码分割(下) 的全部内容, 来源链接: utcz.com/a/92708.html

回到顶部