根据环境拆分webpack配置
- 为什么需要拆分配置?
- 如何拆分配置?
-
为什么要拆分配置
由于我们日常开发的项目, 后期需要根据不同的环境打包,生成对应环境的包,所以我们需要不同环境的webpack配置,比如开发环境我们需要安装很多利于我们开发过程中的插件,loader等,但是生产环境下不需要这些东西,所以就不需要把这些开发过程用到的插件打包进去。
-
如何拆分配置?
需要用到的插件
webpack-merge,合并配置。我们将不同环境的配置分隔开,dev => webpack.dev.config.js, prod => webpack.prod.config.js; 公用的配置文件叫做 webpack.base.config.js
目录结构
build
| | ———— build.js
| | ———— webpack.dev.config.js
| | ———— webpack.prod.config.js
| | ———— webpack.base.config.js
|
public
| | ———— index.html
| | ———— favicon.ico
|
src
| | ———— main.ts
| | ———— App.vue
webpack.dev.config.js 开发环境的配置
然后我们写一下webpack.dev.config.js的配置, 用于开发时使用。
const { merge } = require('webpack-merge')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
const webpackBaseConfig = require('./webpack.base.config')
const HOST = process.env.HOST || '0.0.0.0'
const PORT = process.env.PORT || 8088
portfinder.basePort = PORT
// 以上插件均为最新版本
function createNotifierCallback () {
const notifier = require('node-notifier')
return (serverity, errors) => {
if (serverity !== 'error') return
const error = errors[0]
const filename = error.file && error.file.split('!').pop()
notifier.notify({
title: packageConfig.name,
message: serverity + ':' + error.name,
subtitle: filename || '',
icon: path.join(__dirname, 'logo.png')
})
}
}
module.exports = env => {
let devConfig = merge(webpackBaseConfig, {
devServer: {
host: '0.0.0.0',
port: 8088,
inline: true,
open: false, // 是否启动项目之后自动打开浏览器运行
hot: true, // 启动热更新
noInfo: true, // 无webpack运行时的打包信息
proxy: {}, // 代理
historyFallBack: true // 用于路由设置为'hostory'模式,刷新404的问题
},
target: 'web', // 不设置不会启动热更新, websocket不会连接
plugins: [
new webpack.DefinePlugin({
"process.env.NODE_ENV": env
}),
new webpack.HotMoudleReplacementPlugin(),
new HtmlWebpackPlugin({
template: 'index.html', // 你的index.html模板文件
title: 'webpack拆分配置', // 你的index.html的title
filename: 'index.html', // 打包输出的文件名称
inject: true, // 将打包的js全部插入到body的最底部
favicon: '' // 你的网页标签的图标
})
]
})
return new Promise((resolve, reject) => {
portfinder.getPort((err, port) => {
if (err) {
reject(err)
} else {
devConfig.devServer.port = port
devConfig.plugins.push(new FriendlyErrorsWebpackPlugin({
compliationSuccessInfo: {
quiet: true,
message: [`Your application is running here http://${devConfig.devServer.host}:${devConfig.devServer.port}`]
},
onErrors: env === 'development' ? createNotifierCallback() : undefined
}))
resolve(devConfig)
}
})
})
}
webpack.prod.config.js 生产环境配置
接下来是 生产环境的配置 webpack.prod.config.js
const { merge } = require("webpack-merge")
const webpack = require('webpack')
const webpackBaseConfig = require('./webpack.base.config')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')
// const OptimizeCssWebpackPlugin = require('optimize-css-assets-webpack-plugin')
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin')
// optimize-css-assets-webpack-plugin 与 css-minimizer-webpack-plugin 两者用途一样, 随便挑一个用就行
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = env => {
console.log(process.env.NODE_ENV)
return merge(webpackBaseConfig(env), {
optimization: {
runtimeChunk: {
name: "runtime"
},
usedExports: true,
minimize: true,
minimizer: [new TerserWebpackPlugin({
parallel: true
}), new CssMinimizerWebpackPlugin()],
splitChunks: {
cacheGroups: {
defaultVendors: {
chunks: 'initial',
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
priority: -10
},
common: {
name: 'common',
chunks: 'initial',
minChunks: 2,
priority: -20
}
}
}
},
plugins: [
new webpack.DefinePlugin({
"__VUE_OPTIONS_API__": false,
"__VUE_PROD_DEVTOOLS__": false,
"proccess.env.NODE_ENV": env
}),
new HtmlWebpackPlugin({
title: '移动端',
template: require('path').resolve('public/index.html'),
filename: 'index.html',
hash: true,
inject: true,
chunks: ['runtime', 'vendors', 'common', 'main']
}),
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: ['**/*', 'dist']
})
]
})
}
webpack.base.config.js 公共配置
最后是 公共配置, 也就是loader的配置,和一些公用的插件。webpack.base.config.js
const webpack = require('webpack')
const VueLoaderPlugin = require('vue-loader/dist/plugin').default
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const resolve = (file) => {
return require('path').resolve(__dirname, '..' file)
}
module.exports = env => ({
mode: env,
devtool: env === 'development' ? 'inline-cheap-module-source-map' : 'source-map',
entry: {
main: resolve('src/main.js')
},
output: {
filename: 'js/[name][contenthash].js',
path: env === 'development' ? resolve('dist') : resolve('servers/dist'),
publicPath: '/',
chunkFilename: 'js/[name]/[name][contenthash:7].js'
},
resolve: {
alias: {
'@': utils.resolve('src')
},
extensions: [".ts", ".tsx", ".js", ".vue", ".json"]
},
performance: false,
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
ts: 'ts-loader',
tsx: 'babel-loader!ts-loader'
}
}
},
{
test: /\.js$/,
include: utils.resolve('src'),
use: [
'thread-loader',
'babel-loader'
]
},
{
test: /\.ts$/,
include: utils.resolve('src'),
use: [
{
loader: 'ts-loader',
options: {
transpileOnly: true,
appendTsSuffixTo: [/TS\.vue$/]
}
}
]
},
{
test: /\.tsx$/,
include: utils.resolve('src'),
use: [
{
loader: 'ts-loader',
options: {
transpileOnly: true,
appendTsSuffixTo: [/TSX\.vue$/]
}
}
]
},
{
test: /\.(sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader',
options: {
importLoaders: 2
}
}, {
loader: 'postcss-loader'
}, {
loader: 'sass-loader'
}
],
sideEffects: true
},
]
},
plugins: [
new VueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: env === 'development' ? '[name].css' : 'css/[name]-[contenthash:7].css',
chunkFilename: env === 'development' ? '[name].css' : 'css/[name]-[contenthash:7].css'
})
]
})
最后我们还需要一个打包入口 build.js
const webpack = require('webpack')
const chalk = require('chalk')
const webpackProdConfig = require('./webpack.prod.config')
module.exports = new Promise((resolve, reject) => {
let env = process.argv[2].match(/(NODE_ENV=\w+)/g)[0].split('=')[1]
console.log('打包环境', env)
webpack(webpackProdConfig(env), (err, stats) => {
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
chunks: false,
chunkModules: false
}) + '\n\n')
if (stats.hasErrors()) {
reject(err)
console.log(chalk.red(' Build failed with errors.\n'))
process.exit(1)
}
console.log(chalk.cyan(' Build complete.\n'))
console.log(chalk.yellow(
' Tip: built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won\'t work.\n' + new Date()
))
resolve()
})
})
package.json 配置
{
"scripts": {
"serve": "cd servers && yarn dev",
"dev": "webpack-dev-server --config build/webpack.dev.config.js --env=development --progress",
"build": "node build/build.js --env.NODE_ENV=production"
},
}
总结
根据这三篇文章, 差不多就可以自己手搭公司的项目进行开发了, 其他的可以添加dllPlugin啊,cache-loader啊等,这些优化项根据需要添加就好了,代码开发规范 eslint 自行配置就好,相信自己,你可以的。