Webpack打包优化实战:从体积瘦身到构建加速

作者:沉舟

时间:2026-10-22

浏览:599

本文深入解析Webpack打包优化的核心技巧,涵盖从定位大体积模块、提取公共代码、移除无用资源到模块化引入及CDN外部引用的全流程。重点讲解CommonsChunkPlugin与DLLPlugin的配置细节,旨在帮助开发者显著减小vendor.js体积并大幅提升构建效率,改善前端项目加载体验。

文章目录

Webpack打包优化概述

前端构建工具经历了从Browserify、Grunt、Gulp到Rollup、Webpack的演进,涌现出众多优秀方案。目前,Webpack无疑是使用最广泛的打包工具,无论是主流前端框架还是各类工具库,大多首选其作为构建基础。因此,在开发中选用Webpack作为打包工具是一个明智的选择。在最近的项目实践中,我也应用了Webpack,并遇到了一些关于优化的问题,在此总结Webpack打包优化的相关细节与方法。

本次项目使用了Vue全家桶,Webpack配置直接采用vue-cli生成的默认设置。项目打包后发现生成的vendor.js文件体积异常庞大,且打包过程耗时极长。为此,我尝试了多种优化手段以改善这一状况。

定位体积大的模块

定位体积大的模块

要优化打包体积,首要任务是识别出占用空间较大的模块。我们可以借助webpack插件webpack-bundle-analyzer来查看整个项目的体积结构对比。该插件以Treemap(树状地图)的形式直观展示结果,并支持具体的交互操作。它不仅能列出项目中引用的所有依赖,还能清晰显示各个模块体积在整个项目中的占比。

Webpack打包优化概述

该插件的安装方法可通过 npm install webpack-bundle-analyzer --save-dev 执行,并在webpack配置信息的 plugins: [new BundleAnalyzerPlugin()] 部分添加相应配置即可。对于vue-cli的配置方式,默认已安装该插件但未启用。找到config/index.js文件,在build配置下会有bundleAnalyzerReport的配置项,默认值为process.env.npm_config_report 。建议在package.json的scripts中添加一行 "analyz": "npm_config_report=true npm run build" ,这样每次需要启用该插件时,只需执行 npm run analyze 命令即可。

提取公共模块

提取公共模块

Webpack在模块化打包方面有两个核心功能:一是支持大量模块类型,无论是TypeScript、CoffeeScript还是Sass、Stylus等语言均能处理;二是可以通过配置控制打包文件的粒度,这一点将在下文详细阐述。

在开发中,我们通常会将所有依赖库单独提取出来,不与项目代码混合。这时会用到Webpack自带的插件CommonsChunkPlugin ,从名称即可看出它是一个用于提取公共模块的插件。根据文档说明,可以传入一个对象作为参数,常用参数包括:

  1. name(names)
  2. minChunks
  3. chunks

name参数易于理解,指最终打包文件的名称;若使用names参数,则必须传入字符串数组。minChunks参数若为数字,表示当模块被其他模块引用的次数达到该数值时,该模块将被打包;若为函数,则返回值必须为布尔类型,用于指示该模块是否应被打包进公共模块。chunks参数指定一个字符串数组,设置后打包时仅从指定的模块中提取公共子模块。

下面通过几个实例说明该插件的工作原理。

假设有两个模块chunk1.js和chunk2.js,以及两个项目文件a.js和b.js,其结构大致如下:


// a.js
require('./chunk1');
require('./chunk2');
require('jquery');
// b.js
require('./chunk1');
require('./chunk2');
require('vue');
// webpack配置如下
module.exports = {
 entry: {
  main: './main.js', 
  main1: './main1.js',    
  jquery:["jquery"],   
  vue:["vue"]  
 },  
 output: {   
  path: __dirname + '/dist',  
  filename: '[name].js' 
 },  
 plugins: [ 
  new CommonsChunkPlugin({  
   name: ["common","jquery","vue","load"],  
   minChunks:2 
  })  
 ] };

最终的打包结果为:jquery被打包到jquery.js,vue被打包到vue.js,common.js打包的是公共模块(chunk1和chunk2)。使用该插件打包时,满足minChunks条件的模块会被打包到name数组的第一个块中,随后数组后面的块依次打包。首先从entry中查找,若未找到则生成一个空块。name数组中的最后一个块打包的是Webpack的runtime代码,使用时必须先加载该块。

现在来看vue-cli对该插件的配置文件:


new webpack.optimize.CommonsChunkPlugin({
 name: 'vendor',
 minChunks: function (module, count) {
  // 将node_modules中的依赖模块全部提取到vendor文件中
  return (
   module.resource &&
   /\.js$/.test(module.resource) &&
   module.resource.indexOf(
    path.join(__dirname, '../node_modules')
   ) === 0
  )
 }
}),
// webpack在使用CommonsChunkPlugin时会生成一段runtime代码,并且打包进vendor中。
// 这样即使不改变vendor代码,每次打包时runtime会变化导致vendor的hash变化,这里
// 把独立的runtime代码抽离出来来解决这个问题
new webpack.optimize.CommonsChunkPlugin({
 name: 'manifest',
 chunks: ['vendor']
}),

移除不必要的文件

移除不必要的文件

