配置最佳实践,塑造打包优化

Webpack 4 配置最佳实践

2018/06/22 · JavaScript
· webpack

原作出处:
Zindex   

Webpack 4 发表已经有一段时间了。Webpack 的版本号已经到来了
4.12.x。但因为 Webpack
官方还向来不形成搬迁指南,在文档层面上还兼具欠缺,大部分人对升级 Webpack
依旧贰只雾水。

而是 Webpack
的开发组织已经写了有个别零星的篇章,官网上也有了新版配置的文档。社区中有些开发者也早就成功试水,升级到了
Webpack 4,并且总括成了博客。所以我也毕竟去打听了 Webpack 4
的具体意况。以下正是自笔者对搬迁到 Webpack 4 的一对经历。

正文的根本在:

  • Webpack 4 在配备上带来了什么样惠及?要动员搬迁须要修改配置文件的怎么内容?
  • 事先的 Webpack 配置最佳实践在 Webpack 4 那一个本子,还适用吗?

var path = require(‘path’)
var utils = require(‘./utils’)
var webpack = require(‘webpack’)
var config = require(‘../config’)
var merge = require(‘webpack-merge’)
var baseWebpackConfig = require(‘./webpack.base.conf’)
var HtmlWebpackPlugin = require(‘html-webpack-plugin’)

浅谈React + Webpack 塑造打包优化,reactwebpack

本文介绍了React + Webpack 营造打包优化,分享给我们,具体如下:

应用 babel-react-optimize 对 React 代码进行优化

自小编批评没有运用的库,去除 import 引用

按需打包所用的类库,比如 lodash 、 echart 等

lodash 能够应用babel-plugin-lodash 实行优化。

亟需专注的是

在 babel-react-optimize 中动用了
babel-plugin-transform-react-remove-prop-types
那个插件。平常状态下,要是您在代码中尚无引用到零部件的 PropTypes
,则一心没难题。就算您的零件用到了,那么使用该插件大概会促成难题。

具体见:

Webpack 创设打包优化

Webpack 创设打包存在的标题至关心重视要集中于上面三个方面:

  1. Webpack 构建速度慢
  2. Webpack 打包后的文书体量过大

Webpack 创设速度慢

能够应用 Webpack.DDLPlugin , HappyPack 来增进营造速度。具体参见小铭在
DMP DDLPlugin 的文书档案。原来的作品如下:

Webpack.DLLPlugin

加上一个 webpack.dll.config.js
关键是用到三个 DllPlugin 插件,把部分第3方的财富独立包装,同时停放二个manifest.json 配置文件中,

这么在组件中立异后,就不会再度 build 这一个第贰方的资源,

  1. 并且独立布置 dll/vendors.js 文件,提供给 webpack.dll.config.js
  2. 修改 package.json

在 scripts 中添加: “dll”: “webpack –config webpack.dll.config.js
–progress –colors “, 。

实施 npm run dll 今后,会在 dll 目录下生产 四个公文 vendor-manifest.json
,vendor.dll.js

配备 webpack.dev.config.js 文件,出席叁个 DllReferencePlugin
插件,并钦命 vendor-manifest.json 文件

new webpack.DllReferencePlugin({
 context: join(__dirname, 'src'),
 manifest: require('./dll/vendor-manifest.json')
})

修改 html

<% if(htmlWebpackPlugin.options.NODE_ENV ==='development'){ %>
 <script src="dll/vendor.dll.js"></script>
<% } %>

在意,须求在 htmlWebpackPlugin 插件中配备 NODE_ENV 参数

Happypack

通过二十四线程,缓存等办法升高 rebuild 功效

在 webpack.dev.config.js 中针对分裂的能源创制多个 HappyPack, 比如 js 二个,less 1 个,并设置好 id

new HappyPack({
 id: 'js',
 threadPool: happyThreadPool,
 cache: true,
 verbose: true,
 loaders: ['babel-loader?babelrc&cacheDirectory=true'],
}),
new HappyPack({
 id: 'less',
 threadPool: happyThreadPool,
 cache: true,
 verbose: true,
 loaders: ['css-loader', 'less-loader'],
})

在 module.rules 中配置 use 为 happypack/loader, 设置 id

{
 test: /\.js$/,
 use: [
 'happypack/loader?id=js'
 ],
 exclude: /node_modules/
}, {
 test: /\.less$/,
 loader: extractLess.extract({
 use: ['happypack/loader?id=less'],
 fallback: 'style-loader'
 })
}

减去 Webpack 打包后的文件体量大小

先是要求对我们任何 bundle 举行分析,由什么东西组成及各组成都部队分所占大小。

那边推荐 webpack-bundle-analyzer 。安装后在 webpack.dev.config.js
中丰裕插件即可,就能在每便运转后活动在网站打开分析结果,如下图

plugins.push( new BundleAnalyzerPlugin());

亚洲必赢官网 1

除了,还是能够将打包进程输出成json文件

webpack --profile --json -> stats.json

接下来到上面那七个网站开始展览辨析

  1. webpack/analyse
  2. Webpack Chart

由此地方的图形分析能够掌握得看看,整个 bundle.js
的组成都部队分及相应的尺寸。

