mirror of
https://gitee.com/ShopeX/ECShopX_admin-frontend
synced 2026-08-06 04:46:24 +08:00
407 lines
12 KiB
JavaScript
Executable File
407 lines
12 KiB
JavaScript
Executable File
const path = require('path')
|
|
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
|
const WebpackAliyunOss = require('webpack-aliyun-oss')
|
|
const TerserPlugin = require('terser-webpack-plugin')
|
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
|
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
|
|
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin')
|
|
const bodyParser = require('body-parser')
|
|
|
|
const SRC_PATH = path.resolve(__dirname, 'src')
|
|
const envVars = process.env
|
|
const isDev = process.env.NODE_ENV === 'development'
|
|
const isProd = process.env.NODE_ENV === 'production'
|
|
|
|
// 输出环境变量信息
|
|
console.log(`🚀 构建模式: ${process.env.NODE_ENV}`)
|
|
console.log(`🚀 构建平台: ${process.env.PLATFORM}`)
|
|
console.log('📋 环境变量:')
|
|
Object.keys(envVars).forEach((key) => {
|
|
if (key.indexOf('VUE_APP') > -1) {
|
|
console.log(` ${key}: ${envVars[key]}`)
|
|
}
|
|
})
|
|
|
|
// 在构建完成后复制微前端文件
|
|
const getNewpcCopyConfig = () => {
|
|
const sourceDir = process.env.PLATFORM === 'bbc' ? './newpc_bbc' : './newpc_b2c'
|
|
return {
|
|
patterns: [
|
|
{
|
|
from: path.resolve(__dirname, sourceDir),
|
|
to: path.resolve(__dirname, './dist/newpc'),
|
|
noErrorOnMissing: true
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
// 基础配置
|
|
lintOnSave: isDev, // 只在开发环境启用 lint
|
|
publicPath: process.env.VUE_APP_PUBLIC_PATH || '/',
|
|
runtimeCompiler: true,
|
|
productionSourceMap: false, // 生产环境不生成 source map
|
|
|
|
// CSS 配置
|
|
css: {
|
|
loaderOptions: {
|
|
sass: {
|
|
sassOptions: {
|
|
includePaths: [SRC_PATH]
|
|
},
|
|
additionalData: `@import "~@/styles/imports.sass"`
|
|
},
|
|
scss: {
|
|
additionalData: `@import "~@/styles/imports.scss";`
|
|
}
|
|
},
|
|
// 生产环境提取 CSS
|
|
extract: isProd
|
|
? {
|
|
ignoreOrder: true // 忽略 CSS 顺序警告
|
|
}
|
|
: false
|
|
},
|
|
|
|
// Webpack 配置
|
|
configureWebpack: (config) => {
|
|
// 开发环境配置
|
|
if (isDev) {
|
|
config.devtool = 'eval-cheap-module-source-map' // 更快的 source map
|
|
// 开发环境性能优化
|
|
config.cache = {
|
|
type: 'filesystem',
|
|
buildDependencies: {
|
|
config: [__filename]
|
|
}
|
|
}
|
|
}
|
|
|
|
// 生产环境优化
|
|
if (isProd) {
|
|
// 代码压缩配置
|
|
config.optimization = {
|
|
...config.optimization,
|
|
minimize: true,
|
|
minimizer: [
|
|
new TerserPlugin({
|
|
terserOptions: {
|
|
compress: {
|
|
drop_console: true,
|
|
drop_debugger: true,
|
|
pure_funcs: ['console.log', 'console.info', 'console.warn']
|
|
},
|
|
output: {
|
|
comments: false
|
|
}
|
|
},
|
|
extractComments: false,
|
|
parallel: true
|
|
}),
|
|
new CssMinimizerPlugin({
|
|
parallel: true,
|
|
minimizerOptions: {
|
|
preset: [
|
|
'default',
|
|
{
|
|
discardComments: { removeAll: true },
|
|
normalizeWhitespace: false
|
|
}
|
|
]
|
|
}
|
|
})
|
|
],
|
|
// 代码分割优化
|
|
splitChunks: {
|
|
chunks: 'all',
|
|
minSize: 20000,
|
|
minChunks: 1,
|
|
maxAsyncRequests: 30,
|
|
maxInitialRequests: 30,
|
|
enforceSizeThreshold: 50000,
|
|
cacheGroups: {
|
|
elementUI: {
|
|
name: 'chunk-elementUI',
|
|
test: /[\\/]node_modules[\\/]element-ui[\\/]/,
|
|
priority: 30,
|
|
chunks: 'all',
|
|
reuseExistingChunk: true
|
|
},
|
|
libs: {
|
|
name: 'chunk-libs',
|
|
test: /[\\/]node_modules[\\/]/,
|
|
priority: 20,
|
|
chunks: 'all',
|
|
reuseExistingChunk: true
|
|
},
|
|
commons: {
|
|
name: 'chunk-commons',
|
|
minChunks: 2,
|
|
priority: 10,
|
|
chunks: 'all',
|
|
reuseExistingChunk: true
|
|
},
|
|
styles: {
|
|
name: 'styles',
|
|
test: /\.(css|scss|sass)$/,
|
|
chunks: 'all',
|
|
enforce: true,
|
|
priority: 40,
|
|
reuseExistingChunk: true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 在主构建流程中添加文件复制插件
|
|
// config.plugins.push(new CopyWebpackPlugin(getNewpcCopyConfig()))
|
|
}
|
|
|
|
// OSS CDN 上传配置
|
|
if (process.env.VUE_APP_OSS_CDN === 'true') {
|
|
try {
|
|
config.plugins.push(
|
|
new WebpackAliyunOss({
|
|
from: ['./dist/**', '!./dist/**/*.html', '!./dist/**/*.ico'],
|
|
dist: '/ecshopx-admin',
|
|
region: process.env.VUE_APP_ALIOSS_REGION,
|
|
accessKeyId: process.env.VUE_APP_ALIOSS_ACCESS_KEY_ID,
|
|
accessKeySecret: process.env.VUE_APP_ALIOSS_ACCESS_KEY_SECRET,
|
|
bucket: process.env.VUE_APP_ALIOSS_BUCKET,
|
|
deleteAll: false, // 不删除远程文件
|
|
timeout: 120000 // 2分钟超时
|
|
})
|
|
)
|
|
console.log('✅ OSS CDN 上传插件已启用')
|
|
} catch (error) {
|
|
console.warn('⚠️ OSS CDN 配置错误:', error.message)
|
|
}
|
|
}
|
|
|
|
// 别名配置
|
|
return {
|
|
resolve: {
|
|
alias: {
|
|
'@': path.resolve(__dirname, './src'),
|
|
'assets': path.resolve(__dirname, './src/assets'),
|
|
'components': path.resolve(__dirname, './src/components'),
|
|
'lodash': 'lodash-es'
|
|
},
|
|
extensions: ['.js', '.vue', '.json', '.ts', '.png', '.jpg', '.jpeg', '.gif', '.svg'],
|
|
modules: ['node_modules', path.resolve(__dirname, 'src')]
|
|
},
|
|
module: {
|
|
rules: [
|
|
{
|
|
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
|
type: 'asset',
|
|
parser: {
|
|
dataUrlCondition: {
|
|
maxSize: 4 * 1024 // 4kb
|
|
}
|
|
},
|
|
generator: {
|
|
filename: 'img/[name].[hash:8][ext]'
|
|
}
|
|
},
|
|
{
|
|
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
|
type: 'asset',
|
|
parser: {
|
|
dataUrlCondition: {
|
|
maxSize: 4 * 1024 // 4kb
|
|
}
|
|
},
|
|
generator: {
|
|
filename: 'fonts/[name].[hash:8][ext]'
|
|
}
|
|
}
|
|
]
|
|
},
|
|
performance: {
|
|
hints: 'warning',
|
|
maxEntrypointSize: 1024 * 1024, // 入口文件大小限制为1MB
|
|
maxAssetSize: 1024 * 1024 // 单个资源大小限制为1MB
|
|
}
|
|
}
|
|
},
|
|
|
|
// Webpack 链式配置
|
|
chainWebpack: (config) => {
|
|
// 删除预加载和预获取
|
|
config.plugins.delete('preload')
|
|
config.plugins.delete('prefetch')
|
|
|
|
config.plugin('define').tap((args) => {
|
|
args[0]['process.env'] = {
|
|
...args[0]['process.env'],
|
|
// 添加自定义环境变量
|
|
VUE_APP_PLATFORM: JSON.stringify(process.env.PLATFORM || 'bbc')
|
|
}
|
|
return args
|
|
})
|
|
|
|
// 生产环境优化
|
|
if (isProd) {
|
|
// 启用 gzip 压缩
|
|
const CompressionPlugin = require('compression-webpack-plugin')
|
|
config.plugin('compressionPlugin').use(
|
|
new CompressionPlugin({
|
|
filename: '[path][base].gz',
|
|
algorithm: 'gzip',
|
|
test: /\.(js|css|html|svg)$/,
|
|
threshold: 10240, // 只压缩大于10kb的文件
|
|
minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
|
|
deleteOriginalAssets: false // 保留原文件
|
|
})
|
|
)
|
|
|
|
// 优化CSS提取
|
|
config.plugin('mini-css-extract').use(MiniCssExtractPlugin, [
|
|
{
|
|
filename: 'css/[name].[contenthash:8].css',
|
|
chunkFilename: 'css/[name].[contenthash:8].css',
|
|
ignoreOrder: true // 忽略 CSS 顺序警告
|
|
}
|
|
])
|
|
|
|
// Bundle 分析(可选)
|
|
if (process.env.ANALYZE) {
|
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
|
config.plugin('bundle-analyzer').use(BundleAnalyzerPlugin)
|
|
}
|
|
}
|
|
|
|
// 优化图片加载
|
|
config.module
|
|
.rule('images')
|
|
.test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
|
|
.type('asset')
|
|
.parser({
|
|
dataUrlCondition: {
|
|
maxSize: 4096 // 4kb
|
|
}
|
|
})
|
|
.set('generator', {
|
|
filename: 'img/[name].[hash:8][ext]'
|
|
})
|
|
|
|
// 添加别名
|
|
config.resolve.alias
|
|
.set('@', path.join(__dirname, 'src'))
|
|
.set('assets', path.join(__dirname, 'src/assets'))
|
|
.set('components', path.join(__dirname, 'src/components'))
|
|
|
|
// 配置字体资源处理
|
|
config.module
|
|
.rule('fonts')
|
|
.test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/)
|
|
.type('asset')
|
|
.set('parser', {
|
|
dataUrlCondition: {
|
|
maxSize: 4 * 1024 // 4kb
|
|
}
|
|
})
|
|
.set('generator', {
|
|
filename: 'fonts/[name].[hash:8][ext]'
|
|
})
|
|
},
|
|
|
|
// 开发服务器配置
|
|
devServer: {
|
|
port: 8080,
|
|
hot: true,
|
|
open: true,
|
|
compress: true, // 启用 gzip 压缩
|
|
historyApiFallback: true, // 支持 HTML5 History API
|
|
// 添加中间件来解析请求体
|
|
setupMiddlewares: (middlewares, devServer) => {
|
|
// 添加body-parser中间件来解析请求体
|
|
devServer.app.use(bodyParser.json())
|
|
devServer.app.use(bodyParser.urlencoded({ extended: true }))
|
|
return middlewares
|
|
},
|
|
// 性能优化
|
|
client: {
|
|
logging: 'warn', // 只显示警告和错误
|
|
progress: true,
|
|
overlay: {
|
|
errors: true,
|
|
warnings: false
|
|
}
|
|
}
|
|
// 代理配置 - 支持所有HTTP方法 (GET, POST, PUT, DELETE, PATCH等)
|
|
// proxy: {
|
|
// '/website/decorate': {
|
|
// target: process.env.VUE_APP_TEMPLATE_URL,
|
|
// changeOrigin: true,
|
|
// secure: false, // 支持https
|
|
// // pathRewrite:{
|
|
// // '^/website/decorate': '/template'
|
|
// // }
|
|
// },
|
|
// '/_nuxt': {
|
|
// target: process.env.VUE_APP_TEMPLATE_URL,
|
|
// changeOrigin: true,
|
|
// secure: false, // 支持https
|
|
// // pathRewrite:{
|
|
// // '^/post_template': ''
|
|
// // }
|
|
// },
|
|
// '/api': {
|
|
// target: 'https://test-dtc-sit.amandax.com.cn',
|
|
// changeOrigin: true,
|
|
// // secure: false, // 支持https
|
|
// // 支持所有HTTP方法
|
|
// methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],
|
|
// // 处理请求体
|
|
// onProxyReq: (proxyReq, req, res) => {
|
|
// // 记录详细的请求信息
|
|
// console.log('🔍 代理请求详情:')
|
|
// console.log(' Method:', req.method)
|
|
// console.log(' URL:', req.url)
|
|
// // 处理POST/PUT/PATCH请求的请求体
|
|
// if (req.body && ['POST', 'PUT', 'PATCH'].includes(req.method)) {
|
|
// const bodyData = JSON.stringify(req.body);
|
|
// proxyReq.setHeader('Content-Type', 'application/json');
|
|
// proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
|
|
// proxyReq.write(bodyData);
|
|
// console.log(' ✅ 请求体已设置:', bodyData)
|
|
// } else {
|
|
// console.log(' ⚠️ 没有请求体或不是POST/PUT/PATCH请求')
|
|
// }
|
|
// },
|
|
// // 处理响应
|
|
// onProxyRes: (proxyRes, req, res) => {
|
|
// // 可以在这里添加响应处理逻辑
|
|
// console.log(`代理请求: ${req.method} ${req.url} -> ${proxyRes.statusCode}`);
|
|
// },
|
|
// // 错误处理
|
|
// onError: (err, req, res) => {
|
|
// console.error('代理错误:', err);
|
|
// res.writeHead(500, {
|
|
// 'Content-Type': 'application/json'
|
|
// });
|
|
// res.end(JSON.stringify({ error: '代理请求失败' }));
|
|
// },
|
|
// pathRewrite: {
|
|
// // '^/api': ''
|
|
// }
|
|
// }
|
|
// }
|
|
},
|
|
|
|
// 并行处理
|
|
parallel: require('os').cpus().length > 1
|
|
|
|
// PWA 配置(如果需要)
|
|
// pwa: {
|
|
// name: 'EcshopX Admin',
|
|
// themeColor: '#4DBA87',
|
|
// msTileColor: '#000000',
|
|
// appleMobileWebAppCapable: 'yes',
|
|
// appleMobileWebAppStatusBarStyle: 'black'
|
|
// }
|
|
}
|