02-Webpack4配置增强
我们已经完成了基于React的脚手架工程的创建,现在让我们来进一步增强我们的工程,已方便日后的开发。
增强Webpack
清理 /dist 文件夹
dist文件夹里包含了我们生成的各种打包文件,我们更新生成配置后,如果不即使删除里面的残留文件,可能导致旧打包文件和新打包文件共存的情况。
我们可以在编译时添加脚本删除,如下所示:
"build": "rd /S /Q dist && webpack"
也可以通过Webpack的clean-webpack-plugin插件来实现。
安装插件yarn add -D clean-webpack-plugin
修改webpack.config.js文件,加入html-webpack-plugin插件
// 管理插件,通过插件实现增强功能
plugins: [
// 每次编译前清除dist文件夹
new CleanWebpackPlugin(),
],
区分开发和生成环境
开发环境(development)和生产环境(production)的构建目标差异很大。在开发环境中,我们需要具有强大的、具有实时重新加载(live reloading)或热模块替换(hot module replacement)能力的 source map 和 localhost server。而在生产环境中,我们的目标则转向于关注更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间。由于要遵循逻辑分离,我们通常建议为每个环境编写彼此独立的 webpack 配置。
基于以上原理,我们将原有的webpack.config.js一个配置文件分割为webpack.common.js,webpack.dev.js和webpack.prod.js三个配置文件。
首先安装yarn add -D webpack-merge
根据原有webpack.config.js文件将对应配置分散到三个配置文件中
webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const webpack = require('webpack')
module.exports = {
// 入口文件
entry: './src/index.tsx',
// 需要解析的文件后缀名
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
// 管理插件,通过插件实现增强功能
plugins: [
// 自动清理dist
new CleanWebpackPlugin(),
// 根据模板生成html
new HtmlWebpackPlugin({
title: 'My App',
template: './src/index.html'
}),
],
// 配置项目处理的不同文件及模块
module: {
rules: [
{
test: /\.(ts|tsx)?$/,
loader: 'awesome-typescript-loader'
},
]
}
};
webpack.dev.js
const merge = require('webpack-merge')
const common = require('./webpack.common.js')
const webpack = require('webpack')
const path = require('path');
module.exports = merge(common, {
// 标识配置为开发用
mode: 'development',
// 控制是否生成,以及如何生成 source map
devtool: 'cheap-module-eval-source-map',
// 管理开发服务器
devServer: {
// 查找文件路径
contentBase: 'dist',
// 启用 HMR
hot: true,
},
plugins: [
// 当开启 HMR 的时候使用该插件会显示模块的相对路径,建议用于开发环境
new webpack.NamedModulesPlugin(),
// 启用 HMR 热更新,建议用于开发环境
new webpack.HotModuleReplacementPlugin()
],
// 管理输出
output: {
// 定义输出文件名规则
filename: '[name].bundle.js',
// 定义输出文件名路径
path: path.resolve(__dirname, 'dist'),
},
})
webpack.prod.js
const merge = require('webpack-merge')
const common = require('./webpack.common.js')
const webpack = require('webpack')
const path = require('path');
module.exports = merge(common, {
// 标识配置为生产用
mode: 'production',
// 控制是否生成,以及如何生成 source map
devtool: 'source-map',
// 管理输出
output: {
// 定义输出文件名规则
filename: '[name].[contenthash].js',
// 定义输出文件名路径
path: path.resolve(__dirname, 'dist'),
},
})
最后修改package.json:
"scripts": {
"build": "webpack --config webpack.prod.js",
"dev": "webpack-dev-server --config webpack.dev.js"
},
Source Map说明
Webpack的打包过程中,会对源代码进行压缩,合并,编译等操作,导致编译后的代码和源码差异较大。为了更容易地追踪错误和警告,通过JavaScript 提供的source map功能,能够将编译后的代码映射到源代码上,便于错误定位。
在Webpack中,是通过devtool配置项来指定构造的source map类型。配置项很多,但大致可以划分为5类,其余配置项可以是其任意组合。
- eval: 使用eval包裹模块代码,尾部通过souceURL来定位原始代码位置,不产生.map文件
- source-map: 产生.map文件,通过.map文件定位
- cheap: 不包含列信息(debug时注意点都在行数上,不用关心列数)也不包含loader的sourcemap(意味着如果使用了类似bable类编译工具,定位到的就是编译后的代码而非原始代码)
- module: 包含loader的sourcemap(比如babel的sourcemap)
- inline: 将.map作为DataURI嵌入,不单独生成.map文件
综上所示,我们在开发环境选用cheap-module-eval-source-map,就能够定位到各个原始文件上。生产环境则考虑使用source-map。
代码压缩
Webpack4的mode是production时,会自动开启js的压缩,不过这里我们还是使用uglifyjs-webpack-plugin插件。
安装
yarn add -D uglifyjs-webpack-plugin
修改webpack.prod.js文件
module.exports = merge(common, {
// 标识配置为生产用
mode: 'production',
// 控制是否生成,以及如何生成 source map
devtool: 'source-map',
plugins: [
new UglifyJSPlugin({
sourceMap: true
}),
],
// 管理输出
output: {
// 定义输出文件名规则
filename: '[name].[contenthash].js',
// 定义输出文件名路径
path: path.resolve(__dirname, 'dist'),
},
})
这里需要注意一点,UglifyJSPlugin压缩插件不能解析es6语法,需要引入bable来处理es6,es7的js文件的编译。
指定环境
程序中使用的某些第三方library可能会和process.env.NODE_ENV环境变量关联,比如在生产环境中增加额外的日志记录或测试,在生产环境中增加一些优化。因此我们根据不同的环境预设好process.env.NODE_ENV的值。NODE_ENV本质上是Node.js露给执行脚本的系统环境变量,同时并不能在Webpack.prod.js类似的构建脚本中预设NODE_ENV的值,但我们可以通过webpack内置的 DefinePlugin为所有的依赖定义这个变量。
对应环境的webpack配置文件中增加如下所示的插件配置:
// 预设程序执行环境
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})