缓解 bundle.js 体量过大的解决思路如下:

  1. 延续祖宗门户环境启用压缩等插件,去除不须求插件
  2. 拆分业务代码与第叁方库及国有模块
  3. webpack 开启 gzip 压缩
  4. 按需加载

生儿育女环境启用压缩等插件,去除不要求插件

确认保障在生养环境运维 webpack.DefinePlugin 和
webpack.optimize.UglifyJsPlugin 。

const plugins = [
 new webpack.DefinePlugin({
  'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production')
 }),
  new webpack.optimize.UglifyJsPlugin({
  compress: {
   warnings: false,
   drop_console: false //eslint-disable-line
  }
  })   
]

拆分业务代码与第叁方库及公共模块

鉴于连串的事情代码变更频率很高,而第3方库的代码变化则相对没有那么频率。若是将事情代码和第1库打包到同贰个chunk
的话,在每回创设的时候,哪怕业务代码只改了一行,尽管第壹方库的代码没有产生变化,会促成整个
chunk 的 hash
跟上2回差异。那不是我们想要的结果。大家想要的是,就算第2方库的代码没有转变,那在营造的时候也要保证相应的
hash
没有产生变化,从而能接纳浏览器缓存,更好的增强页面加载品质和浓缩页面加载时间。

之所以得以将第二库的代码单独拆分成 vendor
chunk,与业务代码分离。那样即使业务代码再怎么产生变化,只要第3方库代码没有产生变化,对应的
hash 就不变。

先是 entry 配置五个 app 和 vendor 七个chunk

entry: {
 vendor: [path.join(__dirname, 'dll', 'vendors.js')],
 app: [path.join(__dirname, 'src/index')]
},
output: {
 path: path.resolve(__dirname, 'build'),
 filename: '[name].[chunkhash:8].js'
},

中间 vendros.js 是祥和定义的哪些第壹方库要求纳入 vendor 中,如下:

require('babel-polyfill');
require('classnames');
require('intl');
require('isomorphic-fetch');
require('react');
require('react-dom');
require('immutable');
require('redux');

接下来经过 CommonsChunkPlugin 拆分第叁库

plugins.push(
 // 拆分第三方库
 new webpack.optimize.CommonsChunkPlugin({ name: 'vendor' }),
 // 拆分 webpack 自身代码
 new webpack.optimize.CommonsChunkPlugin({
  name: 'runtime',
  minChunks: Infinity
 })
);

地点的配置有多个细节要求注意

  1. 使用 chunkhash 而不用 hash
  2. 独立拆分 webpack 本身代码

使用 chunkhash 而不用 hash

先来探望那二者有什么不相同:

  1. hash 是 build-specific
    ,任何3个文本的改变都会导致编写翻译的结果不一致,适用于开发阶段
  2. chunkhash 是 chunk-specific ,是依据各样 chunk 的剧情计算出的
    hash,适用于生产

从而为了确定保障第1方库不变的情状下,对应的 vendor.js 的 hash
也要维持不变,大家再 output.filename 中应用了 chunkhash

独自拆分 webpack 自己代码

Webpack 有个已知难题:

webpack 本身的 boilerplate 和 manifest 代码大概在历次编写翻译时都会生成。

这造成大家只是在 入口文件 改了一条龙代码,但编译出的 vendor 和 entry chunk
都变了,因为它们本身都包蕴这一部分代码。

那是不客观的,因为实际大家的第③方库的代码没变,vendor
不应该在大家工作代码变化时产生变化。

于是大家须要将 webpack 那部分代码分离抽离

new webpack.optimize.CommonsChunkPlugin({
   name: "runtime",
   minChunks: Infinity
}),

中间的 name 只要不在 entry 即可,日常使用 “runtime” 或 “manifest” 。

其它2个参数 minChunks 表示:在传唱公共chunk(commons chunk)
从前所急需包蕴的足足数量的 chunks。数量必须大于等于2,可能个别等于
chunks的数码,传入 Infinity 会立时生成 公共chunk,但中间没有模块。

越来越多关于 CommonChunkPlugin 可以查看 官方文书档案

拆分公共财富

同 上面包车型客车拆分第1方库一样,拆分公共财富得以将公用的模块单独打出几个chunk,你能够设置 minChunk
来摘取是共用多少次模块才将它们抽离。配置如下:

new webpack.optimize.CommonsChunkPlugin({
 name: 'common',
 minChunks: 2,
}),

是不是要求实行这一步优化能够自动根据项目标政工复花费来判定。

开启 gzip

采纳 CompressionPlugin 插件开启 gzip 即可:

// 添加 gzip
new CompressionPlugin({
 asset: '[path].gz[query]',
 algorithm: 'gzip',
 test: /\.(js|html)$/,
 threshold: 10240,
 minRatio: 0.8
})

以上正是本文的全部内容,希望对我们的求学抱有协助,也愿意大家多多协理帮客之家。

+ Webpack 创设打包优化,reactwebpack
本文介绍了React + Webpack 营造打包优化,分享给我们,具体如下: 使用
babel-react-optimize 对 React 代…

亚洲必赢官网 ,本文介绍了React + Webpack 营造打包优化,分享给大家,具体如下:

