一、公共路径
可以看到根据前几掌的学习,dist/app.html 引用的资源都是通过相对路径来引用的。
如果想要使用 CDN 的路径或者当前服务器的路径,来作为link上面的路径前缀,就可以使用publicPath
。
publicPath
:可以用来指定应用程序中所有资源的基础路径。
webpack.config.js
export default {
// ...
output: {
// ...
publicPath: 'http://localhost:8080/'
}
}
打包之后就可以看到 app.html 引用的资源都加上了设置的域名。
二、环境变量
- –env
在之前的学习中,我们通过 webpack.config.js 中的 mode 来区分生产环境和开发环境。这里 mode 的值可以通过命令行传参的方式获取,以判断当前是什么环境。
例如: --env production 或 --env goal=local
npx webpack --env production
可以看到 production: true,表示现在是使用生产环境。
2. --env的应用
说明这个 env 是有用的,看下怎么应用:
webpack.config.js:
//...
module.exports = (env) => {
return {
//...
// 根据命令行参数 env 来设置不同环境的 mode。如果指令里面env.production为true,mode就用production, 否则用development
mode: env.production ? 'production' : 'development',
//...
}
}
- 题外话:压缩js
刚刚打包看了下 js 没有压缩,理论上 webpack 自己有个 terser 插件可以压缩,但是它没有生效,这是因为之前我们压缩 css 使用了 cssMinimizerPlugin,所以需要单独配置一下 terser。
npm install terser-webpack-plugin -D
webpack.config.js
const TerserPlugin = require('terser-webpack-plugin')
// ...
module.exports = (env) => {
return {
optimization: {
minimizer: [
new CssMinimizerPlugin(),
new TerserPlugin() // 压缩js
],
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
}
}
三、拆分配置文件
刚刚是通过判断指令里面的 production 是否设置,来区分 mode 里面的环境用哪个。每次指令都得加一个环境变量有点子烦,因此优化一哈.
将生产环境和开发环境两个的配置文件单独放到不同的配置文件中。如 webpack.config.dev.js (开发环境配置)和webpack.config.prod.js (生产环境配置)。在项目根目录下创建一个配置文件夹 config 来存放他们。 记得设置output 时打包的dist文件夹要放到上一层目录
比如开发环境里面不需要设置publicPath,也不需要压缩js,相应的配置就可以删了;生产环境不需要devtool、devserver这些,也可以删了。
然后启动指令需要通过 -c 指定一下用哪个配置
npx webpack -c ./config/webpack.config.dev.js
四、npm 脚本
刚刚的打包指令还是有点子复杂,这会优化一哈。
在当前项目下建一个 package.json,把刚刚手动敲的指令放进来,这样每次启动的时候就可以用npm run start
或者npm run build
来编译了。
"scripts": {
"start": "webpack serve -c ./config/webpack.config.js --env development",
"build": "webpack -c ./config/webpack.config.js --env production"
},
五、提取公共配置,合并配置文件
把 webpack.config.dev.js 和 webpack.config.prod.js 中重复的部分放到 webpack.config.common.js,开发和生成环境的配置文件就保留剩下的即可。
再使用 webpack-merge
这个工具来合并配置文件。
npm install webpack-merge -D
webpack.config.js
const { merge } = require('webpack-merge')
const commonConfig = require('./webpack.config.common')
const productionConfig = require('./webpack.config.prod')
const developmentConfig = require('./webpack.config.dev')
module.exports = (env) => {
switch(true) {
case env.development:
return merge(commonConfig, developmentConfig)
case env.production:
return merge(commonConfig, productionConfig)
defult:
return new Error('No matching configuration was found')
}
}
webpack.config.common.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const toml = require('toml')
const yaml = require('yaml')
const json5 = require('json5')
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-module.js'
},
output: {
path: path.resolve(__dirname, '../dist'),
clean: true,
assetModuleFilename: 'images/[contenthash][ext]'
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html',
filename: 'app.html',
inject: 'body'
}),
new MiniCssExtractPlugin({
filename: 'styles/[contenthash].css'
})
],
module: {
rules: [
{
test: /\.png$/,
type: 'asset/resource',
generator: {
filename: 'images/[contenthash][ext]'
}
},
{
test: /\.svg$/,
type: 'asset/inline'
},
{
test: /\.txt$/,
type: 'asset/source'
},
{
test: /\.jpg$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 4 * 1024 * 1024
}
}
},
{
test: /\.(css|less)$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource'
},
{
test: /\.(csv|tsv)$/,
use: 'csv-loader'
},
{
test: /\.xml$/,
use: 'xml-loader'
},
{
test: /\.toml$/,
type: 'json',
parser: {
parse: toml.parse
}
},
{
test: /\.yaml$/,
type: 'json',
parser: {
parse: yaml.parse
}
},
{
test: /\.json5$/,
type: 'json',
parser: {
parse: json5.parse
}
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
[
'@babel/plugin-transform-runtime'
]
]
}
}
}
]
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
}
webpack.config.dev.js
module.exports = {
output: {
filename: 'scripts/[name].js'
},
mode: 'development',
devtool: 'inline-source-map',
devServer: {
static: './dist'
}
}
webpack.config.prod.js
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
output: {
filename: 'scripts/[name].[contenthash].js',
publicPath: 'http://localhost:8080/'
},
mode: 'production',
optimization: {
minimizer: [
new CssMinimizerPlugin(),
new TerserPlugin()
]
},
performance: {
hints: false
}
}