升级 webpack 到 4.x 版本
说明
webpack 4 可以零配置启动,也支持通过配置文件进行更细致的配置,相比于上一个版本,配置已经简化了很多
webpack 4 引入了
mode
用来设置开发环境,同时也可以简化配置项,不同的mode
会携带不同的默认配置
--mode development
开发模式更关注开发体验:编译速度、报错信息--mode production
生产模式更关注用户体验:文件大小、运行性能、打包速度
webpack 4 的
plugin
插件体系较之前版本改动较大,一些插件已经不能使用
1. 零配置启动
安装
# webpack-cli CLI 工具被拆分为单独的包了
sudo yarn add webpack webpack-cli --dev
package.json 中添加脚本,通过
--mode
定义环境变量
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production"
},
文件组织
零配置启动的默认入口文件是
/src/index.js
输出文件为/dist/main.js
如果需要自定义还是使用 webapck 配置文件吧
├── dist
│ └── main.js # index.js 和 bd.js 被打包到 一个文件了
├── index.html
├── package.json
├── src
│ ├── bd.js
│ └── index.js
└── yarn.lock
结果
yarn run build
webpack --mode production
生产环境默认会压缩
2. 配置文件启动
1. 添加 package.json scripts
"scripts": {
"dev": "webpack-dev-server --config build/webpack.dev.config.js",
"start": "yarn run dev",
"build": "webpack --colors --config build/webpack.prod.config.js",
"report": "webpack --colors --env.REPORT --config build/webpack.prod.config.js",
"server": "nodemon server/index.js"
},
2. 公用的配置
// webpack.base.config.js 与在 webpack 3.x 下的配置基本没有变化
module.exports = {
context: common.context,
entry: utils.computeEntry(config, packageConfig),
output: utils.computeOutput(config),
cache: true,
resolve: {
extensions: ['.js', '.json', '.jsx', '.css'],
modules: ['node_modules', common.sourceCode]
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: common.sourceCode,
options: {
formatter: require('eslint-friendly-formatter')
}
},
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
include: common.sourceCode
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: namedAssets(current.env !== 'production' ? 'imgs/[name].[ext]' : 'imgs/[name].[hash:10].[ext]')
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: namedAssets(current.env !== 'production' ? 'media/[name].[ext]' : 'media/[name].[hash:10].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: namedAssets(current.env !== 'production' ? 'fonts/[name].[ext]' : 'fonts/[name].[hash:10].[ext]')
}
},
{
test: require.resolve(common.requestModule),
loader: 'imports-loader?basicRequestLink=>' + JSON.stringify(current.conf.basicRequestLink)
},
{
test: require.resolve(utils.resolve(common.sourceCode)('index.js')),
loader: 'imports-loader?assetsPublicPath=>' + JSON.stringify(current.conf.assetsPublicPath)
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: utils.resolve(common.sourceCode)('index.html'),
filename: 'index.html',
inject: 'body',
minify: false,
xhtml: true,
cache: false
// favicon: ''
})
]
};
3. 开发环境配置
// webpack.dev.config.js
module.exports = merge(baseWebpackConfig, {
mode: 'development', // 通过 mode 声明开发环境
devtool: '#cheap-module-eval-source-map',
module: {
rules: [
{
test: /\.(scss|sass|css)$/,
include: common.sourceCode,
use: utils.computeStyleLoader(false, ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'])
}
]
},
// optimization 代替 webpack 3.x 中 webpack.optimize.CommonsChunkPlugin 分离模块
optimization: {
splitChunks: {
cacheGroups:{
commons: {
chunks: 'initial',
minChunks: 2,
maxInitialRequests: 5,
minSize: 0
},
vendor: {
test: /node_modules/,
chunks: 'initial',
name: 'vendor',
priority: 10,
enforce: true,
}
}
},
runtimeChunk: {
name: 'runtime'
}
},
plugins: [
new CleanWebpackPlugin(['dev'], { root: common.context }),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new FriendlyErrorsPlugin()
],
devServer: { // webpack-dev-server 的配置没有大的变化
contentBase: currentConfig.assetsRoot,
publicPath: currentConfig.assetsPublicPath,
historyApiFallback: true,
// clientLogLevel: 'none',
hot: true,
inline: true,
compress: true,
open: true,
openPage: 'index.html',
port: currentConfig.port,
host: currentConfig.devServerIp,
stats: {
colors: true,
errors: true,
warnings: true,
modules: false,
chunks: false
}
}
});
4. 生产环境配置
extract-text-webpack-plugin
不在适用 webpack 4.x,改用mini-css-extract-plugin
代替
'use strict';
/* eslint-disable */
const utils = require('./utils');
const config = require('../config/index');
const common = config.common;
const currentConfig = config.production;
// 设置环境变量
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = JSON.parse(currentConfig.env.NODE_ENV);
}
/*
production 环境下 webpack 配置文件,安装 plugins
*/
const webpack = require('webpack');
const merge = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const baseWebpackConfig = require('./webpack.base.config');
// 打包信息展示插件
let reportPlugin = [];
if (currentConfig.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
reportPlugin.push(new BundleAnalyzerPlugin());
}
// workbox 插件
let workboxPlugin = [];
if (currentConfig.needWorkboxSW) {
const WorkboxPlugin = require('workbox-webpack-plugin');
const defaultConfig = {
cacheId: 'webpack-pwa',
skipWaiting: true,
clientsClaim: true,
swDest: 'service-wroker.js',
// 一下两个配置不在需要
// globPatterns: ['**/*.{html,js,css,png.jpg}'],
// globIgnores: [ 'service-wroker.js' ],
runtimeCaching: [
{
urlPattern: /.*\.js/,
handler: 'networkFirst', // 网络优先
}
]
};
workboxPlugin.push(new WorkboxPlugin.GenerateSW(currentConfig.workboxConfig || defaultConfig));
}
module.exports = merge(baseWebpackConfig, {
// mode 声明生产环境,生产环境下回默认压缩文件
mode: 'production',
devtool: currentConfig.productionSourceMap ? '#source-map' : false,
module: {
rules: [
{
// 使用 mini-css-extract-plugin 插件来分离出 css 文件
test: /\.(scss|sass|css)$/,
include: common.sourceCode,
use: [
MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'
]
}
]
},
// optimization 配置模块分离,代替 webpack.optimize.CommonsChunkPlugin
optimization: {
splitChunks: {
cacheGroups:{
commons: {
chunks: 'initial',
minChunks: 2,
maxInitialRequests: 5,
minSize: 0
},
vendor: {
test: /node_modules/,
chunks: 'initial',
name: 'vendor',
priority: 10,
enforce: true,
},
styles: {
name: 'styles',
test: /\.scss$/,
chunks: 'all',
enforce: true,
}
}
},
runtimeChunk: {
name: 'runtime'
},
},
plugins: [
new CleanWebpackPlugin(['dist'], { root: common.context }),
new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.ModuleConcatenationPlugin(),
new OptimizeCSSPlugin({ cssProcessorOptions: { safe: true } }),
new MiniCssExtractPlugin({
filename: utils.resolve(currentConfig.assetsSubDirectory)('css/[name].[contenthash].css')
}),
new CopyWebpackPlugin([
{
from: 'src/manifest.json',
to: 'manifest.json'
},
{
from: 'src/icon.png',
to: 'static/imgs/icon.png'
}
]),
...workboxPlugin,
...reportPlugin
]
});
5. 更多配置
更多配置可以查看源码 需要切换到 webpack-v4-template 分支