Webpack 4 事先的 Webpack 最佳实践

这里以 Vue 官方的 Webpack 模板
vuejs-templates/webpack
为例,说说 Webpack 4 事先,社区里相比较成熟的 Webpack
配置文件是怎么协会的。

//
用于从webpack生成的bundle中提取文本到特定文件中的插件
//
能够抽取出css,js文件将其与webpack输出的bundle分离

使用
babel-react-optimize对
React 代码举行优化

区分开发和生育环境

约莫的目录结构是那般的:

+ build + config + src

1
2
3
+ build
+ config
+ src

在 build 目录下有多少个 webpack 的安顿。分别是:

  • webpack.base.conf.js
  • webpack.dev.conf.js
  • webpack.prod.conf.js
  • webpack.test.conf.js

那分别对应开发、生产和测试环境的配置。当中 webpack.base.conf.js
是局地公共的配备项。大家运用
webpack-merge
把这个集体配置项和环境特定的安顿项 merge
起来,成为多少个完好无损的配置项。比如 webpack.dev.conf.js 中:

‘use strict’ const merge = require(‘webpack-merge’) const
baseWebpackConfig = require(‘./webpack.base.conf’) const
devWebpackConfig = merge(baseWebpackConfig, { … })

1
2
3
4
5
6
7
‘use strict’
const merge = require(‘webpack-merge’)
const baseWebpackConfig = require(‘./webpack.base.conf’)
 
const devWebpackConfig = merge(baseWebpackConfig, {
   …
})

那四个条件不仅有一些安排不一样,更首要的是,每一种配置中用
webpack.DefinePlugin 向代码注入了 NODE_ENV 那一个环境变量。

本条变量在分化条件下有不一样的值,比如 dev 环境下正是development。那几个环境变量的值是在 config
文件夹下的布署文件中定义的。Webpack
首先从安插文件中读取那个值,然后注入。比如那样:

build/webpack.dev.js

plugins: [ new webpack.DefinePlugin({ ‘process.env’:
require(‘../config/dev.env.js’) }), ]

1
2
3
4
5
plugins: [
  new webpack.DefinePlugin({
    ‘process.env’: require(‘../config/dev.env.js’)
  }),
]

config/dev.env.js

module.exports ={ NODE_ENV: ‘”development”‘ }

1
2
3
module.exports ={
  NODE_ENV: ‘"development"’
}

有关分歧条件下环境变量具体的值,比如开发环境是 development,生产环境是
production,其实是豪门约定俗成的。

框架、库的笔者,或然是大家的事务代码里,都会有局地基于条件做判断,执行分歧逻辑的代码,比如那样:

if (process.env.NODE_ENV !== ‘production’) { console.warn(“error配置最佳实践,塑造打包优化。!”) }

1
2
3
if (process.env.NODE_ENV !== ‘production’) {
  console.warn("error!")
}

那几个代码会在代码压缩的时候被预执行二次,然后一旦条件表明式的值是
true,那那几个 true
分支里的情节就被移除了。那是一种编写翻译时的死代码优化。那种差距差别的条件,并给环境变量设置差别的值的履行,让大家打开了编写翻译时按环境对代码进行针对优化的只怕。

var ExtractTextPlugin = require(‘extract-text-webpack-plugin’)

检查没有采用的库,去除 import 引用

Code Splitting && Long-term caching

Code Splitting 一般须要做这个事情:

  • 为 Vendor 单独包装(Vendor 指第二方的库只怕国有的基础零部件,因为
    Vendor 的变化比较少,单独打包利于缓存)
  • 为 Manifest (Webpack 的 Runtime 代码)单独包装
  • 为差异入口的国有事务代码打包(同理,也是为了缓存和加载速度)
  • 为异步加载的代码打三个公家的包

Code Splitting 一般是透过安排 康芒斯ChunkPlugin
来达成的。贰个顶级的配备如下,分别为 vendor、manifest 和 vendor-async
配置了 CommonsChunkPlugin。

new webpack.optimize.CommonsChunkPlugin({ name: ‘vendor’, minChunks
(module) { return ( module.resource && /.js$/.test(module.resource) &&
module.resource.indexOf( path.join(__dirname, ‘../node_modules’) )
=== 0 ) } }), new webpack.optimize.CommonsChunkPlugin({ name:
‘manifest’, minChunks: Infinity }), new
webpack.optimize.CommonsChunkPlugin({ name: ‘app’, async:
‘vendor-async’, children: true, minChunks: 3 }),

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    new webpack.optimize.CommonsChunkPlugin({
      name: ‘vendor’,
      minChunks (module) {
        return (
          module.resource &&
          /.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, ‘../node_modules’)
          ) === 0
        )
      }
    }),
 
    new webpack.optimize.CommonsChunkPlugin({
      name: ‘manifest’,
      minChunks: Infinity
    }),
 
    new webpack.optimize.CommonsChunkPlugin({
      name: ‘app’,
      async: ‘vendor-async’,
      children: true,
      minChunks: 3
    }),

