本文深入解析如何在 Webpack 项目中区分开发与生产环境。通过 package.json 定义脚本命令,利用 minimist 解析命令行参数,动态加载不同配置文件。详细阐述开发环境下的 CSS 模块化、HMR 热更新及 Source-map 调试配置,以及生产环境的代码压缩、CSS 分离与公共模块拆分策略,帮助开发者构建高效且易于维护的构建流程。
Webpack 环境配置背景与目标
在早期的小型项目中,Webpack 配置往往采用单一模式,未对运行环境进行细分。近期在开发一个复杂的商城项目时,深入研究了 Webpack 的高级配置功能,经过两天的调试与优化,整理出一套相对完善的配置方案,现将其核心思路与实现细节分享出来。
如何有效区分开发环境与生产环境?
基于 Node.js 命令行参数的环境区分机制
Webpack 基于 Node.js 平台运行,因此区分环境的核心在于 Node.js 层面的控制。启动 Webpack 时通常执行如 npm run 或 yarn start 等命令,我们需要通过这些命令行指令向 Webpack 传递当前所处的环境标识。
package.json 脚本配置
package.json
{
"name": "webpac-demo",
"version": "1.0.0",
"description": "webpack练习",
"main": "index.js",
"scripts": {
//配置开发环境参数。注意:真实开发中 package.json 文件中不能有注释
"dev": "webpack --env=development",
//配置生产环境参数
"dist": "webpack --env=production",
"start": "webpack-dev-server --env=development"
},
"dependencies": {
"font-awesome": "^4.7.0",
"react": "^16.2.0",
"react-dom": "^16.2.0"
},
"devDependencies":{
...
}
}
通过在命令行中执行 npm run dev 或 npm run dist,可以将特定参数传递给构建过程。获取这些参数的关键在于使用 Node.js 的命令行参数解析工具。
使用 minimist 解析参数
minimist
minimist 是一个轻量级的命令行参数解析库。
// test.js
var args = require('minimist')(process.argv.slice(2));
console.log(args.hello);
$ node test.js --env=production
// production
$ node test.js --env=development
// development
$ node test.js --env
// true 注意:不是空字符串而是true
minimist 会将接收到的参数解析为键值对形式的 JSON 对象。利用该对象,我们可以准确判断当前执行的是开发环境打包还是生产环境打包操作。
// webpack.config.js
const webpack = require('webpack');
//当前项目的绝对路劲
const path = require('path');
// 命令行参数解析引擎
const argv = require('minimist')(process.argv.slice(2));
let env = null;
switch (argv.env) {
case 'production':
//生产环境配置文件名
env = 'webpack.config.prod';
break;
default:
//开发环境配置文件名
env = 'webpack.config.dev';
}
console.log(`当前是 ${argv.env} 打包`);
// 这时候,我们就可以加载相应的wabpack配置了。
module.exports = require( path.resolve( '加载的配置文件路劲',env ) );
开发环境与生产环境配置详解
Webpack 开发环境与生产环境的具体配置差异
开发环境:调试与模块化优化
开发环境配置
开发环境的首要目标是提升开发效率与调试便利性,无需关注代码合并或 CSS 样式分离等优化细节。
开发环境主要关注三点:1. CSS 模块化处理;2. 模块热替换(HMR)功能;3. Source-map 代码映射,用于错误定位。
// 开发环境打包配置
const path = require('path');
const webpack = require('webpack');
const base = require('./webpack.config.base')
const dfPath = require('./path')
// webpack配置合并工具
const merge =require('webpack-merge')
const RS = (...arg)=>path.resolve( __dirname , ...arg )
// 合并方式配置
let strategyMerge = merge.strategy({
entry: 'prepend'
});
let config = {
entry: {
app: path.resolve(dfPath.root,'src/app.js')
},
output: {
path: dfPath.dist,
filename: '[name].bundle.js',
publicPath: '/',
chunkFilename: '[name].sepChunk.js'
},
module:{
rules: [
{
test: /\.js$/,
use:['babel-loader'],
exclude: [
dfPath.node_modules
]
},
{
test:/\.css$/,
use:[
'style-loader',
{
loader:'css-loader',
options:{
// css模块化,方便多人开发
module:true,
// 定义模块化css后的类名(默认为hash值,可读性差)path:路劲; name:文件名; local:本地定义的className
localIdentName: '[path][name]__[local]--[hash:base64:5]'
},
}
],
// 排除的文件,遇到这些文件不会用当前 loader 处理,也就不会模块化
exclude:[
RS('./src/common'),
RS('node_modules')
]
},
{
test:/\.css$/,
use:['style-loader','css-loader'],
include:[
RS('./src/common'),
RS('node_modules')
]
},
{
test: /\.(png|jpg|jpeg|gif)$/,
use: ['url-loader?limit=8192'],
}
]
},
plugins:[
// 模块热替换功能
new webpack.HotModuleReplacementPlugin()
],
// 代码映射,方便报错时,找到对应的源代码
devtool: 'cheap-module-eval-source-map',
devServer:{
// 服务器打包后,输出的资源路劲
publicPath:'/',
open:true
}
};
// 导出合并后的webpack配置
module.exports = strategyMerge( base , config );
生产环境:性能与打包优化
生产环境配置
生产环境用于最终发布至服务器,需确保代码简洁、加载性能最优,并移除所有调试辅助工具。
生产环境的优化方向包括:1. 公共模块拆分,单独打包;2. CSS 文件分离,独立输出;3. 代码压缩处理。
// 生产环境配置
const webpack = require('webpack');
const base = require('./webpack.config.base')
const path = require('path');
const dfPath = require('./path');
const merge = require('webpack-merge');
// 压缩工具
const ClosureCompilerPlugin = require('webpack-closure-compiler');
// css单独打包插件
const extractTextWebpackPlugin = require('extract-text-webpack-plugin');
const extractCSS = new extractTextWebpackPlugin('assets/css/[name]_[contenthash:6].css');
// weback合并配置
let strategyMerge = merge.strategy({
entry: 'replace',
output: 'replace',
module:{
rules: 'replace'
}
});
let config ={
entry: {
// 公共模块拆分,这些代码会单独打包,一般我们会把引用的框架文件拆分出来,方便浏览器缓存,节省资源。
vender:['react'],
app: path.resolve(dfPath.root,'src/app.js')
},
output: {
path: dfPath.dist,
filename: 'assets/js/[name]_[chunkhash].bundle.js',
publicPath: '/',
chunkFilename: 'assets/js/[name].sepChunk.js',
hashDigestLength: 6
},
module:{
rules: [
{
test: /\.js$/,
use:['babel-loader'],
exclude: [
dfPath.node_modules
]
},
/* 开启 css单独打包 和 css模块化的配置 */
{
test: /\.css$/,
use: extractCSS.extract({
use: [
{
loader: 'css-loader',
options:{
modules: true
}
}
]
})
},
{
test: /\.(png|jpg|jpeg|gif)$/,
use: [
{
loader: 'url-loader',
options:{
limit:8192,
name: '[name]_[hash].[ext]',
outputPath: 'assets/img/'
}
}
],
},
{
test: /\.(mp4|ogg|svg|ico)$/,
use: [
{
loader: 'file-loader',
options:{
name: '[name]_[hash].[ext]',
outputPath: 'assets/media/'
}
}
]
},
{
test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'url-loader',
options:{
limit:10000,
name: '[name]_[hash].[ext]',
outputPath: 'assets/font/',
mimetype: 'application/font-woff'
}
}
]
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'url-loader',
options:{
limit:10000,
name: '[name]_[hash].[ext]',
outputPath: 'assets/font/',
mimetype: 'application/octet-stream'
}
}
]
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader',
options:{
name: '[name]_[hash].[ext]',
outputPath: 'assets/font/',
}
}
]
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'url-loader',
options:{
limit:10000,
name: '[name]_[hash].[ext]',
outputPath: 'assets/font/',
mimetype: 'image/svg+xml'
}
}
]
},
]
},
plugins:[
extractCSS,
// 设置 process.env(生产环境) 环境变量的快捷方式。
new webpack.EnvironmentPlugin({
NODE_ENV: 'production'
})
,new ClosureCompilerPlugin()
],
devtool: 'source-map'
};
module.exports = strategyMerge(base,config);
以上为本文全部内容,希望对读者学习 Webpack 配置有所帮助,欢迎支持本站。