webpack4打包优化(HappyPack、thread

您所在的位置:网站首页 佳能80d电池要充多久 webpack4打包优化(HappyPack、thread

webpack4打包优化(HappyPack、thread

#webpack4打包优化(HappyPack、thread| 来源: 网络整理| 查看: 265

一、速度分析

安装插件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二、体积分析

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

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

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

安装插件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 替代 forEachMap和Set 替代Objectincludes 替代 indexOf()默认使用更快的md4 hash算法 替代 md5算法,md4较md5速度更快webpack AST 可以直接从loader传递给AST,从而减少解析时间使用字符串方法替代正则表达式

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

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

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

可选方案

thread-loader(官方推出)parallel-webpackHappyPackHappyPack

注:因为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-pluginuglifyjs-webpack-pluginterser-webpack-plugin(webpack4.0推荐使用,支持压缩es6代码)npm install terser-webpack-plugin --save-devconst 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 映射到相关的依赖上去

首先使用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》课程实践总结得出,欢迎探讨和指正,以上。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3