CommonsChunkPlugin
的风味就是布署相比较难懂,咱们的配置往往是复制过来的,那些代码基本上成了模版代码(boilerplate)。假诺Code Splitting 的渴求简单倒好,倘诺有相比较特殊的渴求,比如把分歧入口的
vendor 打差异的包,那就很难布置了。总的来说配置 Code Splitting
是三个比较难受的工作。

而 Long-term caching
策略是这么的:给静态文件一个十分长的缓存过期岁月,比如一年。然后在给文件名里加上贰个hash,每趟创设时,当文件内容改动时,文件名中的 hash
也会转移。浏览器在依据文件名作为文件的标识,所以当 hash
改变时,浏览器就会另行加载这一个文件。

Webpack 的 Output 选项中能够配备文件名的 hash,比如那样:

output: { path: config.build.assetsRoot, filename:
utils.assetsPath(‘js/[name].[chunkhash].js’), chunkFilename:
utils.assetsPath(‘js/[id].[chunkhash].js’) },

1
2
3
4
5
output: {
  path: config.build.assetsRoot,
  filename: utils.assetsPath(‘js/[name].[chunkhash].js’),
  chunkFilename: utils.assetsPath(‘js/[id].[chunkhash].js’)
},

var env = process.env.NODE_ENV === ‘testing’
? require(‘../config/test.env’)
: config.build.env

按需打包所用的类库,比如 lodash 、 echart 等

Webpack 4 下的极品实践

// 合并基础的webpack配置
var webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true
})
},

lodash
可以采取babel-plugin-lodash拓展优化。

Webpack 4 的变与不变

Webpack 4 这么些版本的 API 有一对 breaking
change,但不意味着说那么些版本就产生了石破天惊的浮动。其实变化的点唯有多少个。而且假若您精心询问了那一个生成,你势必会弹冠相庆。

搬迁到 Webpack 4 也只供给检查一下
checklist,看看这几个点是或不是都掩盖到了,就足以了。

devtool: config.build.productionSourceMap ? ‘#source-map’ : false,
// 配置webpack的输出
output: {
// 编写翻译输出目录
path: config.build.assetsRoot,
// 编写翻译输出文件名格式
filename: utils.assetsPath(‘js/[name].[chunkhash].js’),
//
没有点名输有名的文书输出的文本名格式
chunkFilename: utils.assetsPath(‘js/[id].[chunkhash].js’)
},

急需注意的是

支出和生产条件的分别

Webpack 4 引入了 mode
那一个选项。这一个选项的值能够是 development 也许 production。

安装了 mode 之后会把 process.env.NODE_ENV 也设置为 development 或者production。然后在 production 方式下,会暗许开启 UglifyJsPlugin
等等一堆插件。

Webpack 4 扶助零铺排利用,能够从命令行钦点 entry
的地点,如若不钦点,便是 src/index.js。mode
参数也足以从命令行参数字传送入。那样有个别常用的生产条件打包优化都得以直接启用。

大家须求注意,Webpack 4
的零配置是有限度的,如若要抬高本身想加的插件,或许要加多个entry,仍旧须要一个计划文件。

即使那样,Webpack 4
在各样方面都做了着力,努力让零配置能够做的政工越多。那种内置优化的点子使得我们在档次运行的时候,能够把首要精力放在工作支付上,等中期业务变复杂过后,才须要关爱配置文件的编写。

在 Webpack 4 推出 mode
这几个选项从前,假使想要为分歧的支付环境塑造不相同的营造选项,我们只可以通过树立五个Webpack 配置且分别设置分化的条件变量值那种形式。那也是社区里的超级实践。

Webpack 4 推出的 mode
选项,其实是一种对社区中最佳实践的收受。那种思路作者是很同情的。开源项目来自于社区,在社区中成长,从社区中接收养分,然后回报社区,那是2个良性循环。近日本人在司空见惯前端项目中都看来了就像的可行性。接下来要讲的此外几个Webpack 4 的特点也是和社区的上报离不开的。

那正是说上文中介绍的运用三个 Webpack
配置,以及手动环境变量注入的法子,是不是在 Webpack 4
下就不适用了吗?其实不然。在Webpack 4
下,对于多个自重的档次,大家照样亟待多少个分裂的计划文件
。假若大家对为测试环境的打包做一些相当处理,大家还索要在这么些配置文件里用
webpack.DefinePlugin 手动注入 NODE_ENV 的值(比如 test)。

Webpack 4 下倘诺须要一个 test 环境,那 test 环境的 mode 也是
development。因为 mode
唯有付出和生产三种,测试环境应该是属于开发阶段。

// 配置webpack插件

在 babel-react-optimize 中使用了
babel-plugin-transform-react-remove-prop-types
这几个插件。平常意况下,假诺您在代码中尚无引用到零部件的 PropTypes
,则完全没难点。要是你的机件用到了,那么使用该插件恐怕会招致难题。

其三方库 build 的选项

在 Webpack 3 时日,我们必要在生产环境的的 Webpack 配置里给第①方库设置
alias,把这些库的门径设置为 production build
文件的门路。以此来引入生产版本的依赖。

譬如说那样:

resolve: { extensions: [“.js”, “.vue”, “.json”], alias: { vue$:
“vue/dist/vue.runtime.min.js” } },

