位置: IT常识 - 正文

webpack之常见性能优化(webpack常用属性)

编辑:rootadmin
webpack之常见性能优化 文章目录构建性能减少模块解析优化loader性能限制loader的应用范围缓存loader结果开启多线程打包热替换 (Hot Module Replacement)传输性能分包手动分包自动分包单模块体积压缩代码压缩tree shaking懒加载gzip辅助工具运行性能

推荐整理分享webpack之常见性能优化(webpack常用属性),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:webpack常用属性,webpack常用,webpack的基本功能和基本原理,webpack常用属性,webpack基础知识,webpack常用属性,webpack常见的plugin,webpack相关,内容如对您有帮助,希望把文章链接给更多的朋友!

关于webpack的性能优化,主要体现在三个方面:

构建性能:是指在开发阶段的构建性能。当构建性能越高,开发效率越高。传输性能:在这方面重点考虑网络中的总传输量、JS文件数量以及浏览器缓存。运行性能:主要是指JS代码在浏览器端运行的速度。构建性能减少模块解析

模块解析包括:AST抽象语法树分析、依赖分析、模板语法替换

对某个模块不进行解析,可以缩短构建时间

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

如果没有loader对该模块进行处理,该模块的源码就是最终打包结果的代码。

对于模块中没有其他依赖模块,则不需要解析,可以通过配置module.noParse进行处理:

module.exports = { mode: "development", module: { noParse: /JQuery/ } }优化loader性能限制loader的应用范围

针对一些第三方库,不使用loader进行处理。例如babel-loader,转换一些本身就是用ES5语法书写的第三方库,反而会浪费构建时间。 因此通过module.rules.exclude或module.rules.include,排除或仅包含需要应用loader的场景。

module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, //或 // include: /src/, use: "babel-loader" } ] } }缓存loader结果

如果某个文件内容不变,经过相同的loader解析后,解析后的结果也不变,所以我们可以把loader的解析结果保存下来,让后续的解析直接用缓存的结果,具体实现如下:

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

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

那么问题来了,loader明明不是从后往前执行的吗?那为什么cache-loader还可以拿到loader的缓存结果?

其实每个loader的运行过程中,还包括一个过程,即pitch

