首页 web前端 js教程 有关webpack前端性能优化(详细教程)

有关webpack前端性能优化(详细教程)

Jun 22, 2018 pm 05:08 PM
webpack 性能优化

webpack是近期最火的一款模块加载器兼打包工具,它能把各种资源,例如JS(含JSX)、coffee、样式(含less/sass)、图片等都作为模块来使用和处理。这篇文章主要给大家总结介绍了关于webpack学习教程之前端性能优化的相关资料,需要的朋友可以参考下。

前言

曾几何时,我们是如上图的方式引入JS资源的,相信现在很少遇见了。近年来Web前端开发领域朝着规范开发的方向演进。体现在以下两点:

1、MVC研发构架。多多益处(逻辑清晰,程序注重数据与表现分离,可读性强,利于规避和排查问题...)

2、构建工具层出不穷。多多益处(提升团队协作,以及工程运维,避免人工处理琐碎而重复的工作)

  • 模块化开发

  • 将前端性能优化理论落地,代码压缩,合并,缓存控制,提取公共代码等

  • 其他的还包括比如你可以用ES 6 或CoffeeScript写源码,然后构建出浏览器支持的ES5

所以,前端这么好玩,如果还有项目没有前后端分离的话,真的是守旧过头了。

主流构建工具

市面上有许多构建工具,包括Grunt、Gulp、browserify等,这些和WebPack都是打包工具。但WebPack同时也具备以下特点:

相比Grunt,WebPack除了具备丰富的插件外,同时带有一套加载(Loader)系统。使它支持多种规范的加载方式,包括ES6、CommonJS、AMD等方式,这是Grunt、Gulp所不具备的。

从代码混淆的角度来看,WebPack更加的极致

代码分片为处理单元(而不是文件),使得文件的分片更为灵活。

P.S.此处只做简单的比较,不论孰优孰劣。其实工具都能满足需求,关键是看怎么用,工具的使用背后是对前端性能优化的理解程度。

引言

最近在用webpack优化首屏加载性能,通过几种插件之后我们上线前后的速度快了一倍,在此就简单的分享下吧,先上个优化前后首屏渲染的对比图。

可以看到总下载时间从3800ms缩短到1600ms。

我们在用webpack时一般都会选择多入口文件吧,为的就是将自己的源码跟第三方库代码分离。这是之前的代码,

entry: {
 entry: './src/main.js',
 vendor: ['vue', 'vue-router', 'vuex', 'element-ui','echarts']
},
output: {
 path: config.build.assetsRoot,
 filename: utils.assetsPath('js/[name].[chunkhash].js'),
 chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
}
登录后复制

echarts非常大,所以打包时的vendor.js大概为1.2MB(经过gzip压缩之后),而且首页没有用到echarts,所以我之后使用了externals将第三方库以cdn的方式去引入,下面是优化过的代码

entry: {
 entry: './src/main.js',
 vendor: ['vue', 'vue-router', 'vuex', 'element-ui']
 },
 // 这里的output为base中的output,不是生产的output
 output: {
 path: config.build.assetsRoot,
 filename: '[name].js',
 libraryTarget: "umd",
 publicPath: process.env.NODE_ENV === 'production' ?
  config.build.assetsPublicPath : config.dev.assetsPublicPath
 },
 externals: {
 echarts: 'echarts',
 _: 'lodash'
 },
登录后复制

这就是优化前后的对比。