1
2
3
4
5
6
resolve: {
  extensions: [".js", ".vue", ".json"],
  alias: {
    vue$: "vue/dist/vue.runtime.min.js"
  }
},

在 Webpack 4 引入了 mode 之后,对于一些信赖,大家得以毫不配置
alias,比如 React。React 的进口文件是那般的:

‘use strict’; if (process.env.NODE_ENV === ‘production’) {
module.exports = require(‘./cjs/react.production.min.js’); } else {
module.exports = require(‘./cjs/react.development.js’); }

1
2
3
4
5
6
7
‘use strict’;
 
if (process.env.NODE_ENV === ‘production’) {
  module.exports = require(‘./cjs/react.production.min.js’);
} else {
  module.exports = require(‘./cjs/react.development.js’);
}

那般就落实了 0 配置活动选择生产 build。

但半数以上的第二库并从未做那些进口的环境判断。所以那种状态下大家依然供给手动配置
alias。

plugins: [
//
new webpack.DefinePlugin({
‘process.env’: env
}),

具体见:

Code Splitting

Webpack 4 下还有三个大转移,就是放任了 CommonsChunkPlugin,引入了
optimization.splitChunks 这些选项。

optimization.splitChunks 私下认可是不用安装的。若是 mode 是 production,那Webpack 4 就会张开 Code Splitting。

暗中同意 Webpack 陆只会对按需加载的代码做分割。若是大家需求配备开始加载的代码也进入到代码分割中,能够安装
splitChunks.chunks 为 ‘all’。

Webpack 4 的 Code Splitting
最大的风味正是布置不难(0配置起步),和依照内置规则自动拆分。内置的代码切分的条条框框是那样的:

  • 新 bundle 被七个及以上模块引用,只怕来自 node_modules
  • 新 bundle 大于 30kb (压缩此前)
  • 异步加载并发加载的 bundle 数不能够压倒 5 个
  • 开始加载的 bundle 数无法超出 3 个

简易的说,Webpack
会把代码中的公共模块自动抽出来,变成三个包,前提是那么些包大于 30kb,不然Webpack 是不会挤出公共代码的,因为扩充二次呼吁的血本是不能够忽视的。

切实的作业场景下,具体的拆分逻辑,能够看 SplitChunksPlugin
的文档以及
webpack 4: Code Splitting, chunk graph and the splitChunks
optimization
那篇博客。那两篇文章基本陈列了独具恐怕出现的情况。

若果是普通的应用,Webpack 4 内置的条条框框就足足了。

设就算异样的须要,Webpack 4 的 optimization.splitChunks API也得以满足。

splitChunks 有二个参数叫 cacheGroups,这一个参数近似事先的 CommonChunks
实例。cacheGroups 里每一个对象正是贰个用户定义的 chunk。

事先我们讲到,Webpack 4 内置有一套代码分割的条条框框,那用户也能够自定义
cacheGroups,也便是自定义 chunk。这几个 module 应该被抽到哪些 chunk
呢?那是由 cacheGroups 的抽取范围控制的。种种 cacheGroups
都得以定义本身抽取模块的界定,也便是什么文件中的公共代码会抽取到温馨这个chunk 中。差异的 cacheGroups 之间的模块范围若是有混合,我们能够用
priority 属性控制优先级。Webpack 4
暗中认可的抽取的预先级是低于的,所以模块会优先被抽取到用户的自定义 chunk
中。

splitChunksPlugin 提供了二种控制 chunk 抽取模块范围的法门。一种是 test
属性。这么些天性能够流传字符串、正则可能函数,全部的 module 都会去匹配
test 传入的规则,假设条件适合,就被纳入那么些 chunk
的备选模块范围。要是我们传入的原则是字符串或然正则,那匹配的流程是那样的:首先匹配
module 的途径,然后匹配 module 从前所在 chunk 的 name。

诸如我们想把全数 node_modules 中引入的模块打包成三个模块:

vendors1: { test: /[\/]node_modules[\/]/, name: ‘vendor’, chunks:
‘all’, }

1
2
3
4
5
  vendors1: {
    test: /[\/]node_modules[\/]/,
    name: ‘vendor’,
    chunks: ‘all’,
  }

因为从 node_modules 中加载的借助路径中都涵盖
node_modules,所以那个正则会合作全部从 node_modules 中加载的依赖性。

test 属性能够以 module 为单位决定 chunk
的抽取范围,是一种细粒度相比小的法子。splitChunksPlugin
的第二种控制抽取模块范围的点子正是 chunks 属性。chunks
能够是字符串,比如 ‘all’|’async’|’initial’,分别表示了总体
chunk,按需加载的 chunk 以及初阶加载的 chunk。chunks
也足以是贰个函数,在那些函数里大家得以得到chunk.name。那给了我们透过输入来划分代码的能力。那是一种细粒度相比较大的不二法门,以
chunk 为单位。

举个例证,比如大家有 a, b, c 八个输入。我们盼望 a,b
的集体代码单独打包为 common。也正是说 c 的代码不参加国有代码的细分。

我们得以定义二个 cacheGroups,然后设置 chunks
属性为1个函数,这些函数负责过滤那个 cacheGroups 包涵的 chunk
是怎么样。示例代码如下:

optimization: { splitChunks: { cacheGroups: { common: { chunks(chunk) {
return chunk.name !== ‘c’; }, name: ‘common’, minChunks: 2, }, }, }, },

1
2
3
4
5
6
7
8
9
10
11
12
13
  optimization: {
    splitChunks: {
      cacheGroups: {
        common: {
          chunks(chunk) {
            return chunk.name !== ‘c’;
          },
          name: ‘common’,
          minChunks: 2,
        },
      },
    },
  },

地方配置的趣味正是:我们想把 a,b 入口中的公共代码单独打包为叁个名为
common 的 chunk。使用 chunk.name,我们能够轻松的到位那么些供给。

在上边的图景中,我们精通 chunks
属性能够用来按入口切分几组公共代码。现在我们来看二个稍稍复杂一些的情况:对区别分组入口中引入的
node_modules 中的注重进行分组。

比如大家有 a, b, c, d 多少个入口。我们期待 a,b 的依靠打包为 vendor1,c, d
的信赖打包为 vendor2。

其一供给要求大家对进口和模块都做过滤,所以大家须求动用 test
属性那几个细粒度相比小的艺术。大家的笔触正是,写八个 cacheGroup,一个cacheGroup 的衡量尺度是:假使 module 在 a 或然 b chunk 被引入,并且
module 的途径包括 node_modules,这那几个 module 就应该被打包到 vendors1中。 vendors2 同理。

vendors1: { test: module => { for (const chunk of
module.chunksIterable) { if (chunk.name && /(a|b)/.test(chunk.name)) {
if (module.nameForCondition() &&
/[\/]node_modules[\/]/.test(module.nameForCondition())) { return
true; } } } return false; }, minChunks: 2, name: ‘vendors1’, chunks:
‘all’, }, vendors2: { test: module => { for (const chunk of
module.chunksIterable) { if (chunk.name && /(c|d)/.test(chunk.name)) {
if (module.nameForCondition() &&
/[\/]node_modules[\/]/.test(module.nameForCondition())) { return
true; } } } return false; }, minChunks: 2, name: ‘vendors2’, chunks:
‘all’, }, };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  vendors1: {
    test: module => {
      for (const chunk of module.chunksIterable) {
            if (chunk.name && /(a|b)/.test(chunk.name)) {
                if (module.nameForCondition() && /[\/]node_modules[\/]/.test(module.nameForCondition())) {
                 return true;
             }
            }
       }
      return false;
    },
    minChunks: 2,
    name: ‘vendors1’,
    chunks: ‘all’,
  },
  vendors2: {
    test: module => {
      for (const chunk of module.chunksIterable) {
            if (chunk.name && /(c|d)/.test(chunk.name)) {
                if (module.nameForCondition() && /[\/]node_modules[\/]/.test(module.nameForCondition())) {
                 return true;
             }
            }
       }
      return false;
    },
    minChunks: 2,
    name: ‘vendors2’,
    chunks: ‘all’,
  },
};

