section-3.1 Tree Shaking 概念详解
当引入一个模块的时候,只引入需要的代码,而不是所有的代码都打包进去,那么这时候就需要把不需要的代码“摇”掉,这个时候可以使用Tree Shaking
// match.js
export const add = (a, b) => {
console.log(a + b);
}
export const minus = (a, b) => {
console.log(a - b);
}
// index.js
import { add } from './match.js';
add(1, 2);
上面我们在index.js里只需要使用add这个方法,但是打包的时候会发现mian.js里minus依然被打包进去,这个就需要配置webpack对代码进行剔除,在webpack.config.js中添加 optimization(优化)配置,设置 usedExports 为 true
// webpack.config.js
// 为了容易阅读,其他的webpack配置、插件等都被我删除掉,但并非不需要,babel的options也被我挪到.babelre文件里,不贴出来
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}
]
},
optimization: {
// 这里告知webpack,如果没有export导出,则可以移除未使用的导出(不是移除整个模块,只是移除没被用到的export代码)
usedExports: true
}
}
在package.json中添加
"sideEffects": false
如果到这里还不知道package.json各个字段的配置,可以参考:npm的package.json中文文档
这里需要注意,Tree Shaking 只支持 ES Module 模块引入,也就是只支持静态引入,commonJS是不支持的,比如下面这样动态引入是不支持的
const add = require(./match.js)
这个时候看打包后的 main.js ,会发现代码还是被打包出来,这是因为在 development 环境中,代码是不会被剔除的,但会有提示
/*! exports provided: add, minus */
/*! exports used: add */
这个时候我们把配置改成 production ,需要进行下面的设置,把 optimization 配置删除即可
// package.json
// css 文件是 import './index.css',不需要剔除
// babel 也是没有 export 出任何东西的,但也不需要剔除
"sideEffects": ["@babel/polyfill", "*.css"]
section-3.2 Develoment 和 Production 模式的区分打包
对到开发中,需要对dev和prod环境分开处理打包,参考vue中的build,分别建立base/dev/prod三个配置来进行打包处理
webpack.base.js -- 公用的webpack配置
webpack.dev.js -- 开发环境webpack配置
webpack.prod.js -- 生产环境webpackp配置
|- build
|- webpack.base.js
|- webpack.dev.js
|- webpack.prod.js
// webpack.base.config
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
main: './src/index.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, '../dist')
},
module: {
rules: [ //模块打包规则
{
test: /\.js$/,
exclude: /node_modules/, // 如果代码是在node-modules,则排除
loader: "babel-loader" //webpack与babel的桥梁,并不会进行解析
},{
test: /\.(woff|eot|ttf|svg)$/,
use: {
loader: 'file-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'icon-font/'
}
}
},{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
limit: 2048 //是否小于2KB
}
}
},{
test: /\.scss$/,
use: [
'style-loader',
{
loader: "css-loader",
options: {
importLoaders: 2
}
},
'sass-loader',
'postcss-loader']
},{
test: /\.css$/,
use: [
'style-loader',
"css-loader",
'postcss-loader'
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html'
}),
new CleanWebpackPlugin()
],
}
因为我们需要的不是某一个配置文件,而是该文件与base文件合并后的配置,所以需要安装webpack-merge,执行npm i webpack-merge -D
,在 dev 和 prod 两个配置里都加入webpack-merge
// webpack.dev.js
const webpack = require('webpack');
const merge = require('webpack-merge'); // 加入 merge 模块
const commonConfig = require('./webpack.base.js'); // 加入 base 配置
const devConfig = {
mode: "development", // production
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: './dist',
open: true,
proxy: { // 接口代理
'/api': 'http://localhost:80'
},
hot: true, //webpack-dev-server开启热更新
hotOnly: true //html没生效,浏览器不刷新
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
optimization: {
usedExports: true
}
}
module.exports = merge(commonConfig, devConfig); // 合并两者配置并输出
// webpack.prod.js
const merge = require('webpack-merge');
const commonConfig = require('./webpack.base.js');
const prodConfig = {
mode: "production",
devtool: 'cheap-module-source-map'
}
module.exports = merge(commonConfig, prodConfig);
对应的修改package.json文件,来对不同环境执行不同命令,对到里面的--config指定配置文件,自行百度或查看我之前第一章第四节 section-1.4 使用webpack的配置文件
"scripts": {
"start": "webpack-dev-server",
"dev": "webpack-dev-server --config ./build/webpack.dev.js",
"build": "webpack --config ./build/webpack.prod.js"
},
section-3.3&3.4 Webpack 和 Code Splitting
Code Splitting:代码分割,将页面逻辑和依赖分开打包,因为业务逻辑是多变的,依赖一般是不变的(比如使用了loadash/jQuery这些),而且这种做法虽然多了一个请求,但是现代浏览器是并行下载的,对到大的文件分开下载会比直接下载一个大型文件更快
这里以loadash为例(执行npm i loadash -D
下载包)
逻辑代码(dafault),本节没写的index.js代码都是以下这段,以同步加载的形式,下面说的defalut都是这个
// index.js 未做代码分割,会将 loadash 和 业务逻辑打包到一个 js 里,
import _ from 'loadash';
console.log(_.join(['a', 'b', 'c'], '*'));
console.log(_.join(['a', 'd', 'z'], ','));
代码分割也可以手动制作
// loadash.js
import _ from 'loadash';
window._ = _;
// index.js
console.log(_.join(['a', 'b', 'c'], '*'));
console.log(_.join(['a', 'd', 'z'], ','));
// webpack.config.js
entry: {
loadash: './src/loadash.js',
main: './src/index.js'
}
逻辑代码为 dafault,webpack 4 默认支持代码分割配置,具体对到 splitChunks 推荐阅读一下这篇文章
// webpack.config.js
entry: {
main: './src/index.js'
},
optimization: {
splitChunks: {
chunks: 'all'
}
}
这样就完成了对同步代码的代码分割
|- dist
|- index.html
|- main.js
|- vendors~main.js //这个就是分割出来的 loadash
对到异步代码(import),无需做任何配置,会自动进行代码分割,也就是不需要写 optimization
// index.js
// /* webpackChunkName:"loadash" */ 是魔法注释,将这个分割出来的文件起名为ladash
function getComponent() {
return import(/* webpackChunkName:"loadash" */ 'lodash').then(({ default: _}) => { // 以异步的形式加载 loadash
let elm = document.createElement('div');
elm.innerHTML = _.join(['Dell', 'Lee'], '-');
return elm
})
}
getComponent().then(elm => {
document.getElementById('root').appendChild(elm);
})
由于异步加载是实验性做法,babel并不支持,所以这里我们需要安装一个babel官方的代码分割插件 syntax-dynamic-import 的插件,还有一个非官方的代码分割插件“babel-plugin-dynamic-import-webpack”,个人尝试后不可用,或许是因为版本问题,这里不进行深究,执行npm i @babel/plugin-syntax-dynamic-import -D
进行安装
// .babelrc
{
presets: [[
"@babel/preset-env", {
corejs: 3,
useBuiltIns: "usage",
targets: {
chrome: "67"
}
}]
],
plugins: ["@babel/plugin-syntax-dynamic-import"]
}
这样就完成了对异步代码的代码分割
|- dist
|- index.html
|- main.js
|- 0.js //这个就是分割出来的 loadash
对到异步的刚好自己粗心遇到了问题,但编译不会提示跟报错,注意 import('lodash').then(({ default: _})
别写错,因为我把default拼错了,浏览器一直提示 _ 没有模块依赖,然后一直找不到问题,还以为是插件用的不对
section-3.5&3.6 SplitChunksPlugin 配置参数详解
这节主要说一下优化中的代码分割配置,webpack4是默认自带的,除非想用实验性的异步加载模块也被分割出来才需要安装上一节的babel插件
split-chunks-plugin 如果为空(也就是只有一个{}),则默认会有一段配置,具体看官网,这里主要对参数进行说明,例子就不搬了,看官网即可。默认配置主要是这四条规则
- New chunk can be shared OR modules are from the node_modules folder
可共享(多处被引用)或来自 node_modules 中的模块 - New chunk would be bigger than 30kb (before min+gz)
模块大于30kb - Maximum number of parallel requests when loading chunks on demand would be lower or equal to 5
加载模块时,最大的并行请求数大于等于5 - Maximum number of parallel requests at initial page load would be lower or equal to 3
入口文件加载模块时,最大并行请求数大于等于3
optimization: {
splitChunks: { // 代码分割
// 分割条件匹配
chunks: "all", // "async"只对异步代码进行打包 "initial"同步
minSize: 30000, // 大于30k,正确应该是30720才是30k,进行代码分割
minChunks: 1, // 当模块被引入至少一次
maxAsyncRequests: 5, // 只能同时加载5个代码块,大于5的时候,前5个会被分割出来
maxInitialRequests: 3, // 首页(入口文件)最多只能分割3个
automaticNameDelimiter: '~', // 组和文件名直接的拼接符
name: true, // 打包生成的文件名是否有效,如果true则走cacheGroups中的规则命名
// 分组
cacheGroups: { // 缓存组,不会直接打包文件,会把符合组条件的文件先缓存起来,最后再打包成一个模块
vendors: { // 匹配组名,会给打包文件前面加 vendors 入口名
test: /[\\/]node_modules[\\/]/, // 检测是否是在node_modules中
priority: -10, // 优先级,当某个模块同时满足多个组的时候,按照优先级进行分配打包
filename: 'vendors.js' // 会让上面的 automaticNameDelimiter 失效
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true, //如果一个模块已经被打包过,则不再打包
filename: 'common.js'
}
}
}
}
还有一点,上面的filename,如果是异步加载模块是会报错的,因为在运行中babel只能给分割出来的模块暂时命名为数字(runtime时),所以默认配置里并没有该属性
section-3.7 Lazy Loading 懒加载,Chunk 是什么?
vue中有路由,可以通过在路由中使用箭头函数,来让页面资源异步加载
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/pages/home/Home'
// import City from '@/pages/city/City'
// import Detail from '@/pages/detail/Detail'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home // 上面是import同步加载
},{
path: '/city',
name: 'City',
component: () => import('@/pages/city/City')
},{
path: '/detail/:id', // router动态路由
name: 'Detail',
component: () => import('@/pages/detail/Detail')
}
],
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
}
})
其实本质依旧是代码分割,只是分割后的chunk只有在需要的时候才会去加载,而不是进入页面的时候并列下载
async function getComponent() {
const { default: _ } = await import(/* webpackChunkName:"loadash" */ 'lodash');
const elm = document.createElement('div');
elm.innerHTML = _.join(['Dell', 'Lee'], '-');
return elm
}
document.addEventListener('click', () => {
getComponent().then(elm => {
document.getElementById('root').appendChild(elm);
})
})
上面这个例子中,只有点击页面才会去请求分割出来的loadash.js。
对到chunk是什么,说实话我自己都不知道它是什么(应该说我不知道怎么用中文来描述它)
chunk,就是webpack打包后的js文件,或许这叫代码块?
Built at: 2019-05-23 01:02:27
Asset Size Chunks Chunk Names
index.html 349 bytes [emitted]
main.js 35 KiB main [emitted] main
vendors~loadash.js 1.35 MiB vendors~loadash [emitted] vendors~loadash
Entrypoint main = main.js
chunk主要有以下三种:
- webpack.config.js 当中配置的入口文件(entry)是 chunk,可以理解为entry chunk
- 入口文件以及它的依赖文件通过code split (代码分割)出来的也是chunk,可以理解为children chunk
- 通过commonsChunkPlugin创建出来的文件也是chunk,可以理解为commons chunk
webpack4默认自带code splitting 了,已经将CommonsChunkPlugin从webpack v4 legato 中移除,也就是上面优化当中的splitChunks配置
section-3.8 打包分析,Preloading, Prefetching
通过创建 analyze 来查看打包数据分析以及各文件之间的依赖关系
官方提供的三个可视化链接来查看 bundle 分析(bundle analysis),通过在package.json中添加--profile --json > stats.json
来生成stats.json文件,这个文件放到官方提供的bundle分析网页中去查看
"scripts": {
"dev-build": "webpack --profile --json > stats.json --config ./build/webpack.dev.js",
"start": "webpack-dev-server",
"dev": "webpack-dev-server --config ./build/webpack.dev.js",
"build": "webpack --config ./build/webpack.prod.js"
}
预加载(Preloading)和预提取(Prefetching)
// index.js
document.addEventListener('click', () => {
import(/* webpackPrefetch: true, webpackChunkName: "click" */ './click.js').then(({default: func}) => {
func();
})
})
// click.js
function handleClick () {
const elm = document.createElement('div');
elm.innerHTML = "Prefetching Chunk"
document.getElementById('root').appendChild(elm);
}
export default handleClick;
上面这个例子,在加载index.js的时候,页面并不会加载Prefetching Chunk这样的文字,只有在点击后才会出现文字。这样的点击事件理论上其实是不需要在页面加载的时候直接加载的,只有在点击后这个事件代码才有用(真实项目中比如登录框)
webpack的优化理念其实并非文件缓存,而是代码利用率(代码覆盖率),加载的页面只加载有需要的代码,剩余的代码可以在空闲期再去加载,这就是Prefetching。这也就是splitChunks为什么chunks的默认配置项是async而不是all,因为官方希望我们更多的去关注代码覆盖率的问题
因为例子太简单,所以无效代码占据比例较大(真实场景肯定不会是这样的),上图可以看到代码利用率是22.5,如果是直接写在click事件里,代码利用率只有6.6(当然还有一些注释,就不截图了)
Prefeching 其实重点理念是将来可能会用到的代码(也就是跨页面,预先加载后面的流程代码),它实际是在页面头部增加<link rel="prefetch" href="./click.js">,指示浏览器在空闲时间去加载click.js,这样当需要使用的时候直接从 disk cache 里面取,既不影响当前页面的渲染,又提高了其他页面加载渲染的速度
而Preloading便是预加载,实际是在页面头部增加<link rel="preload">,错误地使用Preload实际上会损害性能,造成当前页面的阻塞。因为它是和当前页面并行下载文件的,所以官方推荐的是使用Prefeching
当我做demo的时候发现,preload并没有任何效果,页面头部也没任何挂载,也不会产生任何请求,只有在点击的时候才会加载click.js,也就是说webpackPreload这个配置项可能已经被移除了,即使文档里依然有它的记录,如果有有误请大佬指正
section-3.9 CSS 文件的代码分割
我们对到css/sass/less/stylus,一般在开发环境里都是使用的style-loader,这样的loader会把css in js里的样式直接以style标签的形式插入到页面上。chunk有多少引用到css,则会有多少个style标签,很明显,这样的做法对到线上环境必然是不妥的,这个时候我们就需要把css in js中的样式抽离成单独的文件进行导入,这个时候我们需要使用 MiniCssExtractPlugin
它跟以前webpack3使用的 extract-text-webpack-plugin 相比,最主要的优势在于没有重复的编译(具体等我后面尝试了以后再来修改)
执行npm install --save-dev mini-css-extract-plugin
进行安装,由于其hmr支持度不好(甚至需要reloadAll进行重载),所以这里只对生产环境进行配置,去除style-load,改成MiniCssExtractPlugin.loader,由于css不同于less/scss/stylus,并不需要配置importLoaders来进行loader流程重复,所以拆分成两块
当然你不在乎那点编译性能其实这样匹配也行/\.(sa|sc|c)ss$/
。毕竟css在这些loader里也能正确识别
// webpack.prod.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // css拆分成单文件
module: {
rules: [
{
test: /\.scss$/,
use: [
// 'style-loader',
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
importLoaders: 2
}
},
'sass-loader',
'postcss-loader'
]
},{
test: /\.css$/,
use: [
// 'style-loader',
MiniCssExtractPlugin.loader,
"css-loader",
'postcss-loader'
]
}
]
}
对到线上环境,我们需要的不仅是文件独立,还需要代码合并与压缩(默认会合并,但只是简单的写在同一个文件里,比如两个文件都有一个.style类名的样式,这个文件里会有两个.style的类名样式)
.style{
background-color: darkseagreen;
}
.style{
font-size: 18px;
}
这里需要使用 OptimizeCssAssetsPlugin 插件来对代码进行合并压缩
执行 npm install --save-dev optimize-css-assets-webpack-plugin
安装,添加配置,plugins里是为了配置出sourceMap,否则默认不会生成sourceMap,参考文章:mini-css-extract-plugin搭配optimize-css-assets-webpack-plugin不生成source-map问题,当然以个人经验来讲没必要,因为我们会对less/scss/stylus做sourceMap,但应该没见过有人为css做sourceMap吧
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); // css压缩
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[name].chunk.css'
}),
new OptimizeCssAssetsPlugin({
// 生成sourceMap
cssProcessorOptions: {
map: {
// 不生成内联映射,生成sourceMap
inline: false,
// 向css文件添加source-map路径注释
// 如果没有此项压缩后的css会去除source-map路径注释
annotation: true
}
}
})
],
optimization: {
minimizer: [new OptimizeCssAssetsPlugin({})] // 压缩代码
}
section-3.10 Webpack 与浏览器缓存( Caching )
我们在更改代码后,需要用户重新下载新的业务代码,但由于浏览器会有缓存问题,这样会导致用户的文件得不到更新,甚至出bug。在最早以前,是人为手工的为代码文件名添加后缀或时间戳,后来历史演变(原本想说一下,然后全部被我删掉了)现在是添加文件名加hash的形式
而因为我们做了代码分割,所以没更改到的文件不需要变,只有改变的才需要去重新下载,其他的走缓存即可,因此我们需要使用 contenthash 占位符来标识文件,如字面意思,内容哈希,内容不变哈希也不变,还有其他的占位符自行查看文档
// webpack.prod.js
output: {
filename: '[name]_[contenthash].js',
chunkFilename: '[name]_[contenthash].js'
},
webpack通过 runtime 和 manifest 来加载和解析模块,而对到如何清楚模块发生变化,这里我估计得去找--watch那里挖
毕竟,按照文档的说法:runtime负责的是连接模块所需的加载和解析逻辑, Manifest负责解析和加载模块,import 或 require 语句转换为 __webpack_require__
方法,此方法指向模块标识符(module identifier)。通过使用 manifest 中的数据,runtime 将能够查询模块标识符,检索出背后对应的模块。
一个负责查找对应关系,一个负责转换引用方式来让runtime识别出对应的模块,这两个都不是监听文件变化的,所以是的,我看完了以后似懂非懂,还去查找一些博文看了一下,基本可以确定,这两个名词简单来说就是用来确定文件应该去加载哪些模块的,跟监听变化没有半毛钱关系,那块估计去找 --watch或hmr相关的应能找出点东西来
为什么扯这个,因为旧的webpack(不知道哪一版之前),即使文件没变化,hash也会发生变化,导致每次都得重新下载所有文件,这样缓存策略就不够好了,需要将manifest独立出一个文件来,没更改的文件hash才不会发生变化
// webpack.prod.js
optimization: {
runtimeChunk: {
name: "chunkName"
}
}
最近电脑坏了拿去修,需要15到20天…现在迫不得已拿出5年前的笔记本暂行扛着,打字显示出来的速度都跟不上我打字速度…好想买台19款 imac…
section-3.11 Shimming 的作用
Shimming,也就是垫片,其作用可以简单的理解为帮我们处理一些全局的东西。
假设我们的项目是基于jq和loadash写的业务逻辑,到处都需要用到,那么这个时候我们借助webpack自带的ProvidePlugin,便可以简单的在全局中引入对应的库文件了
// webpack.base.js
const webpack = require('webpack');
plugins: [
new webpack.ProvidePlugin({
_: 'lodash'
})
]
// import _ from 'lodash'; //已经不需要在头部先引入loadash了,ProvidePlugin悄悄帮我们做这一步
console.log(_.join(['a', 'b', 'c'], '*'));
console.log(_.join(['a', 'd', 'z'], ','));
本质上,我们所做的,就是告诉 webpack
如果你遇到了至少一处用到 lodash 变量的模块实例,那请你将 lodash package 包引入进来,并将其提供给需要用到它的模块。
如果我们项目里多次用到某个库中的方法,我们甚至可以将这个方法也做成垫片
// webpack.base.js
const webpack = require('webpack');
plugins: [
new webpack.ProvidePlugin({
_: 'lodash',
join: ['lodash', 'join'] // 这样就不需要写成 _.join()
})
]
一些传统的模块依赖的 this 指向的是 window 对象。但是当模块运行在 CommonJS 环境下这将会变成一个问题,也就是说此时的 this 指向的是 module.exports。(看不懂的话随便在入口文件打印一下this,由于我们使用的都是import的方式,这些模块中的全局this都是指向的module.exports)
这个时候我们需要借助 imports-loader 来修改这个行为
执行npm i imports-loader -D
// webpack.base.js
{
test: /\.js$/,
exclude: /node_modules/, // 如果代码是在node-modules,则排除
use: [
{
loader: 'babel-loader' //webpack与babel的桥梁,并不会进行解析
},{
loader: 'imports-loader?this=>window'
}
]
}
// index.js
// 下面这两句能直接引发bug,this不指向moudule了,变成了undefined
// 特地记录一下,后面去查一下怎么解决,总不可能说一个文件为了this重新指向window就不去import任何东西吧
// import './style.css'; // css in js
// import _ from 'lodash';
console.log(_.join(['a', 'b', 'c'], '*'));
console.log(_.join(['a', 'd', 'z'], ','));
console.log(this) // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
关于打包后 this 变成 undefined 种种问题:
https://blog.csdn.net/sinat_17775997/article/details/70495891
https://www.jianshu.com/p/a182d4f75e88
section-3.12 环境变量的使用方法
webpack 命令行 环境配置 中,通过设置 --env
可以使你根据需要,传入尽可能多的环境变量。在 webpack.config.js
文件中可以访问到这些环境变量。例如,--env.production
或 --env.NODE_ENV=local
现在将原本的webpack.base.js/webpack.dev.js/webpack.prod.js三个进行改写,删除两个环境配置中的merge,将环境配置指向统一的webpack.base.js中,更改package.json(为了跟之前做区分,新增两条命令,原来命令行继续保留,原配置文件也保留,复制新增原配置目录commonbuild)
// package.json
"scripts": {
"commondev": "webpack-dev-server --env.dev --config ./commonbuild/webpack.base.js",
"commonprod": "webpack --env.prod --config ./commonbuild/webpack.base.js"
}
// webpack.prod.js
// const merge = require('webpack-merge');
// const commonConfig = require('./webpack.base.js');
module.exports = prodConfig;
// webpack.dev.js
// const merge = require('webpack-merge');
// const commonConfig = require('./webpack.base.js');
module.exports = devConfig;
// webpack.base.js
const merge = require('webpack-merge');
const devConfig = require('./webpack.dev.js');
const prodConfig = require('./webpack.prod.js');
const baseConfig = {
entry: {
main: './src/index.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/, // 如果代码是在node-modules,则排除
use: {loader: 'babel-loader'} //webpack与babel的桥梁,并不会进行解析
},{
test: /\.(woff|eot|ttf|svg)$/,
use: {
loader: 'file-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'icon-font/'
}
}
},{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
limit: 2048 //是否小于2KB
}
}
}
]
},
performance: false, // 不提示性能警告
optimization: {
usedExports: true,
runtimeChunk: {
name: "chunkName"
},
splitChunks: {
chunks: "all", // "async"只对异步代码进行打包 "initial"同步
minSize: 30000, // 大于30k,正确应该是30720才是30k,进行代码分割
minChunks: 1, // 当模块被引入至少一次
maxAsyncRequests: 5, // 只能同时加载5个代码块,大于5的时候,前5个会分割
maxInitialRequests: 3, // 首页(入口文件)最多只能分割3个
automaticNameDelimiter: '~', // 文件名,组和文件名直接的拼接符
name: true, // 打包生成的文件名是否有效,如果true则走cacheGroups中的规则命名
cacheGroups: { // 缓存组,不会直接打包文件,会把符合组条件的文件打包成一个模块
vendors: { // 匹配组名,会给打包文件前面加vendors~入口名
test: /[\\/]node_modules[\\/]/, // 检测是否是在node_modules中
priority: -10, // 优先级,当某个模块同时满足多个组的时候,按照优先级进行分配打包
name: "vendors"
// filename: 'vendors.js' // 会让上面的 automaticNameDelimiter 失效
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true, //如果一个模块已经被打包过,则不再打包
// filename: 'common.js'
}
}
}
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html' //猜测,这个是根据package.json目录?
}),
new CleanWebpackPlugin(),
new webpack.ProvidePlugin({ // 自动加载模块,全局垫片
_: 'lodash'
})
],
}
module.exports = (env) => {
// 这里的env.dev就是package.json里传进来的环境参数
if(env.dev) return merge(baseConfig, devConfig);
if(env.prod) return merge(baseConfig, prodConfig);
}
--env参数语法
如果需要对环境进行复制的判断配置,这种全局环境的配置方法将会非常有用
网友评论