webpack之常见性能优化

  • 构建性能
    • 减少模块解析
    • 优化loader性能
    • 限制loader的应用
    • 缓存loader的结果
    • 多线程打包
    • 开启热替换
    • 常见loader和plugin
  • 传输性能
    • 分包
      • 手动分包
      • 自动分包
    • 模块体积优化
    • 代码压缩
    • tree shaking
    • 懒加载
    • gzip
    • 辅助工具
  • 运行性能

关于webpack常见的性能优化,可从以下三方面做处理。

  1. 构建性能,当构建性能越高,开发效率越高。
  2. 传输性能,在这方面重点考虑网络中总的传输量,以及文件数量等。
  3. 运行性能,主要是指js在客户端的运行效率。

构建性能

减少模块解析

如果某个模块不做解析,该模块经过loader处理后的代码就是最终代码。

对于单独的模块不需要解析(不进行AST、不记录依赖、不进行依赖替换等操作,直接生成最终代码),可以做一下处理:

module.exports = {mode:'development',mdule:{noParse:/ElementUI/,}
}

对于存在依赖的模块,如果使用了noParse,存在的依赖并不会被记录和替换。

优化loader性能

限制loader的应用

针对某些第三方库,不必要使用某些loader处理。例如babel-loader,处理一些已经打包好的第三方库,反而增加了项目构建时间。

