前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >鹅厂原创 | 优化 Webpack 构建结果

鹅厂原创 | 优化 Webpack 构建结果

作者头像
用户1097444
发布2022-06-29 15:46:18
2820
发布2022-06-29 15:46:18
举报
文章被收录于专栏:腾讯IMWeb前端团队

nixzheng 

腾讯SNG事业群——前端高级工程师

(左右滑动查看代码)

0写在前面

Webpack应该是当下流行度最广的JavaScript构建、打包工具了。我们团队中大部分项目也在使用Webpack构建。项目的是传统的非SPA页面,我们使用了CommonsChunkPlugin来提取公共模块,保证各页面之间部分公共库可以复用缓存,同时使用UglifyJS等来保证输出文件体积的减小。原本Webpack这部分的配置是这样的:

代码语言:javascript
复制
{  // ...
  plugins: [    // ...
    new webpack.optimize.CommonsChunkPlugin({      name: 'vendor',      minChunks: 5,
    })
  ],
}

但这么做粒度还太粗,无法对打包的文件做更精细的控制。庆幸的是Webpack生态圈是如此的丰富,有不少好工具可以利用。

1分析打包结果

webpack-bundle-analyzer是一个非常好用的Webpack包分析工具。可以将每个文件包含的内容通过非常漂亮的图片表现出来。

我们在production模式的webpack配置下引入插件:

代码语言:javascript
复制
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;// ...plugins: [  // ...
  new BundleAnalyzerPlugin(),
]// ...

通过插件生成的包结构如下:

可以发现这里有两个严重的问题:

  • 有部分可以共用的脚本并没有公用。
  • areaData_min.js是项目中显示地区的一个JavaScript数据文件,体积很大,用到的页面也很多,但并不是强依赖,却被打包到了bundle里。

其他常见的问题包括vendor中打包入了过多文件,多次引入了不同版本的库文件等。

2模块异步化

首先我们来把非强依赖的模块异步化。

Webpack 1.0中可以通过 require.ensure 来实现异步文件的剥离和加载。Webpack2则通过更标准的 import() 来实现同样的功能。我们首先将 areaData_min.js 异步化:

代码语言:javascript
复制
import('assets/areaData_min').then((data) => {  this.setState({areaData: data});
})

异步后的结果:

独立了一个0_{hash}_.js,同时减少整体体积的效果也很明显。

对于React组件我们可以添加一个AsyncWrapper来复用异步加载逻辑。不过由于Webpack的动态引入其实依赖了静态的分析,所以我们不可以使用const target='lodash'; import(target) 这种方式来实现动态加载。需要额外定义一个AsyncComponent加载所需代码:

代码语言:javascript
复制
import React, {Component, createElement} from 'react'export default class AsyncWrapper extends Component {  constructor(props) {    super(props)    this.state = {      component: null,
    }
  }

  componentDidMount() {    const {load} = this.props

    load().then(module => {      this.setState({component: module.default})
    })

    load(component => {      this.setState({component})
    })
  }

  componentWillUnMount() {    this.setState({component: null})
  }

  render() {    const {component} = this.state    return component ? createElement(component, this.props) : null
  }
}// Target Async Componentimport React from 'react'import AsyncWrapper from './AsyncWrapper'const AsyncComponent = (props) =>
  <AsyncWrapper load={() => import('./TargetComponent')} {...props} />// Use<AsyncComponent xxx="1" />

也可以使用react-loadable等库实现同样的效果。

3调整CommonsChunkPlugin配置

可以发现部分可以公用的文件并没有合到vendor里来。简单调整一下配置:

代码语言:javascript
复制
{  // ...
  plugins: [    // ...
    new webpack.optimize.CommonsChunkPlugin({      name: 'vendor',      minChunks: 4,
    })
  ],
}

值得注意的是,我们需要谨慎权衡minChunks的取值,过小的取值将造成vendor无意义的变大。大部分情况下我并不推荐使用 ~minChunks~。这是由于我们一般希望vendor是稳定的,缓存可长时间使用。如果合并入太多业务代码,vendor的缓存复用率会大为降低,对更新频繁的项目来说对性能反而有损耗。

最后的结果如下图,相比优化前已经大幅改善了。

4小结

  • 将NODE~ENV设置为 production。一般也需要增加 DefinePlugin 设置。
  • 使用DllPlugin。不仅有利于提升vendor的稳定性,同时也会减少每次编译时间。

腾讯 2017 IMWebConf前端大会门票免费送

点击下方礼包,打开文章链接

在评论区留下足迹,回答的点赞数越高,惊喜越多哦!

点我点我

感谢本次会议的王者赞助商:腾讯课堂

感谢直播技术提供方:IT大咖说

感谢钻石赞助商(排名不分先后):100offer、WeTest、轩辕传奇、图灵教育、人民邮电出版社

感谢其他所有的合作伙伴(排名不分先后):HTML5梦工厂、开源中国、SegmentFault、前端圈、W3Cplus、前端早读课、WeX5、掘金、W3Cschool

感谢所有的合作媒体(排名不分先后):Stuq、GitChat、React-China、CSDN、Coding、伯乐在线、V2EX、活动行、腾讯大学、腾讯学院、腾讯研究院、QQ空间,以及所有帮助宣传的团队媒体和个人。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-08-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯IMWeb前端团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0写在前面
  • 1分析打包结果
  • 2模块异步化
  • 3调整CommonsChunkPlugin配置
  • 4小结
相关产品与服务
云直播
云直播(Cloud Streaming Services,CSS)为您提供极速、稳定、专业的云端直播处理服务,根据业务的不同直播场景需求,云直播提供了标准直播、快直播、云导播台三种服务,分别针对大规模实时观看、超低延时直播、便捷云端导播的场景,配合腾讯云视立方·直播 SDK,为您提供一站式的音视频直播解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档