157 lines
3.8 KiB
JavaScript
157 lines
3.8 KiB
JavaScript
const path = require('path')
|
||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||
const { VueLoaderPlugin } = require('vue-loader')
|
||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||
|
||
// 判断是否为生产环境
|
||
const is_production = process.env.NODE_ENV === 'production' || process.argv.includes('--mode=production')
|
||
|
||
module.exports = {
|
||
entry: {
|
||
main: './src/main.js'
|
||
},
|
||
output: {
|
||
path: path.resolve(__dirname, 'dist'),
|
||
filename: 'js/[name].[contenthash:8].js',
|
||
chunkFilename: 'js/[name].[contenthash:8].chunk.js',
|
||
clean: true
|
||
},
|
||
module: {
|
||
rules: [
|
||
{
|
||
test: /\.vue$/,
|
||
loader: 'vue-loader'
|
||
},
|
||
{
|
||
test: /\.js$/,
|
||
loader: 'babel-loader',
|
||
exclude: /node_modules/
|
||
},
|
||
{
|
||
test: /\.css$/,
|
||
use: [
|
||
is_production ? MiniCssExtractPlugin.loader : 'vue-style-loader',
|
||
'css-loader'
|
||
]
|
||
},
|
||
{
|
||
test: /\.(png|jpe?g|gif|svg)$/,
|
||
type: 'asset/resource',
|
||
generator: {
|
||
filename: 'images/[name].[hash:8][ext]'
|
||
}
|
||
},
|
||
{
|
||
test: /\.(woff2?|eot|ttf|otf)$/,
|
||
type: 'asset/resource',
|
||
generator: {
|
||
filename: 'fonts/[name].[hash:8][ext]'
|
||
}
|
||
}
|
||
]
|
||
},
|
||
plugins: [
|
||
new VueLoaderPlugin(),
|
||
// 主应用 HTML
|
||
new HtmlWebpackPlugin({
|
||
template: './public/index.html',
|
||
title: 'Admin Framework Demo',
|
||
filename: 'index.html',
|
||
chunks: ['main']
|
||
}),
|
||
// 注册页面 HTML(独立页面,不依赖 webpack)
|
||
new HtmlWebpackPlugin({
|
||
template: './public/register.html',
|
||
title: '邀请注册',
|
||
filename: 'register.html',
|
||
inject: false, // 不注入 webpack 生成的脚本
|
||
minify: is_production ? {
|
||
removeComments: true,
|
||
collapseWhitespace: true,
|
||
removeRedundantAttributes: true,
|
||
useShortDoctype: true,
|
||
removeEmptyAttributes: true,
|
||
removeStyleLinkTypeAttributes: true,
|
||
keepClosingSlash: true,
|
||
minifyJS: true,
|
||
minifyCSS: true
|
||
} : false
|
||
}),
|
||
...(is_production ? [
|
||
new MiniCssExtractPlugin({
|
||
filename: 'css/[name].[contenthash:8].css',
|
||
chunkFilename: 'css/[name].[contenthash:8].chunk.css'
|
||
})
|
||
] : [])
|
||
],
|
||
resolve: {
|
||
extensions: ['.js', '.vue', '.json'],
|
||
alias: {
|
||
'@': path.resolve(__dirname, 'src'),
|
||
'vue$': 'vue/dist/vue.esm.js'
|
||
}
|
||
},
|
||
devServer: {
|
||
hot: true,
|
||
open: true,
|
||
port: 8080,
|
||
historyApiFallback: true,
|
||
client: {
|
||
overlay: false // 禁用错误浮层
|
||
}
|
||
},
|
||
optimization: {
|
||
splitChunks: {
|
||
chunks: 'all',
|
||
cacheGroups: {
|
||
// 分离 Vue 核心库
|
||
vue: {
|
||
name: 'vue',
|
||
test: /[\\/]node_modules[\\/](vue|vue-router|vuex)[\\/]/,
|
||
priority: 20,
|
||
reuseExistingChunk: true
|
||
},
|
||
// 分离 UI 库
|
||
ui: {
|
||
name: 'ui',
|
||
test: /[\\/]node_modules[\\/]view-design[\\/]/,
|
||
priority: 15,
|
||
reuseExistingChunk: true
|
||
},
|
||
// 分离图表库
|
||
echarts: {
|
||
name: 'echarts',
|
||
test: /[\\/]node_modules[\\/]echarts[\\/]/,
|
||
priority: 15,
|
||
reuseExistingChunk: true
|
||
},
|
||
// 分离其他第三方库
|
||
vendor: {
|
||
name: 'vendor',
|
||
test: /[\\/]node_modules[\\/]/,
|
||
priority: 10,
|
||
reuseExistingChunk: true
|
||
},
|
||
// 公共代码
|
||
common: {
|
||
name: 'common',
|
||
minChunks: 2,
|
||
priority: 5,
|
||
reuseExistingChunk: true
|
||
}
|
||
}
|
||
},
|
||
runtimeChunk: {
|
||
name: 'runtime'
|
||
}
|
||
},
|
||
stats: {
|
||
colors: true,
|
||
modules: false,
|
||
children: false,
|
||
chunks: false,
|
||
chunkModules: false
|
||
}
|
||
}
|
||
|