mode
可以在命令行或配置文件来指定 mode:
命令行:
webpack --mode development
配置文件:
moedule.exports = {
mode: 'production'
}
mode 的值可以是:
- none
- development
- production(默认值)
none
none 模式下,webpack 不会帮你做任何配置
development
development 模式下,将侧重于功能调试和优化开发体验,包含如下内容:
- 浏览器调试工具
- 开发阶段的详细错误日志和提示
- 快速和优化的增量构建机制
production
production 模式下,将侧重于模块体积优化和线上部署,包含如下内容:
- 开启所有的优化代码
- 更小的 bundle 大小
- 去除掉只在开发阶段运行的代码
- Scope hoisting 和 Tree-shaking
- 自动启用 terser 对代码进行压缩
process.env.NODE_ENV
mode 的值决定了打包生成的 chunk 中 process.env.NODE_ENV 的值,根据开发模式下和生产模式执行不同的代码:
/* app.js */
if (process.env.NODE_ENV === 'production') {
doSomething()
} else if (process.env.NODE_ENV === 'development') {
doSomethingElse()
}
一共在两个地方可以使用 process.env.NODE_ENV:
- 在 webpack 配置文件中使用
process.env.NODE_ENV - 在项目源代码中使用
process.env.NODE_ENV
在 webpack 配置文件中使用 process.env.NODE_ENV,访问的是通过命令行传入的参数 NODE_ENV,也就是 package.json 文件中 scripts 里面定义的 NODE_ENV 的值。
/* package.json */
{
"scripts": {
"build": "NODE_ENV=production webpack",
"dev": "NODE_NEV=development webpack serve --open"
}
}
/* webpack.config.js */
console.log(process.env.NODE_ENV) // 这里的值是通过命令行传入的参数值,如果是 npm run build,则值为 production。
在项目源代码中使用 process.env.NODE_ENV,访问的是在配置文件中通过 DefinePlugin 定义的值,而不是通过命令行传入的值。将配置文件的 mode 设置为 development 或者 production,相当于自动通过 DefinePlugin 定义了可以在源代码中访问的 process.env.NODE_ENV 为 mode 的值。
/* webpack.config.js */
const webpack = require('webpack');
module.exports = {
mode: 'development',
entry: {
app: './src/app'
},
output: {
path: 'dist',
filename: 'bundle.js'
},
plugins: [
new webpack.DefinePlugin({
// 这里定义了可以在模块中访问的 process.env.NODE_ENV 的值
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
})
]
};
/* src/index.js */
console.log(process.env.NODE_ENV); // 这里输出的是在配置文件中 mode 指定的值
context
基础目录,用于查找 entry 和 loader 中的文件。必须是绝对路径,默认为配置文件所在的目录。entry 和 loader 中的文件指定相对路径,相对于 context 的路径。
module.exports = {
context: path.resolve(__dirname)
entry: {
// 相对路径,相对 context 选项
index: './src/index.js',
// 模块路径,根据模块的解析规则来解析
vendor: 'lodash'
},
module: {
rules: [
{
test: /\.css$/,
// 推荐使用模块路径
use: ['./node_modules/style-loader', 'css-loader']
}
]
}
}
entry
entry 的值可以是:
- 字符串,简写形式,chunkname 为 main
- 数组,简写形式,chunkname 为 main
- 对象,推荐使用对象来设置 entry 的值
- 函数,动态 entry
module.exports = {
entry: './src/index.js'
}
module.exports = {
entry: ['./src/index.js', './lib/func.js']
}
module.exports = {
entry: {
main: './src/index.js'
}
}
module.exports = {
entry: {
main: ['./src/index.js', './lib/func.js']
}
}
module.exports = {
entry: () => './src/index.js'
}
推荐使用对象来设置 entry 的值:
- 格式:键值对,一个键值对会打包成一个 initial chunk
- 键名:键名是 chunk name,output.filename 占位符中的 [name] 就是 chunk name 的值
- 键值:键值是入口文件路径,可以是相对路径或模块路径,相对路径相对于 context,模块路径根据模块解析规则来解析
- 键值:可以是字符串、数组、对象
将一张依赖图生成一个 chunk,同一个 chunk 中不存在重复的模块
module.exports = {
entry: {
main: './src/index.js'
}
}
将多张依赖图生成一个 chunk,同一个 chunk 中不存在重复的模块(不同依赖图中的相同模块只会打包成一个模块,不会重复打包,通过 webpack_require 来多次引入)
module.exports = {
entry: {
main: ['./src/index.js', './lib/func.js']
}
}
将多张依赖图生成多个 chunk,不同 chunk 中可能存在重复的模块
module.exports = {
entry: {
index: './src/index.js',
about: './src/about.js',
admin: './src/admin.js',
},
optimazation: {
runtimeChunk: 'multiple'
}
}
module.exports = {
entry: {
home: './home.js',
shared: ['react', 'react-dom', 'redux', 'react-redux'],
catalog: {
import: './catalog.js',
filename: 'pages/catalog.js',
dependOn: 'shared',
chunkLoading: false, // Disable chunks that are loaded on demand and put everything in the main chunk.
},
personal: {
import: './personal.js',
filename: 'pages/personal.js',
dependOn: 'shared',
chunkLoading: 'jsonp',
asyncChunks: true, // Create async chunks that are loaded on demand.
layer: 'name of layer', // set the layer for an entry point
},
},
}
output
output.filename
指定 initial chunk 的全名,以及从 initial chunk 中分离出来的 split chunk (runtime, vendor, common) 的全名
module.exports = {
output: {
filename: '[name].bundle.js'
}
}
占位符:
- [name]:chunk name
- [id]:chunk id
- [contenthash]:根据 chunk 的内容创建唯一哈希值
生产模式下,推荐 chunk 文件名 filename: [name].[contenthash].js
output.chunkFilename
指定 async chunk 的全名,以及从 async chunk 中分离出来的 split chunk (vendor, common) 的全名
module.exports = {
output: {
chunkFilename: '[name].chunk.js'
}
}
output.path
打包生成的 chunk 文件和资源文件所在的目录,必须是绝对路径
module.exports = {
output: {
path: path.resolve(__dirname, 'dist')
}
}
output.publicPuth
module.exports = {
output: {
publicPath: '',
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
chunkFilename: '[name].chunk.js',
clean: true
},
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader']
},
{
test: /\.(jpg|jpeg|png|gif)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[hash][ext]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin(),
new MiniCssExtractPlugin({
filename: 'css/[name].css'
})
],
}
资源访问路径 = output.publicPath + 资源名称
- 通过
output.publicPath+output.filename访问 initial chunk 文件 - 通过
output.publicPath+output.chunkFilename访问 async chunk 文件 - 通过
output.publicPath+MiniCssExtractPlugin 插件的 options.filename访问 css 文件 - 通过
output.publicPath+{图片资源 rule}.generator.filename访问 asset/resource 资源文件
output.publicPath 可以是绝对路径、相对于服务的路径、相对于页面的路径。不管是哪种路径,都要以 / 结尾:
publicPath: "https://cdn.example.com/assets/", // CDN(总是 HTTPS 协议)
publicPath: "//cdn.example.com/assets/", // CDN (协议相同)
publicPath: "/assets/", // 相对于服务(server-relative)
publicPath: "assets/", // 相对于 HTML 页面
publicPath: "../assets/", // 相对于 HTML 页面
publicPath: "", // 相对于 HTML 页面(目录相同),默认值
- 如果
output.publicPath是绝对路径http://www.google.com/
HtmlWebpackPlugin 生成的 index.html 文件:
<script defer src="http://www.google.com/app.bundle.js"></script>
<link href="http://www.google.com/css/app.min.css" rel="stylesheet">
MiniCssExtractPlugin 生成的 css 文件:
.container {
background: url(http://www.google.com/images/01dfd42294af18c510ac.jpg) no-repeat;
}
- 如果
output.publicPath是相对服务的路径/backend/
HtmlWebpackPlugin 生成的 index.html 文件:
<script defer src="/backend/app.bundle.js"></script>
<link href="/backend/css/app.min.css" rel="stylesheet">
MiniCssExtractPlugin 生成的 css 文件:
.container {
background: url(/backend/images/01dfd42294af18c510ac.jpg) no-repeat;
}
- 如果
output.publicPath是相对页面的路径./backend/
HtmlWebpackPlugin 生成的 index.html 文件:
<script defer src="./backend/app.bundle.js"></script>
<link href="./backend/css/app.min.css" rel="stylesheet">
MiniCssExtractPlugin 生成的 css 文件:
.container {
background: url(./backend/images/01dfd42294af18c510ac.jpg) no-repeat;
}
不管通过哪种路径设置 output.publicPath,都只是影响 HtmlWebpackPlugin 和 MiniCssExtractPlugin 生成的文件中引用其他资源的路径。具体能不能根据资源路径访问到相应的资源,还得正确的部署 output.path 目录到服务器。
在开发模式下,devServer 自动开启一个开发服务器,并且将所有打包生成的资源存储到内存当中,然后通过 http://[devServer.host]:[devServer.port]/[output.publicPath]/资源名称来访问对应的资源。 这时候 output.publicPath 应该设置为相对服务的路径,例如 /。如果你的页面希望在其他不同路径中找到资源文件,则可以通过 devServer 配置中的 devMiddleware.publicPath 选项进行修改。
在生产模式下,推荐将 output.publicPath 设置为绝对路径,然后将 output.path 目录部署与绝对路径对应的服务器中。
output.clean
是否在生成文件之前清空 output.path 目录
module.exports = {
output: {
clean: true
}
}