开篇:Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。
webpack的特点:
- 丰富的插件,方便进行开发工作
- 大量加载器,可以加载各种静态资源
- 代码分割,提供按需加载的能力
- 发布工具
主要概念: entry, output,loader,plugin,mode,brower compatibility, env
基本配置
一般项目的webpack配置文件,webpack.config.js,它是一个commonjs模块
const path = require('path');
module.exports = {
entry: './main.js', // 配置入口
output: {
filename: 'app.js', // 配置输出
path: path.resolve(__dirname, 'dist')
}
}
1 入口文件entry
入口文件可以是单个或者多个
entry: './main.js'
entry:{
bundle1: './main1.js',
bundle2: './main2.js',
},
output: {
filename: '[name].js' // 此时的输出[name]为文件名,即上面的bundle1,2
}
可以配合htmlWebpackPlugin,配置使用模板文件,即index.html
// webpack.config.js
const htmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
new htmlWebpackPlugin({
title: 'ddd',
name: 'qqq',
template: 'index.html'
})
]
<div><%= htmlWebpackPlugin.options.name%></div>
2 输出output
即最终结果的输出配置,输出的path必须是绝对路径
output: {
// 单入口
filename: 'main.js', // 输出文件名
path: path.resolve(__dirname, "dist"), // 输出文件到磁盘目录,必须是绝对路径
// 存在多入口时,可以使用占位符的写法
filename: '[name].js', // hash chunkhash contenthash
path: path.resolve(__dirname, "dist")
}
如果在编译时,不知道最终输出文件的 publicPath 是什么地址,则可以将其留空,并且在运行时通过入口起点文件中的 webpack_public_path 动态设置。
__webpack_public_path__ = myRuntimePublicPath;
下面会列出几个输出文件名hash模式的配置,请前往webpack官网查看更多配置。
2.1 hash
即在输出的文件中添加哈希值,使每一次构建生成的哈希值都不一样
filename: '[name]-[hash:6].js' // 表示6位哈希后缀
2.2 chunkhash
为实现缓存效果, 需要另外一种hash计算方式,也就是chunkhash,它根据不通话的入口文件进行以来文件解析,构建对应的chunk,生成对应的hash值。生产环境中,公共库和程序入库文件区分开,单独打包更贱,接着采用chunkhash的方式,那么,只要不更改公共库,其hash值不会受影响,例如
entry:{
main: path.join(__dirname, './index.js'),
vendor: ['vue']
},
output:{
path: path.join(__dirname, './dist'),
publicPath: '/dist/',
filename: 'bundle.[chunkhash].js'
}
2.3 contenthash
表示文件内容产生的hash值,内容不同产生的contenthash也不一样,例子就是css的打包,通常项目中的做法都是将css抽离出来作为css文件引用,内容相同,contenthash保持不变
const miniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports= {
module:{
rules:[
{
test: /\.css$/,
use: [
miniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
plugins: [
new miniCssExtractPlugin({
filename: 'main.[contenthash:8].css'
})
]
}
如果对css使用了chunkhash之后,它与依赖它的chunk共用chunkhash,测试后会发现,css与js文件名的chunkhash值是一样的,如果修改了js文件,js的hash值会变化,css的文件名的hash还是和变化后的js文件的hash值一样,如果修改了css文件,也会导致重新构建,css的hash值和js的hash值还是一样的,即使js文件没有被修改。这样会导致缓存作用失效,所以css文件最好使用contenthash。
3 mode
告知wepack使用相对应模式的内置优化
mode = 'production': 'none' | 'production' | 'development'
设置方法,可以再config文件中直接设置, 或者在cli命令行中参数传递,如:
webpack --mode=production
下面是各种默认优化
4 module
即通过规则匹配loader进行编译的结果
5 chunk
webpack根据模块依赖,文件依赖引用关系,生成的文件
6 bundle
webpack通过loader或其他配置处理chunk文件,会输出bundle文件,最后经过加载和编译得到最终结果文件,放在浏览器或者其他环境中去加载使用
7 chunk和bundle,module区别,概念理解
- module,即我们写的代码,初始阶段
- 当我们写的 module 源文件传到 webpack 进行打包时,webpack 会根据文件引用关系生成chunk文件,webpack会对这个chunk文件进行一些操作
- webpack处理好chunk文件后,最终会输出bundle文件,这个bundle文件包含了经过加载和编译的最终源文件,放在浏览器中去加载使用,我们直接写出来的是 module,webpack 处理时是 chunk,最后生成浏览器可以直接运行的 bundle。
8 resolve
配置模块如何解析。例如,当在 ES2015 中调用 import 'lodash',resolve 选项能够对 webpack 查找 'lodash' 的方式去做修改(查看模块)。
8.1 alias
创建 import 或 require 的别名,来确保模块引入变得更简单。例如,一些位于 src/ 文件夹下的常用模块,防止多层级的../../相对引入:
const path = require('path')
resolve:{
alias:{
'@': path.resolve(__dirname, 'src'),
'react-dom': '@hot-loader/react-dom',
}
}
// ....index.jsx
import reactDom from 'react-dom';
import getPrice from '@/utils/getPrice'
8.2 extensions
官方文档上的解释有点过于官方,不是很好理解,但是大概的用途或者意思如下
resolve:{
alias:{
'@': path.resolve(__dirname, 'src'),
'react-dom': '@hot-loader/react-dom',
},
extensions: ['.vue', '.json', '.js', '.mjs']
}
import tik from '@/utils/tik'
// 此时webpack解析的时候,会去目录下面优先寻找tik.vue,找不到的话按照上述数组的顺序进行文件查找,所以上述目录也算是一个排序, 也可以省去我们引入的时候需要多些后缀名的问题
9 externals
排除bundle中的依赖引用,而是从运行环境中区获取外部的拓展依赖 如下,能对Amap进行一个esmodule方式的直接引用,而Amap实际上是通过运行时cdn的形式引入的
// webpack.config.js
externals: {
AMap: 'AMap',
AMapUI: 'AMapUI',
},
// ....index.jsx
import Amap frpm 'Amap'
关于loader和plugin单独开篇来解读