在项目中,通过方法一我定位到几个体积占用较大的库,其中之一便是moment.js日期处理库。对于日期处理功能,该库为何占用如此大的体积?仔细查看发现,引用该库时引入了所有locale文件,而这些文件占据了库体积的大部分。因此,在Webpack打包时移除这部分内容可以有效减小打包文件的体积。

Webpack自带的两个库可以实现这一功能:

  1. IgnorePlugin
  2. ContextReplacementPlugin

IgnorePlugin 的使用方法如下:


// 插件配置
plugins: [
 // 忽略moment.js中所有的locale文件
 new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
],
// 使用方式
const moment = require('moment');
// 引入zh-cn locale文件
require('moment/locale/zh-cn');
moment.locale('zh-cn');

ContextReplacementPlugin 的使用方法如下:


// 插件配置
plugins: [
 // 只加载locale zh-cn文件
 new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /zh-cn/),
],
// 使用方式
const moment = require('moment');
moment.locale('zh-cn');

通过上述两种方式,moment.js的体积大致能缩减为原来的四分之一。

模块化引入与CDN引用

模块化引入

在项目中我使用了lodash这一常用工具库,但在代码定位时发现该库也占用了不少体积。仔细思考,使用这类工具库时往往只用到其中很少的一部分功能,却引入了整个库。因此,这里可以进一步优化,仅引用需要的部分。


import {chain, cloneDeep} from 'lodash';
// 可以改写为
import chain from 'lodash/chain';
import cloneDeep from 'lodash/cloneDeep';

这样就可以只打包我们需要的部分功能。

通过CDN引用

对于一些必要的库,若无法对该库进行更好的体积优化,可以尝试通过外部引入的方式来减小打包文件的体积。采用该方法只需在CDN站点找到需要引用的库的外部链接,并对Webpack进行简单配置即可。


// 在html中添加script引用
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

// 这里externals的key指的是使用时需要require的包名,value指的是该库通过script引入后在全局注册的变量名
externals: {
 jquery: 'jQuery'
}
// 使用方法
require('jquery')

DLLPlugin与DLLReferencePlugin拆分文件

通过DLLPlugin和DLLReferencePlugin拆分文件

如果项目规模过大,打包时间会非常长。若频繁更新上线,则需不断对代码进行编译打包,浪费大量时间。此时,我们可以将那些不常更新的框架和库(如vue.js等)进行单独编译打包。这样,每次开发上线只需对开发文件进行编译打包,从而极大节省不必要的打包时间。这种方法需要DLLPlugin 和DLLReferencePlugin 两个插件配合完成。

DLLPlugin

在使用该插件时,我们需要单独创建一个配置文件,这里命名为webpack.dll.config.js,配置如下:


module.exports = {
 entry: {
  lib: ['vue', 'vuex', 'vue-resource', 'vue-router']
 },
 output: {
  path: path.resolve(__dirname, '../dist', 'dll'),
  filename: '[name].js',
  publicPath: process.env.NODE_ENV === 'production'
   ? config.build.assetsPublicPath
   : config.dev.assetsPublicPath,
  library: '[name]_library'
 },
 plugins: [
  new webpack.DefinePlugin({
   'process.env': '"production"'
  }),
  /**
   * path: manifest.json输出文件路径
   * name: dll对象名,跟output.library保持一致
   */ 
  new webpack.DllPlugin({
   context: __dirname,
   path: path.resolve(__dirname, '../dist/dll', 'lib.manifest.json'),
   name: '[name]_library'
  })
 ]
}

这里要注意几点:

  1. entry中写明所有要单独打包的模块
  2. output的library属性可以将dll包暴露出来
  3. DLLPlugin的配置中,path指明manifest.json文件的生成路径,name暴露出dll的函数名

运行该配置文件便可生成打包文件和manifest.json文件。

DLLReferencePlugin

对于该插件的配置,不需要像上面一样单独写配置文件,只需要在生产配置文件中添加如下代码:


new webpack.DllReferencePlugin({    
 context: __dirname,         // 同dll配置的路径保持一致
 manifest: require('../dist/dll/lib.manifest.json') // manifest的位置
}),

然后运行Webpack,发现打包速度得到了极大提升,且无需每次更新代码时重复编译打包这些依赖库。

其他优化手段

其他

关于Webpack的打包优化,我大致总结了上述方法。为了让页面加载更快,提供更好的用户体验,我们不仅要从打包上优化,还可以从其他方面入手。这里我也简单提一下我使用过的方法。

开启Gzip压缩

开启Gzip压缩可以减少HTTP传输的数据量和时间,从而减少客户端请求的响应时间。由于降低了请求时间,页面加载速度也会得到提升,渲染速度更快,极大地改善了用户体验。由于目前几乎所有主流浏览器都支持Gzip压缩方式,只需对服务器进行相关设置即可,这里就不具体讲解如何配置服务器。

压缩混淆代码

我们平常也会对代码进行压缩混淆,可以通过UglifyJS 等工具对JS代码进行压缩。同时,去掉不必要的空格、注释、console信息等,也能有效减小代码体积。

总结

总结

本文到此结束,主要对Webpack的打包优化部分做了讲解。当然,受限于能力和时间,只研究了部分方法,可能还有其他更多的优化手段,无论是从编译打包的体积还是速度上,都能有更好的优化。接触了一段时间的Webpack后发现,作为一个打包工具,它确实过于复杂,无论从最初的官方文档还是到新的高级特性,都很难完全掌握,仍需自己不断实践和研究。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章