然后我们要到html中以script标签的形式去引externals中的cdn。之后就可以在相应的文件中import了,他的好处是不管你在多少vue文件中引用多少次,他都不会打包到所有的trunk(这里的trunk'指的是按需加载,一会详细说明)中,这是用webpack-bundle-analyzer插件展示的效果。

var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
new BundleAnalyzerPlugin({
  // 可以是`server`,`static`或`disabled`。
  // 在`server`模式下,分析器将启动HTTP服务器来显示软件包报告。
  // 在“静态”模式下,会生成带有报告的单个HTML文件。
  // 在`disabled`模式下,你可以使用这个插件来将`generateStatsFile`设置为`true`来生成Webpack Stats JSON文件。
  analyzerMode: 'server',
  // 将在“服务器”模式下使用的主机启动HTTP服务器。
  analyzerHost: '127.0.0.1',
  // 将在“服务器”模式下使用的端口启动HTTP服务器。
  analyzerPort: 8888, 
  // 路径捆绑,将在`static`模式下生成的报告文件。
  // 相对于捆绑输出目录。
  reportFilename: 'report.html',
  // 模块大小默认显示在报告中。
  // 应该是`stat`,`parsed`或者`gzip`中的一个。
  // 有关更多信息,请参见“定义”一节。
  defaultSizes: 'parsed',
  // 在默认浏览器中自动打开报告
  openAnalyzer: true,
  // 如果为true,则Webpack Stats JSON文件将在bundle输出目录中生成
  generateStatsFile: false, 
  // 如果`generateStatsFile`为`true`,将会生成Webpack Stats JSON文件的名字。
  // 相对于捆绑输出目录。
  statsFilename: 'stats.json',
  // stats.toJson()方法的选项。
  // 例如,您可以使用`source:false`选项排除统计文件中模块的来源。
  // 在这里查看更多选项:https: //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
  statsOptions: null,
  logLevel: 'info' //日志级别。可以是'信息','警告','错误'或'沉默'。
 })
登录后复制

我们会看到,没用externals和用了externals后所有的js中都不会出现类似echarts和lodash的库出现(就算你import一万次他都不会打包一次,厉害吧~~)。

对于externals再说两点——

1.externals中的key是import中使用的

import lodash from "_";
import echarts from "echarts";
登录后复制

2.externals中的value是window下调用的

然后我们再来聊聊为什么output使用trunkhash不用trunk,这是为了持久化缓存。简单说下两者的区别——

trunk:每次build之后的版本,就是说所有的build之后的文件hash值一致,比如我只改了一个文件,最后所有的文件hash都会变,这样所有的文件都不会走cache,这样缓存就失去了意义。

trunkhash:根据每个文件生成不同的hash值,当文件变化时hash会改变且只会改变相应的文件

然后我们肯定是要用到CommonsChunkPlugin,这个插件是用来抽取公共代码的,基本上99%的配置都是长这样子或者类似这样子用两个不同的commonschunkPlugin,但这从某方面来说并没有实现真正意义上的持久化缓存,这个一会我会通过webpack打包原理来详细解释其中的原因。。。。。。

new webpack.optimize.CommonsChunkPlugin({
 names: ['vendor','manifest']
})
登录后复制

在没用这个插件之前,我们的main.js和vendor.js会是这样子。。。

大家会看到我们这两个文件会有公共的部分,比如vue和element-ui,所以我们要抽取公共代码到vendor中,所以我们可以先这样配置

new webpack.optimize.CommonsChunkPlugin({
 name: 'vendor',
}),
登录后复制

但这样的话虽然可以提取公共代码,但我们会把runtime(webpack运行时的代码,一会在打包原理中会再次提到)也放到vendor中,这里面会维护一个trunk的文件列表,类似于这样,就是说我们改任意的代码,这个table里面的hash会变,所以vendor的hash也会变

,所以这没有实现真正的持久化缓存。这个hash table是按需缓存的打包出来的trunk包,一般都是通过require.ensure(就是vue-router中配置的page对应页面,按需加载)

所以我们就把name改为names,就是上面那个配置。因为使用这个插件,我们会把公共代码抽到第一个name中,把runtime放到最后一个name中,也就是我们所谓的“manifest”文件。

并且这个文件会比较小,通常都是2kb左右,所以build后会生成一个script标签,但这样的话就多了一个http请求,所以我们可以用另外一个插件(InlineManifestWebpackPlugin)将manifest.js内联进去。就会长这样子

再回到我们的CommonsChunkPlugin,现在我们随便改任何已存在的文件,vendor.js的hash都不会变,是的,貌似这就实现了持久化缓存。但是当我们新增一个模块,并且在入口文件中import一下,我们的vendor就会跟main一起变。很奇怪对吧,我们明明已经做了自己的源码跟第三方库分离,为什么vendor还会变(到现在应该没有任何一篇博客对此进行详细的说明)。下面我就详细的给大家解释下我的看法,如果大家发现有不对的地方还请指正。

再解释为什么之前,我们先简单了解下webpack的打包规则。

webpack一个entry对应一个bundle,这个bundle包括入口文件和其依赖的模块。其他按需加载的则打包成其他的bundle。还有一个比较重要的文件时manifest,它是最先加载的,负责打包其他的bundle并按需加载和执行。

manifest是一个自执行函数,熟悉angular的同学看第一行应该很了解,因为anguar1.3版本的源码中启动就是angular.bootstrap,对,这里也是一样。里面的modules变量就是对应模块函数,它是webpack处理的基本单位,就是说对应打包前的一个文件

这是js源文件,

这是打包后的文件,

所有的模块函数索引都是连续的(每个js文件生成一个trunkid!!!!!),像这种 /* 4 */ 对应的就是js文件,他通过打包就变成了一个个trunkid,仔细看会看到咱们打包前js文件里的export和require依赖都会统一转换成webpack模块。咱们说的webpackJsonp就是除manifest之外打包其他的文件的函数体。

简单说下main吧,这个图的trunkid是连续的,为了在一张图上显示,我截掉了trunk3-7.

这里面一共有三个参数,第一个是我当前文件的trunkid,它是唯一标识符,就是指main的trunkid,第二个就是打包的所有文件的模块函数,第三个是我要立即执行的trunkid模块函数。

ok,介绍这些就足够了。

然后我们再回过头来看看为什么我们所谓的commonschunkPlugin会变。刚才说过,有几个js就有几个trunkid。

所以当我们新加一个js并引入到main入口时,webpack再次打包,我的main文件会多一个模块函数,刚刚说过trunkid是依次递增的而且不会重复。所以对应的vendor的id会+1,就是这么细微的变化导致hash变了。

大家仔细看,这两个vendor都是10272行,唯一的不同就是我要自执行这个vendor库,这里我引用的jquery,所以这个文件只有jquery,自执行肯定要有模块函数,trunkid+1,所以hash会变。我们再好好回忆一下,其实这也说明了这个插件的意义,我就是要抽出公共的库,OK,这个插件做到了,但是因为webpack打包机制,不同文件生成不同turnkid,所以这是美中不足的一点。再回想一下,我们一般是不会随便修改main.js的,所以从另一角度上来说这就是实现了持久化缓存。但我如果就是想保持vendor的hash不变要怎么办呢?

这段代码就可以实现,没错,如果你对vue-cli了如指掌,这就是vue-cli的官方demo,至于为什么可以,这个我后续会跟大家解释(实在是写不动了。。。)。

最后再给大家介绍一个超级好用的东西,就是cdn。我们现在的需求是想让图片走cdn,让js走线上路径,但官方的解释是通过修改config文件做cdn变化,这样做的话我的所有输出都会走cdn,那所有的ajax请求就跨域了呀。

一开始我的解决方案是,在源文件中挨个替换,这样会比较慢,更重要的是,cdn图片也是有hash值的,当我以后替换图片时,还得重新改相应的hash。有什么方法能让他自动去获取hash呢。

没错,我们需要在url-loader中单独配置cdn,做到js访问线上路径,静态资源使用cdn,两者互不影响。

简单提醒一下,url-loader不能检测到js中的background,所以我们凡是在js中引用的地址,必须在外面先import这张图片,url-loader才会解析并打包。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在微信小程序中如何使用video组件播放视频

在微信小程序中如何使用audio组件

在vue中如何实现axios二次封装

以上是有关webpack前端性能优化(详细教程)的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Go 框架的性能优化与横向扩展技术? Go 框架的性能优化与横向扩展技术? Jun 03, 2024 pm 07:27 PM

为了提高Go应用程序的性能,我们可以采取以下优化措施:缓存:使用缓存减少对底层存储的访问次数,提高性能。并发:使用goroutine和channel并行执行冗长的任务。内存管理:手动管理内存(使用unsafe包)以进一步优化性能。为了横向扩展应用程序,我们可以实施以下技术:水平扩展(横向扩展):在多个服务器或节点上部署应用程序实例。负载均衡:使用负载均衡器将请求分配到多个应用程序实例。数据分片:将大型数据集分布在多个数据库或存储节点上,提高查询性能和可扩展性。

C++ 性能优化指南:探索提高代码执行效率的秘诀 C++ 性能优化指南:探索提高代码执行效率的秘诀 Jun 01, 2024 pm 05:13 PM

C++性能优化涉及多种技术,包括:1.避免动态分配;2.使用编译器优化标志;3.选择优化数据结构;4.应用缓存;5.并行编程。优化实战案例展示了如何在整数数组中查找最长上升子序列时应用这些技术,将算法效率从O(n^2)提升至O(nlogn)。

利用 C++ 优化火箭发动机性能 利用 C++ 优化火箭发动机性能 Jun 01, 2024 pm 04:14 PM

通过建立数学模型、进行模拟和优化参数,C++可显着提高火箭发动机性能:建立火箭发动机的数学模型,描述其行为。模拟发动机性能,计算关键参数(如推力和比冲)。识别关键参数并使用优化算法(如遗传算法)搜索最佳值。根据优化后的参数重新计算发动机性能,提高其整体效率。

优化之道:探寻java框架的性能提升之旅 优化之道:探寻java框架的性能提升之旅 Jun 01, 2024 pm 07:07 PM

通过实施缓存机制、并行处理、数据库优化和减少内存消耗,可以提升Java框架的性能。缓存机制:减少数据库或API请求次数,提高性能。并行处理:利用多核CPU同时执行任务,提高吞吐量。数据库优化:优化查询、使用索引、配置连接池,提升数据库性能。减少内存消耗:使用轻量级框架、避免泄漏、使用分析工具,减少内存消耗。

程序性能优化有哪些常见的方法? 程序性能优化有哪些常见的方法? May 09, 2024 am 09:57 AM

程序性能优化方法包括:算法优化:选择时间复杂度更低的算法,减少循环和条件语句。数据结构选择:根据数据访问模式选择合适的数据结构,如查找树和哈希表。内存优化:避免创建不必要对象,释放不再使用的内存,使用内存池技术。线程优化:识别可并行化任务,优化线程同步机制。数据库优化:创建索引加快数据检索,优化查询语句,使用缓存或NoSQL数据库提升性能。

Java 中如何使用轮廓分析来优化性能? Java 中如何使用轮廓分析来优化性能? Jun 01, 2024 pm 02:08 PM

Java中的轮廓分析用于确定应用程序执行中的时间和资源消耗。使用JavaVisualVM实施轮廓分析:连接到JVM开启轮廓分析,设置采样间隔运行应用程序停止轮廓分析分析结果显示执行时间的树形视图。优化性能的方法包括:识别热点减少方法调用优化算法

Java微服务架构中的性能优化 Java微服务架构中的性能优化 Jun 04, 2024 pm 12:43 PM

针对Java微服务架构的性能优化包含以下技巧:使用JVM调优工具来识别和调整性能瓶颈。优化垃圾回收器,选择并配置与应用程序需求相匹配的GC策略。使用缓存服务(如Memcached或Redis)来提升响应时间并降低数据库负载。采用异步编程,以提高并发性和响应能力。拆分微服务,将大型单体应用程序分解成更小的服务,以提升可伸缩性和性能。

如何快速诊断 PHP 性能问题 如何快速诊断 PHP 性能问题 Jun 03, 2024 am 10:56 AM

快速诊断PHP性能问题的有效技术包括:使用Xdebug获取性能数据,然后分析Cachegrind输出。使用Blackfire查看请求跟踪,生成性能报告。检查数据库查询,识别低效查询。分析内存使用情况,查看内存分配和峰值使用。

See all articles