基本搭建
1 | npm init -y |
一顿yes直接搭建好基本的node环境
1 | yarn install webpack webpack-cli --save-dev |
安装webpack, webpack-cli, 由于是开发环境需要,加上–save-dev
1 | module.exports = { |
新建index.js, 新建webpack.config.js, webpack默认读取webpack.config.js导出的对象.
1 | npx webpack |
webpack默认读取根路径下的webpack.config.js文件, npm5.2之后提供了自动安装npx ,会自动查找当前依赖包中的可执行文件并执行
context
定义了打包的基础目录, 一旦设置, 那么接下来配置设置的根路径将会是配置的基础目录。
1 | const path = require('path'); |
entry
文件打包的起点
- 可以传入数组, 传入数组从前往后依次进行打包, 包名为main
- 可以传入对象, 每个键作为打包的包名, 值为打包的资源路径或者打包的描述符多入口可以设置打包依赖, 减少包体积, 避免重复使用相同的包
1
2
3
4
5
6
7
8
9
10
11
12
13
14module.exports = {
//...
entry: './index.js'
};
// 也可以自定义包名
module.exports = {
//...
entry: {
app: './app.js',
home: { import: './contact.js', filename: 'pages/[name][ext]' },
about: { import: './about.js', filename: 'pages/[name][ext]' }
}
};可以动态引入, 将在make事件中触发1
2
3
4
5
6
7module.exports = {
//...
entry: {
app: { import: ['./app.js', './app2.js'], dependOn: 'react-vendors' },
'react-vendors': ['react', 'react-dom', 'prop-types']
}
};1
2
3
4module.exports = {
//...
entry: () => './demo' // () => new Promise((resolve) => resolve(['./demo', './demo2']))
};
mode
打包模式分为development和production
1 | module.exports = { |
可以在打包时决定
1 | npx webpack --mode=development |
如果我们需要在不同模式下进行定义不同的打包行为, 我们可以定义为函数, 使用方法如下。
开发环境打包文件webpack.base.js
1 | module.exports = (options) => ({ |
主打包文件webpack.dev.js
1 | module.exports = require('./webpack.base.js')({ |
通过配置进行打包, 选择对应的打包文件
1 | webpack --config webpack.dev.js |
output
打包的输出形态, 包括bundle和静态文件
filename
filename 是一个很常见的配置,就是对应于 entry 里面的输入文件。
这里可以使用可替换模板字符串的形式定义输出的打包文件名,浏览器存在缓存机制,如果名称相同,浏览器默认文件没有改变,这样打包文件名相同会使得获取文件出现问题,因此我们通过可替换模板字符串的形式定义输出的打包文件名。
- 编译层
- name: chunk文件名
- chunk层
- id: 内部chunk的id
- chunkhash:这个chunk的hash值
- 模块层
- contenthash: 根据内容生成的hash
- id:模块id
- hash:模块的hash值
- 文件层:
- file: 文件名称和路径
- query: 带前缀 ? 的 query
- url层:
- url
具体参照模板字符串替换
chunkFilename
chunkFilename 指未被列在 entry 中,却又需要被打包出来的 chunk 文件的名称。一般来说,这个 chunk 文件指的就是要懒加载的代码。
注意点: 默认文件输出为[id].js或者遵循output.filename的设置,如果output.filename设置了name, 则会被预先替换为id
可以参照这篇文章看到filename和chunkFilename的区别
path
打包文件路径
publicPath
外部资源路径,通常以/结尾, 默认参照路径为HTML页面所在的路径为准
例如如下配置,请求一个chunk就相当于请求/assets/1.chunk.js
1 | module.exports = { |
library
组织打包的模块,库开发使用
libraryTarget
库打包引入的方式
Module
module对象用于模块的处理方式
rules
对应值为[Rule]数组
rules作用在于提供模块的创建规则,提供对应的loader和解析器(parser)
Rule
Rule是一个对象,这个对象分为三部分
- 条件匹配: 条件匹配通过
test、include、exclude和resource对资源进行匹配(这个资源指的是请求的资源),并且属性issuer对issuer匹配, 这个issuer指的是请求者的文件绝对路径。是导入时的位置。 - 应用规则: 对选中的文件使用
use来应用loader,按照从后往前的顺序应用, 并可以为loader传递参数。 - 嵌套规则:父规则(文档这里没怎么理解, 在我看来是指一般的规则)、
rule、oneOf的顺序,可以通过enforce强制修改顺序。
1 | module.exports = { |
- 注意:
loader顺序从右往左,从下往上执行,按照pitching顺序执行1
2
3
4
5
6
7|- a-loader `pitch`
|- b-loader `pitch`
|- c-loader `pitch`
|- requested module is picked up as a dependency
|- c-loader normal execution
|- b-loader normal execution
|- a-loader normal execution
Rule.oneOf
一旦匹配,就使用
1 | module.exports = { |
Rule.use
提供一个 loader 数组, 从右往左进行匹配
1 | module.exports = { |
Rule.exclude/include
排除/包括 loader 加载某个模块
Rule.parse
文件被 loader 执行后会转成一段js字符串, parse会将其转换为 AST 语法树,有了语法树就可以对代码为所欲为了,其中最重要的功能就是分析出这段代码依赖了哪些模块
Rule.sideEffect
模块是否包含副作用
Rule.type
设置匹配模块的类型,防止 webpack 自定义的行为发生,常用于自定义loader加载模块
Rule.resolve
模块解析可以在模块层被配置, Rule层面的 resolve 会覆盖顶层的 resolve配置
UseEntry
Rule 传入的形式,通常可以是对象或者一个函数, 一个必选的字符串形式的 loader 和一个可选的 option
函数形式则会接受一个加载模块的对象参数
1 | // 对象形式 |
noParse
不解析所传递的正则表达式匹配到的文件,这里特别注意不匹配的文件不能存在require和import
1 | module.exports = { |
unsafeCache
缓存模块是否需要解析, 首先得保证缓存开启。缓存未开启,默认为false。缓存开启,默认会解析node_modules的模块。
1 | module.exports = { |
Resolve
resolve的作用在于如何正确的识别模块,找到需要引入bundle的模块代码
alias
创建别名,使得引入方式更加简单
也可以在给定对象的键后的末尾添加 $,以表示精准匹配
也可以使用 { '路径': false } 表示忽略路径的模块
resolve.alias 优先级高于其它模块解析方式。
1 | const path = require('path'); |
Optimization
优化,会根据打包模式自动切换配置,也可以手动配置
minimize
开启表示需要压缩,需要配合 TerserPlugin 或其它在 optimization.minimizer 定义的插件压缩 bundle
minimizer
使用自定义压缩工具,覆盖默认压缩工具,通常使用 TerserPlugin
1 | module.exports = { |
函数形式,形参为 compiler
1 | module.exports = { |
splitChunks
默认使用 webpack4默认的分块策略,具体手动配置参考 splitChunkPlugin
runtimeChunk
runtimeChunk作用在于将只含有runtime的入口文件单独打包一个文件, 所谓runtime就是指异步加载代码如import('./utils') => {}
emitOnErrors
编译时每当有错误时,会被 emit, 关键错误会被 emit 到代码中
todo