热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

webpack4打包优化(HappyPack、threadloader)

一、速度分析安装插件speedmeasurewebpackpluginnpminstallsavedevspeedmeasurewebpackplugin引入插件、创立插件对象co
一、速度分析

安装插件speed-measure-webpack-plugin

npm install --save-dev speed-measure-webpack-plugin

引入插件、创立插件对象

const SpeedMeasurePlugin = require('speed-measure-webpack-plugin'); //引入插件const smp = new SpeedMeasurePlugin(); //创立插件对象

使用插件的wrap()方法将配置包起来

module.exports = smp.wrap({ entry: { index: './src/index.js', search: './src/search.js', }, output: { path: path.join(__dirname, 'dist'), //__dirname(当前模块的目录名) + dist filename: '[name]_[chunkhash:8].js', //打包后输出的文件名,增加文件指纹 chunkhash },plugpins: [],.....});

打包完成后控制台会输出各个loader的打包耗时,可根据耗时进一步优化打包速度


image.png二、体积分析

体积分析可以分析哪些问题?

  1. 依赖的第三方模块文件大小
  2. 业务里面的组件代码大小

打包后可以很清晰直观的看出各个模块的体积占比

安装插件webpack-bundle-analyzer

npm install --save-dev webpack-bundle-analyzer

引入插件、创立插件对象

const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

增加plugpins配置

plugins: [ new BundleAnalyzerPlugin() ],

打包完成后浏览器会打开http://127.0.0.1:8888/显示打包后的体积分析

image.png三、打包速度优化

webpack构建过程中直接影响构建效率的,一个是文件的编译,另一个是文件的分类打包。相较之下文件的编译更为耗时,而且在Node环境下文件只能一个一个去解决,因而这块的优化需要处理。那么要怎么优化打包速度呢?

1. 使用高版本的webpack和node.js

webpack4新版本的优化使用v8引擎,v8带来的优化包括

  • for of 替代 forEach
  • Map和Set 替代Object
  • includes 替代 indexOf()
  • 默认使用更快的md4 hash算法 替代 md5算法,md4较md5速度更快
  • webpack AST 可以直接从loader传递给AST,从而减少解析时间
  • 使用字符串方法替代正则表达式

更高版本的node.js对原生js api和js数据结构做出进一步的优化

2. 多进程/多实例构建(资源并行解析)

在webpack构建过程中,我们需要使用Loader对js,css,图片,字体等文件做转换操作,并且转换的文件数据量也是非常大的,且这些转换操作不能并发解决文件,而是需要一个个文件进行解决,我们需要的是将这部分任务分解到多个子进程中去并行解决,子进程解决完成后把结果发送到主进程中,从而减少总的构建时间。

可选方案

  • thread-loader(官方推出)
  • parallel-webpack
  • HappyPack
HappyPack

注:因为HappyPack作者对js的兴趣逐渐丢失,所以之后维护将变少,webpack4及之后推荐使用thread-loader
原理:每次webpack解析一个模块,HappyPack会将它及它的依赖分配给worker进程中;
HappyPack会将模块进行一个划分,比方我们有多个模块,这些模块交给HappyPack,首先在webpack compiler(钩子)的run方法之后,进程就会到达HappyPack,HappyPack会做少量初始化,初始化之后会创立一个线程池,线程池会将构建任务里面的模块进行一个分配,比方会将某个模块以及它的少量依赖分配给其中的一个HappyPack线程,以此类推,那么一个HappyPack的一个线程池会包括多个线程,这时候线程池的这些线程会各自去解决其中的模块以及它的依赖,解决完成之后会有一个通信的过程,会将解决好的资源传输给HappyPack的一个主进程,完成整个的一个构建过程。

HappyPack

将src目录下复制出多个相同页面

src.png
在没引入HappyPack之前执行打包
build.png
安装
npm install --save-dev happypack
注:假如在webpack4使用需要HappyPack5.0的版本
引入之后将rules对js的编译改为happypack/loader

rules: [ { test: /.js$/, //对所有js后缀的文件进行编译 use: [ // 'babel-loader' 'happypack/loader', ], },]

在插件中加入happypack-loader

plugins: [ new HappyPack({ // 3) re-add the loaders you replaced above in #1: loaders: ['babel-loader'], }),]happypack.png

很显著可以看出使用happypack之后打包速度加快很多

thread-loader

原理:与HappyPack相似,每次webpack解析一个模块,thread-loader会将它及它的依赖分配给worker进程中;
安装

npm install --save-dev thread-loader

在rule中增加thread-loader,thread-loader可以进行少量配置,例如workers(进程数)

rules: [ { test: /.js$/, //对所有js后缀的文件进行编译 include: path.resolve('src'), //表示在src目录下的.js文件都要进行一下使用的loader use: [ 'babel-loader', { loader: 'thread-loader', options: { workers: 3, }, }, // 'happypack/loader', ], },]thread-loader.png

使用thread-loader之后打包速度也有显著提升

3. 多进程/多实例进行代码压缩(并行压缩)

在代码构建完成之后输出之前有个代码压缩阶段,这个阶段也可以进行并行压缩来达到优化构建速度的目的;

可选方案

  • webpack-parallel-uglify-plugin
  • uglifyjs-webpack-plugin
  • terser-webpack-plugin(webpack4.0推荐使用,支持压缩es6代码)

npm install terser-webpack-plugin --save-dev

const TerserPlugin = require('terser-webpack-plugin');

optimization中增加TerserPlugin插件,开启parallel

optimization: { minimize: true, minimizer: [ new TerserPlugin({ //代码压缩插件 parallel: 4, //开启并行压缩 }), ], },

4. 通过分包提升打包速度

可以使用html-webpack-externals-plugin分离基础包,分离之后以CDN的方式引入所需要的资源文件,缺点就是一个基础库必需指定一个CDN,实际项目开发中可能会引用到多个基础库,还有少量业务包,这样会打出很多个script标签

new HtmlWebpackExternalsPlugin({ externals: [ { module: 'react', entry: 'https://unpkg.com/react@16/umd/react.development.js', global: 'React', }, ],})

进一步分包,采用预编译资源模块
采用webpack官方内置的插件DLLPlugin进行分包,DdllReferenceRlugin对manifest.json引用
DLLPlugin可以将项目中涉及到的例如react、reactdom、redux等组件和框架库打包成一个文件,同时生成manifest.json文件
manifest.json是对分离出来的包进行一个形容,实际项目即可以引用manifest.json,引用之后就会关联DLLPlugin分离出来的包,这个文件是用来让 DLLReferencePlugin 映射到相关的依赖上去

  1. 首先使用DLLPlugin进行分包
    创立一个单独的构建配置文件,webpack.dll.js,在该配置文件中指定出需要分离的包
    在package.json中增加dll的编译语句

"scripts": { "dll": "webpack --config webpack.dll.js" }

webpack.dll.js

const webpack = require('webpack');const path = require('path');module.exports = { mode: 'development', entry: { //对应output 中的library library: ['react', 'react-dom'], }, output: { filename: '[name]_[chunkhash].dll.js', //分离出来的文件名称,一个占位符+hash.dll.js [name]对应的是entry的library path: path.join(__dirname, 'build/library'), //输出到当前目录下的build目录 library: '[name]', //打包后暴露出的库的名字 }, plugins: [ new webpack.DllPlugin({ name: '[name]_[hash]', //打包后library.json中的name path: path.join(__dirname, 'build/library/[name].json'), //打包后生成[name].json的路径 }), ],};

npm run dll之后在build目录下会生成两个文件

image.png
也就是前面提到的manifest.json

构建好之后使用DllReferencePlugin引用manifest.json

plugins: [ new webpack.DllReferencePlugin({ manifest: require('./build/library/library.json'), }),]

5. 通过缓存提升二次打包速度

  • babel-loader 开启缓存
  • terser-webpack-plugin 开启缓存
  • 使用cache-loader或者者 hard-source-webpack-plugin

new HappyPack({ loaders: ['babel-loader?cacheDirectory=true'], })

设置babel-loader的cacheDirectory=true开启缓存

optimization: { minimize: true, minimizer: [ new TerserPlugin({ //代码压缩插件 parallel: 4, //开启并行压缩 cache: true, }), ], },

设置terser-webpack-plugin插件的cache: true开启缓存

使用hard-source-webpack-plugin

npm install --save-dev hard-source-webpack-plugin

plugins: [ new HardSourceWebpackPlugin() ]

第一次运行开始写入缓存文件


image.pngimage.png

开启缓存之后显著提升了打包速度

6. 缩小构建目标

尽可能的少构建模块,比方babel-loader不解析 node_modules

  • 优化resolve.modules配置(减少模块搜索层级)
  • 优化resolve.mainFields配置
  • 优化resolve.extensions配置
四、打包体积优化

主要对打包后图片、js、css文件的资源体积优化

1. 图片压缩

使用Node库的imagemin,配置image-webpack-loader对图片优化,改插件构建时会识别图片资源,对图片资源进行优化
imagemin优点分析

  • imagemin有很多定制选项
  • 可以引入更多第三方优化插件,例如pngquant
  • 可以引入多种图片格式

imagemin的压缩原理

  • pngquant:是一款PNG的压缩器,通过将图像转换为具备alpha通道(通常比24/32位PNG文件小60%-80%)的更高效的8位PNG格式,可明显减小文件大小;
    阿尔法通道(Alpha Channel)是指一张图片的透明和半透明度
  • pngcrush:其主要目的是通过尝试不同的压缩级别和PNG过滤方法来降低PNG IDAT数据流的大小;
  • optipng:其涉及灵感来自于pngcrush。optipng可将图像文件重新压缩位更小的尺寸,而不会丢失任何信息;
  • tingpng:也是将24位png文件转化为更小具备索引的8位图片,同时所有非必要的metadata也会被剥离掉;

npm install image-webpack-loader --save-dev

rules: [ { test: /.(png|jpg|gif|jpeg)$/, use: [ { loader: 'file-loader', options: { name: '[name]_[hash:8].[ext]', }, }, { loader: 'image-webpack-loader', options: { mozjpeg: { progressive: true, quality: 65, }, // optipng.enabled: false will disable optipng optipng: { enabled: false, }, pngquant: { quality: [0.65, 0.9], speed: 4, }, gifsicle: { interlaced: false, }, // the webp option will enable WEBP webp: { quality: 75, }, }, }, ], }]

2. 擦除无用到的css

可以同通过插件遍历代码,识别已经用到的css class
安装插件
npm i purgecss-webpack-plugin -D

const PurgecssPlugin = require('purgecss-webpack-plugin');const PATHS = { src: path.join(__dirname, 'src'),};plugins: [new PurgecssPlugin({ paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }), }),]

3. 动态Polyfill

什么是Polyfill?
babel默认只转换新的Javascript语法(syntax),如箭头函数等,而不转换新的API,比方Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及少量定义在全局对象上的方法(比方Object.assign)都不会转码;因而我们需要polyfill;
链接:https://www.jianshu.com/p/4822852792d1

官方解释

  • 它是一项服务,接受对一组浏览器功能的请求,并且仅返回请求浏览器所需的polyfill。
  • 全世界有许多不同的浏览器和版本的浏览器在使用,每种浏览器都具备与其余浏览器完全不同的功能集。这会使浏览器开发成为一项艰巨的任务。流行浏览器的最新版本可以完成许多旧浏览器无法完成的任务-但是您可能仍必需支持旧浏览器。通过尝试使用polyfills重新创立缺少的功能,Polyfill.io使支持不同的浏览器变得更简单:您可以在支持或者不支持的浏览器中使用最新和最强大的功能。

通过caniuse查询可知,promise有96.17%的兼容性

image.png

因为Polyfill是非必需的,对少量不支持es6新语法的浏览器才需要加载polyfill,为了百分之3.几的客户让所有客户去加载Polyfill是很没有必要的;

我们可以通过polyfill-service,只给客户返回需要的polyfill
每次客户打开一个页面,浏览器端会请求polyfill-service,polyfill-service会识别客户User Agent,下发不同的polyfill
如何使用动态Polyfill service
通过polyfill.io官方提供的服务,自建polyfill服务https://polyfill.io/v3/url-builder/

或者者通过引入cdn来加载polyfill-service
可以通过加载https://polyfill.io/v3/polyfill.min.js网址来查看不同浏览器User Agent的情况;

webpack4对打包构建速度优化和体积优化的内容到此结束,该文章通过学习程柳锋老师的《玩转webpack》课程实践总结得出,欢迎探讨和指正,以上。


推荐阅读
  • npminstall-Dbabelcorebabelpreset-envbabelplugin-transform-runtimebabelpolyfillbabel-loader ... [详细]
  • 1.移除consol.log()的babel插件安装:npmibabel-plugin-transform-remove-console-D配置:babel.config.js:这 ... [详细]
  • ReactJSUIAnt设计空组件原文:https://w ... [详细]
  • Vue cli2.0 项目中使用Monaco Editor编辑器
    monaco-editor是微软出的一条开源web在线编辑器支持多种语言,代码高亮,代码提示等功能,与VisualStudioCode功能几乎相同。在项目中可能会用带代码编 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • uniapp开发H5解决跨域问题的两种代理方法
    本文介绍了uniapp开发H5解决跨域问题的两种代理方法,分别是在manifest.json文件和vue.config.js文件中设置代理。通过设置代理根域名和配置路径别名,可以实现H5页面的跨域访问。同时还介绍了如何开启内网穿透,让外网的人可以访问到本地调试的H5页面。 ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
  • node.jsrequire和ES6导入导出的区别原 ... [详细]
  • 本文讨论了将HashRouter改为Router后,页面全部变为空白页且没有报错的问题。作者提到了在实际部署中需要在服务端进行配置以避免刷新404的问题,并分享了route/index.js中hash模式的配置。文章还提到了在vueJs项目中遇到过类似的问题。 ... [详细]
  • loader资源模块加载器webpack资源模块加载webpack内部(内部loader)默认只会处理javascript文件,也就是说它会把打包过程中所有遇到的 ... [详细]
  • 一、路由首先需要配置路由,就是点击good组件进入goodDetail组件配置路由如下{path:goodDetail,component:goodDetail}同时在good组件中写入如下点击事件,路由中加入 ... [详细]
  • 必须先赞下国人npm库作品:node-images(https:github.comzhangyuanweinode-images),封装了跨平台的C++逻辑,形成nodejsAP ... [详细]
  • 1、PLSQLDeveloper记住登陆密码在使用PLSQLDeveloper时,为了工作方便希望PLSQLDeveloper记住登录Oracle的用户名和密码&#x ... [详细]
  • v8对象机制1.概述v8中每一个API对象都对应一个内部实现对象(堆对象)2.对象创建过程(1)v8::internal::Factory类: ... [详细]
author-avatar
idc01
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有