// 丑化压缩代码
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true
}),

Long-term caching

Long-term caching 那里,基本的操作和 Webpack 3 是平等的。不过 Webpack 3
的 Long-term caching 在操作的时候,有个小标题,这些题材是有关 chunk
内容和 hash 变化不平等的:

在集体代码 Vendor 内容不变的事态下,添加 entry,恐怕 external
重视,可能异步模块的时候,Vendor 的 hash 会改变

事先 Webpack 官方的特辑里面有一篇小说讲这几个标题:Predictable long term
caching with
Webpack。给出了一个化解方案。

其一方案的中坚就是,Webpack 内部维护了一个自增的 id,各样 chunk 都有二个id。所以当增添 entry 也许别的门类 chunk 的时候,id
就会转移,导致内容从未成形的 chunk 的 id 也爆发了扭转。

对此大家的答应方案是,使用 webpack.NamedChunksPlugin 把 chunk id
变为3个字符串标识符,这么些字符包一般正是模块的相对路径。那样模块的 chunk
id 就能够稳定下来。

亚洲必赢官网 2

这里的 vendors1 就是 chunk id

HashedModuleIdsPlugin
的职能和 NamedChunksPlugin 是一律的,只但是 HashedModuleIdsPlugin
把依据模块相对路径生成的 hash 作为 chunk id,这样 chunk id
会更短。因而在生育中更推荐用 HashedModuleIdsPlugin。

那篇小说说还讲到,webpack.NamedChunksPlugin 只好对常见的 Webpack
模块起功能,异步模块,external 模块是不会起效果的。

异步模块能够在 import 的时候拉长 chunkName 的注释,比如那样:import(/
webpackChunkName: “lodash” / ‘lodash’).then() 那样就有 Name 了

据此大家需求再利用三个插件:name-all-modules-plugin

这一个插件中用到有个别老的 API,Webpack 4 会发出警示,那么些
pr
有新的本子,可是小编不肯定会 merge。大家使用的时候可以直接 copy
那一个插件的代码到大家的 Webpack 配置内部。

做了那么些工作以往,大家的 Vendor 的 ChunkId
就再也不会产生不应该发生的转变了。

 

Webpack 创设打包优化

总结