module.exports = {mode:'development',mdule:{rules:[{test:/\.js$/,include:/\.\src/,//应用于src目录下exclude:/node_modules/, //排除某些文件或目录use:["xx-loader"]}],}
}

缓存loader的结果

当文件内容不变时,经过相同的loader解析后,解析结果并没有改变,所以这个时候将loader的解析结果保存下来,让后续的解析直接使用保存的结果,具体如下:

module.exports = {module:{rules:[{test:/\.js$/,use:[{loader:'cache-loader'.cacheDirectory:'./cache'},...loaders]}]}
}

cache-loader的原理是,在执行loader之前,如果发现已缓存文件,直接在loader.pitch函数里return源代码。

多线程打包

通过thread-loader开启一个线程池,后续会把loader放进线程池的线程中运行以提高运行效率。

module.exports = {module:{rules:[{test:/\.js$/,use:[{loader:'cache-loader'.cacheDirectory:'./cache'},'thread-loader']}]}
}

thread-loader可以通过测试决定放置的位置。

开启热替换

热替换(Hot Module Replacement)可以降低代码改动到效果呈现的时间,最新webpack默认开启热替换。

module.exports = {mode:'development',devServer:{open:true,hot:true},plugins:[new HtmlWebpackPlugin({template:'./public/index.html'})]
}

默认情况下,webpack-dev-server不管是否开启热更新,当重新打包后,都会调用location.reload刷新页面,但如果运行module.hot.accept(),将改变这一行为。module.hot.accept的作用就是让webpack-dev-server通过socket管道,把服务器更新的内容发送到浏览器。

对于样式的热替换,可以添加style-loader

module.exports = {mode:'development',devServer:{open:true,hot:true},module:{rules:[{test:/\.css$/,use:['style-loader','css-loader']}]},plugins:[new HtmlWebpackPlugin({template:'./public/index.html'})]
}

常见loader和plugin

loader名称 loader描述
babel-loader 转换ES6+新特性语法
style-loader 将css文件引用并插到html
css-loader 支持.css文件的加载和解析
less-loader 支持less文件转换
sass-loader 支持sass文件转换
ts-loader 将ts转换成js
file-loader 进行图片、字体等文件的打包
raw-loader 将文件以字符串形式导入
thread-loader 多进程打包
plugin名称 plugin描述
CommonsChunkPlugin 将chunks相同的模块代码提取成公共js
CleanWebpackPlugin 清理构建目录
ExtractTextWebpackPlugin 从捆绑包或捆绑包中提取文本到单独的文件中
CopyWebpackPlugin 将文件或者文件夹拷贝到构建的输出目录
HtmlWebpackPlugin 创建html文件去承载输出的bundle
UglifyjsWebpackPlugin 压缩代码
TerserPlugin 压缩代码
ZipWebpackPlugin 将打包的资源生产zip包
OptimizeCSSAssetsPlugin css压缩插件
WebpackBundleAnalyzer 模块依赖的可视化

传输性能

分包

webpack默认不进行分包,会把所有依赖添加到同一个bundle,特别是在多页面打包的情况下,会存在多个chunk引入公共模块导致冗余代码的情况,占用打包体积。

分包的目的是在不影响源代码的情况下降低代码体积,并非所有的情况都适合分包,需要视具体情况而定。

手动分包

思路:

  1. 打包公共模块。例如常见第三方库。
  2. 手动引入公共js

注意事项:

  1. 不要对小型库进行单独打包。
  2. 不要对依赖多的库进行单独打包

公共模块打包过程如下:

//webpack.dll.config.js
const webpack = require('webpack')
module.exports = {mode:"production",entry:{element:['element'],jquery:['jquert']},output:{filename:'dll/[name].js',library:'[name]'//暴露全局变量名},plugin:[new webpack.DllPlugin({path:path.resolve(__dirname,'dll','[name].manifest.json'),//资源清单保存位置name:'[name]'//资源清单中保存的变量名}),]
}//webpack.config.js
const webpack = require('webpack')
module.exports = {plugin:[new webpack.DllReferencePlugin({manifest:require('./dll/element.manifest.json')}) //指定资源清单,在打包时对照资源清单,当发现该模块是资源清单里的资源时不进行打包处理。]
}

引用: https://webpack.docschina.org/plugins/dll-plugin#dllplugin

自动分包

webpack提供了optimization配置项,其中splitChunks是分包策略的配置,通过splitChunksPlugin配置分包策略进行分包,分包时,webpack开启了一个新的chunk,对分离的模块进行打包。

一般开发阶段没必要分包,因为有热替换,并且开发一般是在本机,大文件对开发阶段影响不大。

分包的基础单位是模块。所以在设置minSize时有时会出现打包的文件超过该值。

全局策略:

module.exports = {entry:{},output:{},optimization:{splitChunks:{chunks:'all', //默认为async,可选all或者initialmaxSize:30 *1024,//控制包的最大字节数automaticNameDelimiter:'.',//新chunk名称的分隔符,默认为~minChunks:1,//一个模块被多少个chunk使用时才会进行分包,默认为1minSize:30 * 1024,//单位为字节,当分包达到多少字节后才允许被真正地拆包,默认为30000},},plugin:[]
}

缓存组策略:
当不配置cacheGroups时,内部会存在vendors和default默认配置,我们也可以通过手动更改默认值。

module.exports = {entry:{},output:{},optimization:{splitChunks:{cacheGroups:{//默认存在以下配置,可继承全局配置vendors:{test:/[\\/]node_modules[\\/]/,//当匹配到相应模块时,将这些模块进行单独打包priority:-10//缓存组优先级,优先级越高,该策略越先进行处理,默认值为0},default:{minChunks:2,//最小chunk引用数为2priority:-20,//优先级reuseExistingChunk:true,//重用已经分离的chunk},elementUI:{minSize:0,test: /[\\/]node_modules[\\/]_?element-ui(.*)/,minChunks:2}}},}
}

模块体积优化

代码压缩

webpack内置terser,terser是一个代码压缩工具,压缩代码除了压缩代码体积,还可以提升破解成本。

Terser官网:https://terser.org/

默认情况下webpack的production模式是开启代码压缩,当我们要更改压缩配置时,可做以下处理:

module.exports = {optimization:{minimize:true, //是否启动压缩,默认是只在生产环境自动开启。minimizer:[//压缩时使用的插件,当你自动改压缩配置时必须配置相关压缩插件new TerserPlugin(),//js压缩插件new OptimizeCSSAssetsPlugin()//css压缩插件]}
}

terser、webpack、rollup.js都能够识别/*#__PURE__/注释标记,/*#__PURE__/的作用就是告诉打包工具该函数的调用不会产生副作用。

tree shaking

tree shaking,树摇,可以理解为摇动一棵树,即将腐烂的果实也随之摇动而掉落。

能够tree shaking的代码需要满足一定的代码规范,例如以下情况:

//有利于tree shaking
export xxx 导出,
import {xxx} from 'xxx'导入//不利于tree shaking
export default {xxx}导出,
import xxx from ‘xxx'导入

上面的情况当webpack依赖分析完毕后,webpack会根据每个模块每个导出是否被使用,标记其为dead code,然后交给代码压缩工具处理。

commonjs很难做到tree shaking,所以主流的库为了做tree shaking,都会发布其es6版本。

以vue为例,vue的代码中大量使用/*#__PURE__*/注释,通常产生副作用的代码都是模块内函数的顶级调用。该注释可以作用于任何语句上,让打包工具识别。

tree shaking对于无法识别副作用的函数会认为是副作用函数,不会产生副作用的代码标记/*#__PURE__*/注释。

相比于js,css并无法做到tree shaking,不过可以通过正则匹配页面样式有没有引用进行移除样式代码。

可以通过purgecss-webpack-plugin进行处理,css module无法处理。

https://www.npmjs.com/package/purgecss-webpack-plugin

懒加载

通过动态导入模块,例如在判断里使用导入语句。
导入语句不能使用commonjs,虽然require支持动态导入,但是它在打包环节也会进入依赖分析。
动态加载可以使用import(),import作为es6的草案,webpack打包发现使用import()的调用,会对其单独打包,打包结果该代码时,浏览器会使用jsonp远程请求该模块,import()返回的是一个promise。

async function run(){if(判断条件){const { chunk } = await import(/* webpackChunkName:'自定义chunkName' */'xxx.js')}
}
run()

请求的异步的模块会加入webpackJsonp数组里。

值得注意的是,这样的异步导入是不可以做到tree shaking的,不过可以使用取巧的方法,通过一个媒介引入,打包分析过程既能tree shaking又能异步加载。

//媒介文件
export { xxx } from '目标文件'//主文件
async function run(){if(判断条件){const { chunk } = await import(  '媒介文件')}
}
run()

gzip

http传输中,开启gzip需要进行如下配置:

  1. request header:Accept-Encoding:gzip,deflate,br
  2. response header:Content-Encoding:gzip

对哪些文件压缩,采用哪种压缩算法,这个需要测试权衡,毕竟压缩文件和解压文件都是需要时间的,对于相对大点的文件一般会有收益。

webpack压缩参与的步骤在于将文件预压缩,当请求到来时直接响应已经压缩的文件,而不需要先压缩再响应。

gzip预压缩可以通过compression-webpack-plugin插件进行。

const CompressionWebpackPlugin = require('compression-webpack-plugin')module.export = {plugin:[new CompressionWebpackPlugin({test:/\.js$/ //针对需要预压缩的文件minRatio:0.5 //压缩比率})]
}

以gzip为例,打包之后的文件包含了.js和.js.gz文件

辅助工具

  1. ESLint:通过ESLint规范代码。
  2. webpack-bundle-analyzer:通过该插件可以生成可视化打包结果的页面,有助于我们分析模块依赖。

运行性能

运行性能这方面,主要指js在浏览器端运行速度,取决于我们如何书写高性能的代码。

关于高性能的代码,可以参考常见的设计模式、代码规范、最佳实践等。

webpack之常见性能优化相关推荐

  1. 亿级PV,常见性能优化策略总结与真实案例

    作者:晓明 来自:美团技术团队 0 题记 美团网是国内最大的O2O服务平台,虽然经常面临高并发.大流量等问题,但在用户体验优化上美团APP仍被众多IT同行所推崇,他们在性能优化方面积累的宝贵经验尤其值 ...

  2. java常见性能优化_十大最常见的Java性能问题

    java常见性能优化 Java性能是所有Java应用程序开发人员都关心的问题,因为快速使应用程序与使其正常运行同等重要. 史蒂文·海恩斯(Steven Haines)使用他在Java性能问题上的个人经 ...

  3. 性能优化分析及常见性能优化策略总结

    最近,大家似乎都对性能优化分析,这一方面比较感兴趣.一方面是比较感兴趣,另一方面就是遇见许多类似的状况,但是,却不知从何下手,根源在哪里?应当如何正确优化?首先,先跟大家讲解下常见的性能优化策略分类! ...

  4. web常见性能优化总结(浏览器渲染过程详解)

    文章目录 一.什么是web的性能优化 二.web性能优化的目的 三.web性能优化的原理 3.1 加载文档 3.2 生成dom树 3.3 加载css 和js 3.4 生成CSS OM 3.5 rend ...

  5. webpack学习:性能优化

    本文内容如下 性能优化相关内容 如果你都有了答案,可以忽略本文章,或去webpack学习导图寻找更多答案 性能优化两大方面 一,开发环境性能优化 优化: 构建速度,代码调试 HMR热模块更新(代码调试 ...

  6. Vue的常见性能优化

    这里写目录标题 编码阶段 不要在模板里面写过多表达式 尽量减少 data 中的数据. 对象层级不要过深,否则性能就会差 computed 和 watch 区分使用场景 SPA 页面采用 keep-al ...

  7. ios 常见性能优化

    1. 用ARC管理内存 2. 在正确的地方使用reuseIdentifier 3. 尽可能使Views透明 4. 避免庞大的XIB 5. 不要block主线程 6. 在Image Views中调整图片 ...

  8. 常见性能优化小技巧原理

    一.多用有序数组+折半查找 金山卫士开源后立马招来各种批判,其中有一段批评金山卫士源码说太多if else而不用表驱动使得代码可读性不高,笔者看了下大致如下: TCHAR szFolderPath[M ...

  9. Webpack 生产环境性能优化之externals

    前言 在实际开发中,我们可能会引入一些第三方库,比如说 elementUI.但是在项目打包的时候,webpack会将main.js 中引入的第三方代码进行打包,为了减小js代码的体积,我们又不希望把它 ...

最新文章

  1. ELK 使用4-Kafka + zookpeer
  2. swift_039(Swift中的KVC的使用方法)
  3. Matplotlib for Python Developers
  4. 淡谈泛型约束T(转)
  5. 仿京东首页上侧导航左侧地址栏布局(1)
  6. linux mail命令查看邮件/mail控制台
  7. rust安装教程linux,如何在 Linux 中安装 Rust 编程语言
  8. 安卓程序开发——创建安卓虚拟机
  9. 【活动(深圳)DevOps/.NET 微服务 秋季分享会】火热报名中!
  10. java工程开发之图形化界面之(第六课)
  11. mysql 说说反模式设计_sql反模式分析1
  12. 2020 高考大数据下,数据可视化告诉你如何填志愿、选学校?
  13. ArchSummit微课堂|蘑菇街DevOps实践及心路历程分享
  14. Shell脚本学习-阶段十二-在CentOS 7上给一个网卡分配多个IP地址
  15. Graph_Master(连通分量_C_Trajan缩点+最小路径覆盖)
  16. 稳定好用的短连接生成平台,支持API批量生成
  17. 从头来过教你PHP脚本语言(先导篇)
  18. APP实用开发—自定义加载动画
  19. PerformanceManagementSystem
  20. 网络编程、正则表达式

热门文章

  1. 计算机传真机电话,为什么计算机能发传真?语音信箱真是把语音投入到信箱里吗?...
  2. 阿里云服务器地域暂时无法办理经营性ICP许可证?
  3. 网站常用的favicon.ico文件
  4. Android targetSdkVersion从23升级到26适配指南
  5. Qt源码解析-源码解析-QVideoWidget播放手机视频旋转问题
  6. 打印机用计算机名慢,“电脑连上打印机就超级慢”的解决方案
  7. UE_LOG打印信息
  8. 口红游戏 插口红游戏 h5页面开发
  9. 鲲鹏聚数,华为宣布联合高校发起GaussDB金种子发展计划
  10. 美国Zip code大全