function loader(source){ return `new source` } loader.pitch = function(filePath){ // 可返回可不返回 // 如果返回,返回源代码 } module.exports = loader;

第一次打包时,会先把filepath交给loader1.pitch执行, 检查是否有缓存结果,若无缓存,往后执行。调用loader2.pitch,检查是否有缓存,若无缓冲,往后执行,依次类推…直到最后结束了再调用loader,当调用cache-loader时,就会返回loader处理的结果并缓存。 当第二次打包时(流程同上),若发现有缓存,则直接返回缓存结果,不会继续往后走了,示例图如下:

pitch的好处,可以根据是否有返回,来控制下一步到哪。

对于babel-loader,使用它本身的配置也是可以缓存的。

开启多线程打包

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

module.exports = { module: { rules: [{ test: /\.js$/, use: [ "thread-loader", "babel-loader" ] }] } };

放到线程池的loader的缺点:

无法使用 webpack api 生成文件。无法使用自定义的 plugin api。无法访问 webpack options。

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

由于开启和管理线程需要消耗时间,所以在小项目使用会增加构建时间。

热替换 (Hot Module Replacement)

其实,热更新是不能降低构建时间(可能还会稍微增加),因为它发生代码运行期间,但它可以降低代码改动到效果显现的时间。

//配置文件 module.exports = { devServer: { open: true, hot: true //开启HMR }, plugins: [ new HTMLWebpackPlugin({ template: "./public/index.html" }) ] } //index.js if(module.hot){ // 是否开启热更新 module.hot.accept() // 接收热更新 }

默认情况下,webpack-dev-server不管是否开启了热更新,当重新打包后,都会调用location.reload刷新页面 但如果运行module.hot.accept(),将改变这一行为, module.hot.accept()的作用是让webpack-dev-server通过socket管道,把服务器更新的内容发送到浏览器,然后,将结果交给插件HotModuleReplacementPlugin注入的代码执行插件HotModuleReplacementPlugin会根据覆盖原始代码,然后让代码重新执行。

对于样式热替换,可使用style-loader。

module.exports = { devServer: { open: true, hot: true //开启HMR }, module: { rules: [{ test: /\.css$/, use: ["style-loader", "css-loader"] }] }, plugins: [ new HTMLWebpackPlugin({ template: "./public/index.html" }) ] }

为什么不使用mini-css-extract-plugin插件?

因为热更新发生时,HotModuleReplacementPlugin只会简单的重新运行模块代码。因此style-loader的代码一运行,就会重新设置style元素中的样式,而mini-css-extract-plugin生成文件是在构建期间,运行期间无法改动文件。

整个原理流程:

当开启热更新后,Webpack 会轮询问有没有哪些模块发生变化,如果文件内容发生改变,会异步下载更新的代码,向服务器发送请求。下载完毕后,服务器就会主动发送信息给浏览器告知有文件内容发生改变,浏览器发送请求给服务器请求发送修改后的资源文件,服务器接收到请求后把修改的资源文件发送给浏览器,浏览器把接收到的结果交给HotModuleReplacementPlugin,HotModuleReplacementPlugin再覆盖原始代码,再重新执行代码。

传输性能分包

webpack默认情况下是不会分包的,它会把所有依赖文件合并到一个bundle中。而分包的时机是,当公共模块体积较大 或 有较少的变动,特别是在多页面打包的情况下,会存在多个chunk引入公共模块导致冗余代码的情况,占用打包体积。

分包的目的是在不影响源代码编写的情况下,减少公共代码,降低总体积(特别是一些大型的第三方库)和充分利用浏览器缓存。并非所有的情况都适合分包,需要视具体情况而定。

手动分包

总体思路:

先单独的打包公共模块,并利用DllPlugin生成资源清单。手动引入公共模块,重新设置clean-webpack-plugin,然后使用DllReferencePlugin控制打包结果。

具体打包过程如下:

开启output.library暴露公共模块用DllPlugin创建资源清单用DllReferencePlugin使用资源清单// webpack.dll.config.js const webpack = require('webpack'); module.exports = { mode: "production", entry: { jquery: ["jquery"], lodash: ["lodash"] }, output: { filename: "dll/[name].js", library: "[name]", //libraryTarget: "var" //暴露方式 }, plugins: [ new webpack.DllPlugin({ path: path.resolve(__dirname, "dll", "[name].manifest.json"), //资源清单的保存位置 name: "[name]"//资源清单中,暴露的变量名 }) ] }; //webpack.config.js module.exports = { plugins:[ //指定资源清单,在打包时对照资源清单,当发现该模块是资源清单里的资源时不进行打包处理。 new webpack.DllReferencePlugin({ manifest: require("./dll/jquery.manifest.json") }), new webpack.DllReferencePlugin({ manifest: require("./dll/lodash.manifest.json") }) ]};

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

自动分包

原理:

检查每个chunk编译的结果根据分包策略,找到那些满足策略的模块根据分包策略,生成新的chunk打包这些模块(代码有所变化)把打包出去的模块从原始包中移除,并修正原始包代码

在代码层面,有以下变动

分包的代码中,加入一个全局变量,类型为数组,其中包含公共模块的代码原始包的代码中,使用数组中的公共代码

webpack提供了optimization配置项,其中splitChunks是分包策略的配置。

实际上,webpack在内部是使用SplitChunksPlugin进行分包的,分包时,webpack开启了一个新的chunk,对分离的模块进行打包。打包结果中,公共的部分被提取出来形成了一个单独的文件,它是新chunk的产物

过去有一个库CommonsChunkPlugin也可以实现分包,不过由于该库某些地方并不完善,到了webpack4之后,已被SplitChunksPlugin取代。

一般分包是在生产环境下进行的。

webpack之常见性能优化(webpack常用属性)

分包策略有其默认的配置,只需小小改动即可应用大部分分包场景。

chunks:用于配置需要应用分包策略的chunk。一般只需要配置为 all 即可

all: 对于所有的chunk都要应用分包策略async:【默认】仅针对异步chunk应用分包策略initial:仅针对普通chunk应用分包策略

maxSize:可以控制包的最大字节数。

如果某个包(包括分出来的包)超过了该值,则webpack会尽可能的将其分离成多个包。 分包的基础单位是模块,如果一个完整的模块超过了该体积,它是无法做到再切割的,因此,尽管使用了这个配置,完全有可能某个包还是会超过这个体积

全局策略:

module.exports = { mode: "production", entry: {}, output: {}, optimization: { splitChunks: { // 分包策略 chunks: "all", maxSize: 60000, // 分包策略的其他配置 automaticNameDelimiter: ".", // 新chunk名称的分隔符,默认值~ minChunks: 1, // 一个模块被多少个chunk使用时,才会进行分包,默认值1 minSize: 30000, // 当分包达到多少字节后才允许被真正的拆分,默认值30000 }, }, plugins: [], }

缓存组策略: 每个缓存组提供一套独有的策略,webpack按照缓存组的优先级依次处理每个缓存组,被缓存组处理过的分包不需要再次分包。

默认情况下,webpack提供了两个缓存组:

module.exports = { optimization:{ splitChunks: { //全局配置 cacheGroups: { // 属性名是缓存组名称,会影响到分包的chunk名 // 属性值是缓存组的配置,缓存组继承所有的全局配置,也有自己特殊的配置 vendors: { test: /[\\/]node_modules[\\/]/, // 当匹配到相应模块时,将这些模块进行单独打包 priority: -10 // 缓存组优先级,优先级越高,该策略越先进行处理,默认值为0 }, default: { minChunks: 2, // 覆盖全局配置,将最小chunk引用数改为2 priority: -20, // 优先级 reuseExistingChunk: true // 重用已经被分离出去的chunk } } } } }单模块体积压缩代码压缩

代码压缩除了减少代码体积,还可以破坏代码的可读性,提升破解成本。

Terser是一个新起的代码压缩工具,支持ES6+语法。webpack会内置Terser,当启用生产环境后即可用其进行代码压缩。

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

如果想更改、添加压缩工具,又或者是想对Terser进行配置,使用下面的webpack配置即可:

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"; // 导入 //不使用 export default {xxx}; //导出 import xxx from "xxx"; // 导入

当webpack依赖分析完毕后,webpack会根据每个模块每个导出是否被使用,标记其他导出为dead code,然后交给代码压缩工具处理,代码压缩工具最终移除掉那些dead code代码。

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

webpack在tree shaking的使用,有一个原则:一定要保证代码正确运行

在满足该原则的基础上,再来决定如何tree shaking

因此,当webpack无法确定某个模块是否有副作用时,它往往将其视为有副作用

因此,某些情况可能并不是我们所想要的

//common.jsvar n = Math.random();//index.jsimport "./common.js"

虽然我们根本没用有common.js的导出,但webpack担心common.js有副作用,如果去掉会影响某些功能

如果要解决该问题,就需要标记该文件是没有副作用的

在package.json中加入sideEffects

{ "sideEffects": false}

有两种配置方式:

false:当前工程中,所有模块都没有副作用。注意,这种写法会影响到某些css文件的导入数组:设置哪些文件拥有副作用,例如:["!src/common.js"],表示只要不是src/common.js的文件,都有副作用

这种方式我们一般不处理,通常是一些第三方库在它们自己的package.json中标注

由于webpack无法对css完成tree shaking,所以可以通过正则匹配页面样式有没有引用进行移除样式代码。

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

懒加载

通过动态导入模块,例如在判断里使用导入语句。 导入语句不能使用commonjs,虽然require支持动态导入,但是它在打包环节也会进入依赖分析。 动态加载可以使用import(),import作为es6的草案,webpack打包发现使用import()的调用,会对其单独打包,打包结果该代码时,浏览器会使用JSOP的方式远程去读取一个js模块,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

gzip是一种压缩文件的算法

gizp工作原理:

浏览器发送请求时,会在请求头中设置Accept-Encoding:gzip,deflate,br。表明浏览器支持gzip。服务器收到浏览器发送的请求之后,判断浏览器是否支持gizp,如果支持gzip,则向浏览器传送压缩过的内容,不支持则向浏览器发送未经压缩的内容。一般情况下,浏览器和服务器都支持gzip,响应头返回包含content-encoding:gzip。浏览器接收到服务器的响应之后判断内容是否被压缩,如果被压缩则解压缩显示页面内容。

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

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

使用compression-webpack-plugin插件对打包结果进行预压缩,可以移除服务器的压缩时间。

const CmpressionWebpackPlugin = require("compression-webpack-plugin") module.exports = { plugins: [ new CmpressionWebpackPlugin({ // filename: "[file].gzip" test: /\.js/, //针对需要预压缩的文件 minRatio: 0.5 //压缩比率 }) ] };

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

辅助工具ESlint:检查JS代码规范

官网:https://eslint.org/

民间中文网:https://eslint.bootcss.com/

bundle-analyzer:生成代码分析报告,帮助提升代码质量和网站性能运行性能

运行性能是指,JS代码在浏览器端的运行速度,它主要取决于我们书写代码质量的高低。

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

本文链接地址:https://www.jiuchutong.com/zhishi/296036.html 转载请保留说明!

上一篇:web前端面试高频考点——Vue原理(理解MVVM模型、深度/监听data变化、监听数组变化、深入了解虚拟DOM)(web前端面试常见问题)

下一篇:大数据项目之数仓相关知识(大数据项目之数据采集)

  • 华为儿童手表怎么连接wifi(华为儿童手表怎么添加联系人)

    华为儿童手表怎么连接wifi(华为儿童手表怎么添加联系人)

  • 微信耳机模式怎么取消(微信耳机模式怎么切换回来)

    微信耳机模式怎么取消(微信耳机模式怎么切换回来)

  • 小米手机怎么分享wifi密码给朋友(小米手机怎么分身)

    小米手机怎么分享wifi密码给朋友(小米手机怎么分身)

  • 微博可以改名字吗(微博可以改名字不)

    微博可以改名字吗(微博可以改名字不)

  • 8p支持18w快充吗(8p支持18w快充嘛)

    8p支持18w快充吗(8p支持18w快充嘛)

  • 抖音由于对方的隐私设置,你无法发送消息(抖音由于对方的隐私设置,你无法私信)

    抖音由于对方的隐私设置,你无法发送消息(抖音由于对方的隐私设置,你无法私信)

  • 苹果a1534笔记本是哪一年(苹果a1534笔记本是什么型号)

    苹果a1534笔记本是哪一年(苹果a1534笔记本是什么型号)

  • 手机屏幕干燥划不动怎么办(手机屏幕划起来干涩)

    手机屏幕干燥划不动怎么办(手机屏幕划起来干涩)

  • 百兆路由器最大速度(百兆路由器最大下载速度)

    百兆路由器最大速度(百兆路由器最大下载速度)

  • vivos6带nfc功能吗(vivos6手机带nfc吗)

    vivos6带nfc功能吗(vivos6手机带nfc吗)

  • 华为荣耀30是没法用耳机吗(华为荣耀30没有原装耳机吗)

    华为荣耀30是没法用耳机吗(华为荣耀30没有原装耳机吗)

  • 吃货卡怎么用不了(吃货卡不能用了怎么解)

    吃货卡怎么用不了(吃货卡不能用了怎么解)

  • 苹果6s手机手电筒在哪(苹果6手电在哪里)

    苹果6s手机手电筒在哪(苹果6手电在哪里)

  • 交流电源和直流电源的区别(交流电源和直流电源怎么判断)

    交流电源和直流电源的区别(交流电源和直流电源怎么判断)

  • 抖音加入公会和不加入有什么区别(抖音加入公会和不加入收益有什么区别)

    抖音加入公会和不加入有什么区别(抖音加入公会和不加入收益有什么区别)

  • 华为nova2plus是双卡双待手机吗(华为Nova2plus是双4G吗)

    华为nova2plus是双卡双待手机吗(华为Nova2plus是双4G吗)

  • 荣耀9青春版是什么充电接口(荣耀9青春版是安卓多少)

    荣耀9青春版是什么充电接口(荣耀9青春版是安卓多少)

  • 如何将一个微信上的好友转移到另一个微信上(如何将一个微信的聊天内容迁移到另一个微信)

    如何将一个微信上的好友转移到另一个微信上(如何将一个微信的聊天内容迁移到另一个微信)

  • 荣耀20有唤醒功能吗(荣耀20s唤醒yoyo)

    荣耀20有唤醒功能吗(荣耀20s唤醒yoyo)

  • word不小心关闭没保存(word不小心关闭没保存2010)

    word不小心关闭没保存(word不小心关闭没保存2010)

  • 支付宝预授权在哪里看(支付宝预授权是直接扣款吗)

    支付宝预授权在哪里看(支付宝预授权是直接扣款吗)

  • iphonex几核(苹果x是六核吗)

    iphonex几核(苹果x是六核吗)

  • 荣耀9x的升降摄像头是不是自动升降呢(荣耀9x升降摄像头)

    荣耀9x的升降摄像头是不是自动升降呢(荣耀9x升降摄像头)

  • *21*99999#怎么解除(-9999927)

    *21*99999#怎么解除(-9999927)

  • qq年龄怎么改(qq年龄怎么改成120岁)

    qq年龄怎么改(qq年龄怎么改成120岁)

  • 抖音怎么取消收藏(抖音怎么取消收藏的视频作品)

    抖音怎么取消收藏(抖音怎么取消收藏的视频作品)

  • 如果电脑中毒了,怎么解决?(如果电脑中毒了,航佳进销存还能使用吗)

    如果电脑中毒了,怎么解决?(如果电脑中毒了,航佳进销存还能使用吗)

  • 完美解决:flex布局中设置宽度被压缩的问题(完美解决win11间歇性掉线)

    完美解决:flex布局中设置宽度被压缩的问题(完美解决win11间歇性掉线)

  • 一般纳税人结转税额怎么做会计分录
  • 工业增加值怎么找
  • 利润分配在利润表里填哪一项
  • 保函费用是用来干什么的
  • 换出资产为存货为什么不
  • 没有以前年度损益调整这个科目,怎么增加?
  • 购买基金会计分录怎么填
  • 货物发出未开票不确认收入
  • 异地预缴增值税后本地怎么申报
  • 凭证工本费的账务处理
  • 利润表的企业所得税怎么查询
  • 甲供工程选择适用简易计税方法后,36个月
  • 房产证没有可以补办吗
  • 开红字增值税专用发票步骤
  • 免税发票还可以开吗
  • 文化事业建设费的征收范围
  • 企业没交社保年限怎么算
  • 减半征收城建税文件
  • 个人消费索要公司的钱
  • 销售不动产预收款纳税义务发生时间
  • 承兑贴息的会计分录
  • 地税局完税证明去哪里办理
  • 企业买房可以抵扣多少税
  • 土地抵扣进项税,,能调回来吗
  • 合同签订中,可以撤销吗
  • 公司向股东借款需要股东会决议吗
  • 产品的销售收入减去全部生产成本叫
  • 苹果系统中英文切换快捷键
  • mac怎么访问路径
  • win10系统如何开启蓝牙
  • 支付人工费会计科目
  • 个人所得税应该计入什么科目
  • sguard是什么
  • PHP:pg_fetch_result()的用法_PostgreSQL函数
  • 阐述python中浅复制与深复制
  • 多开票金额会计分录
  • 经营特许权
  • 固定资产清理的会计科目处理
  • php设置中文
  • php控制结构
  • vue3.0实战项目
  • 增值税专用发票有几联?
  • python怎么设置字符串宽度
  • 专用发票货物名称开错可以吗
  • 带折扣的发票如何入账
  • 织梦技巧
  • 如何解决安装包解析错误
  • 金银首饰以旧换新会计处理
  • 内部审计主要目的
  • 企业技术服务费有税前列支限额吗
  • 单位给食堂的补贴怎么算
  • 债券分期付息到期还本的意思
  • 坏账准备具有什么功能
  • 报销人跟领款人有什么区别
  • 对外投资如何做帐
  • 原材料科目怎么设置
  • 下列sql server语句中出现语法错误的是
  • mysql多个group by
  • 如何制作u盘系统win7
  • winxp系统怎么投屏
  • win7怎么用耳机听歌
  • centos6.5安装yum
  • win10系统浏览器怎么换成ie
  • win8怎样恢复系统
  • linux安装.sh
  • 关于我和鬼变成家人的那件事
  • ubuntu 编译ffmpeg
  • 基于像素的分类方法
  • 安卓手机引导模式设置
  • dota2 服务器ip地址
  • unity3d最新api
  • unity ulua
  • python中的变量
  • django批量创建数据
  • jquery foreach循环
  • 在androidstudio中,如何改变图片的位置
  • 股权转让税收优惠个人所得税
  • 民办学校需要交工会经费吗
  • 北京定额发票查验
  • 车辆购置税怎么做账
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设