Webpack 4 的变动主即使对社区中极品实践的选取。Webpack 4 通过新的 API
大大升级了 Code Splitting 的体验。但 Long-term caching 中 Vendor hash
的标题依然不曾化解,须求手动配置。本文首要介绍的正是 Webpack
配置最佳实践在 Webpack 3.x 和 4.x 背景下的异同。希望对读者的 Webpack 4
项目标安排文件组织有所支持。

另外,推荐 SURVIVEJS – WEBPACK
那么些在线教程。那几个课程计算了 Webpack
在实际上付出中的实践,并且把材质更新到了流行的 Webpack 4。

1 赞 4 收藏
评论

亚洲必赢官网 3

// 抽离css文件
new ExtractTextPlugin({
filename: utils.assetsPath(‘css/[name].[contenthash].css’)
}),

Webpack 营造打包存在的题材根本汇聚于上面三个地点:

 

  1. Webpack 营造速度慢
  2. Webpack 打包后的文书体量过大

// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
// see
new HtmlWebpackPlugin({
filename: process.env.NODE_ENV === ‘testing’

Webpack 营造速度慢

? ‘index.html’
: config.build.index,
template: ‘index.html’,
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
//
},

能够动用 Webpack.DDLPlugin , HappyPack 来压实营造速度。具体参见小铭在
DMP DDLPlugin 的文书档案。原作如下:

// necessary to consistently work with multiple chunks via
CommonsChunkPlugin
chunksSortMode: ‘dependency’
}),

Webpack.DLLPlugin

// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: ‘vendor’,
minChunks: function (module, count) {
// any required modules inside node_modules are extracted to vendor

增进二个 webpack.dll.config.js
要害是用到八个 DllPlugin 插件,把某个第1方的财富独立包装,同时停放一个manifest.json 配置文件中,

return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, ‘../node_modules’)
) === 0
)
}
}),
// extract webpack runtime and module manifest to its own file in order
to
// prevent vendor hash from being updated whenever app bundle is updated

如此那般在组件中更新后,就不会再也 build 那个第二方的财富,

new webpack.optimize.CommonsChunkPlugin({
name: ‘manifest’,
chunks: [‘vendor’]
})
]
})

  1. 再正是独立布署 dll/vendors.js 文件,提需求 webpack.dll.config.js
  2. 修改 package.json

//
gzip格局下要求引入compression插件实行削减
if (config.build.productionGzip) {
var CompressionWebpackPlugin = require(‘compression-webpack-plugin’)
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: ‘[path].gz[query]’,
algorithm: ‘gzip’,
test: new RegExp(
‘\\.(‘ +
config.build.productionGzipExtensions.join(‘|’) +
‘)$’
),

在 scripts 中添加: “dll”: “webpack –config webpack.dll.config.js
–progress –colors “, 。

threshold: 10240,
minRatio: 0.8
})
)
}

实施 npm run dll 未来,会在 dll 目录下生产 八个公文 vendor-manifest.json
,vendor.dll.js

if (config.build.bundleAnalyzerReport) {
var BundleAnalyzerPlugin =
require(‘webpack-bundle-analyzer’).BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

安顿 webpack.dev.config.js 文件,参与一个 DllReferencePlugin
插件,并点名 vendor-manifest.json 文件

module.exports = webpackConfig

new webpack.DllReferencePlugin({
 context: join(__dirname, 'src'),
 manifest: require('./dll/vendor-manifest.json')
})

修改 html

<% if(htmlWebpackPlugin.options.NODE_ENV ==='development'){ %>
 <script src="dll/vendor.dll.js"></script>
<% } %>

小心,须求在 htmlWebpackPlugin 插件中布署 NODE_ENV 参数

Happypack

透过二十八线程,缓存等艺术进步 rebuild 成效

在 webpack.dev.config.js 中针对不一样的财富创立多个 HappyPack, 比如 js 三个,less 1 个,并设置好 id

new HappyPack({
 id: 'js',
 threadPool: happyThreadPool,
 cache: true,
 verbose: true,
 loaders: ['babel-loader?babelrc&cacheDirectory=true'],
}),
new HappyPack({
 id: 'less',
 threadPool: happyThreadPool,
 cache: true,
 verbose: true,
 loaders: ['css-loader', 'less-loader'],
})

在 module.rules 中配置 use 为 happypack/loader, 设置 id

{
 test: /\.js$/,
 use: [
 'happypack/loader?id=js'
 ],
 exclude: /node_modules/
}, {
 test: /\.less$/,
 loader: extractLess.extract({
 use: ['happypack/loader?id=less'],
 fallback: 'style-loader'
 })
}

压缩 Webpack 打包后的文本体量大小

率先必要对大家全部 bundle 实行剖析,由什么东西组成及各组成都部队分所占大小。

此间推荐
webpack-bundle-analyzer
。安装后在 webpack.dev.config.js
中增加插件即可,就能在历次运营后活动在网站打开分析结果,如下图

plugins.push( new BundleAnalyzerPlugin());

亚洲必赢官网 4

除外,仍可以够将打包进度输出成json文件

webpack --profile --json -> stats.json

接下来到上面这四个网站进行分析

  1. webpack/analyse
  2. Webpack Chart

透过下面的图纸分析能够领略得看看,整个 bundle.js
的组成都部队分及相应的高低。

解决 bundle.js 容量过大的消除思路如下:

  1. 生儿育女条件启用压缩等插件,去除不供给插件
  2. 拆分业务代码与第叁方库及公共模块
  3. webpack 开启 gzip 压缩
  4. 按需加载

生育环境启用压缩等插件,去除不供给插件

确认保证在生育环境运转 webpack.DefinePlugin 和
webpack.optimize.UglifyJsPlugin 。

const plugins = [
 new webpack.DefinePlugin({
  'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production')
 }),
  new webpack.optimize.UglifyJsPlugin({
  compress: {
   warnings: false,
   drop_console: false //eslint-disable-line
  }
  })   
]

拆分业务代码与第①方库及集人体模型块

出于品种的业务代码变更频率很高,而第1方库的代码变化则相对没有那么频率。假如将业务代码和第2库打包到同三个chunk
的话,在历次营造的时候,哪怕业务代码只改了一行,尽管第叁方库的代码没有爆发变化,会造成整个
chunk 的 hash
跟上二次分化。那不是大家想要的结果。大家想要的是,假设第3方库的代码没有变动,那在构建的时候也要力保相应的
hash
没有发生变化,从而能选拔浏览器缓存,更好的增强页面加载质量和浓缩页面加载时间。

由此得以将第叁库的代码单独拆分成 vendor
chunk,与事务代码分离。那样即便业务代码再怎么爆发变化,只要第2方库代码没有发生变化,对应的
hash 就不变。

先是 entry 配置两个 app 和 vendor 七个chunk

entry: {
 vendor: [path.join(__dirname, 'dll', 'vendors.js')],
 app: [path.join(__dirname, 'src/index')]
},
output: {
 path: path.resolve(__dirname, 'build'),
 filename: '[name].[chunkhash:8].js'
},

内部 vendros.js 是友善定义的什么样第二方库必要纳入 vendor 中,如下:

require('babel-polyfill');
require('classnames');
require('intl');
require('isomorphic-fetch');
require('react');
require('react-dom');
require('immutable');
require('redux');

然后通过 康芒斯ChunkPlugin 拆分第3库

plugins.push(
 // 拆分第三方库
 new webpack.optimize.CommonsChunkPlugin({ name: 'vendor' }),
 // 拆分 webpack 自身代码
 new webpack.optimize.CommonsChunkPlugin({
  name: 'runtime',
  minChunks: Infinity
 })
);

上面的配备有多个细节须求专注

  1. 使用 chunkhash 而不用 hash
  2. 单独拆分 webpack 本身代码

使用 chunkhash 而不用 hash

先来看看那二者有什么分化:

  1. hash 是 build-specific
    ,任何三个文书的变动都会造成编写翻译的结果不一样,适用于开发阶段
  2. chunkhash 是 chunk-specific ,是基于每种 chunk 的始末总括出的
    hash,适用于生产

从而为了保证第3方库不变的意况下,对应的 vendor.js 的 hash
也要保持不变,大家再 output.filename 中央银行使了 chunkhash

单身拆分 webpack 自己代码

Webpack 有个已知难点:

webpack 本人的 boilerplate 和 manifest 代码只怕在每一回编写翻译时都会变动。

那致使大家只是在 入口文件 改了一条龙代码,但编写翻译出的 vendor 和 entry chunk
都变了,因为它们本人都带有那有的代码。

这是不创立的,因为实在咱们的第1方库的代码没变,vendor
不应有在我们业务代码变化时产生变化。

于是我们需求将 webpack 这一部分代码分离抽离

new webpack.optimize.CommonsChunkPlugin({
   name: "runtime",
   minChunks: Infinity
}),

内部的 name 只要不在 entry 即可,平日使用 “runtime” 或 “manifest” 。

其余多少个参数 minChunks 表示:在传唱公共chunk(commons chunk)
从前所急需包罗的足足数量的 chunks。数量必须超过等于2,或然不难等于
chunks的数据,传入 Infinity 会马上生成 公共chunk,但当中没有模块。

越多关于 CommonChunkPlugin 能够查看
法定文书档案

拆分公共财富

同 上边的拆分第叁方库一样,拆分公共能源得以将公用的模块单独打出1个chunk,你能够安装 minChunk
来摘取是共用有些次模块才将它们抽离。配置如下:

new webpack.optimize.CommonsChunkPlugin({
 name: 'common',
 minChunks: 2,
}),

是或不是要求开始展览这一步优化能够活动依照项目的事情复开销来判断。

开启 gzip

利用 CompressionPlugin 插件开启 gzip 即可:

// 添加 gzip
new CompressionPlugin({
 asset: '[path].gz[query]',
 algorithm: 'gzip',
 test: /\.(js|html)$/,
 threshold: 10240,
 minRatio: 0.8
})

如上就是本文的全体内容,希望对大家的求学抱有扶助,也可望大家多多辅助脚本之家。

你也许感兴趣的篇章:

  • vue
    webpack打包优化操作技能
  • vue-cli
    webpack2项目打包优化分享
  • webpack4.0打包优化策略整理小结
网站地图xml地图