初版提交
Some checks failed
Deploy to GitHub Pages / Deploy to GitHub Pages (push) Has been cancelled

This commit is contained in:
2025-09-09 13:35:24 +08:00
parent c2c3237369
commit 77a83e363a
453 changed files with 34080 additions and 18016 deletions

287
rspack.config.js Normal file
View File

@ -0,0 +1,287 @@
const path = require('path')
const { Configuration, DefinePlugin, BannerPlugin } = require('@rspack/core')
const HtmlRspackPlugin = require('html-rspack-plugin')
const { VueLoaderPlugin } = require('vue-loader')
const { publicPath, assetsDir, outputDir, title, devPort } = require('./src/config')
const dayjs = require('dayjs')
const time = dayjs().format('YYYY-M-D HH:mm:ss')
const fs = require('fs-extra')
const { webpackBanner } = require('./layouts')
// 设置环境变量
process.env.VUE_APP_TITLE = title || 'Wagoo'
process.env.VUE_APP_UPDATE_TIME = time
process.env.BASE_URL = publicPath
// 删除这一行避免覆盖rspack.js中设置的值
// process.env.NODE_ENV = process.env.NODE_ENV || 'development'
process.env.VUE_APP_MOCK_ENABLE = 'false' // 启用mock
process.env.VUE_APP_AUTHOR = 'Wagoo' // 设置作者
const resolve = (dir) => path.join(__dirname, dir)
// 定义一个模式变量,避免冲突
const mode = process.env.NODE_ENV || 'development'
/**
* @type {Configuration}
*/
module.exports = {
mode: mode,
context: __dirname,
entry: {
app: './src/main.js',
},
output: {
path: resolve(outputDir),
publicPath: publicPath,
filename: 'js/[name].[contenthash:8].js',
chunkFilename: 'js/[name].[contenthash:8].js',
assetModuleFilename: `${assetsDir}/[name].[hash][ext][query]`,
},
// 增加性能提示配置
performance: {
// 提高阈值以减少警告
maxEntrypointSize: 3000000, // 3MB
maxAssetSize: 1000000, // 1MB
// 只在生产环境显示性能警告
hints: mode === 'production' ? 'warning' : false,
},
module: {
rules: [
{
test: /\.vue$/,
use: [
{
loader: 'vue-loader',
options: {
compilerOptions: {
preserveWhitespace: false,
},
},
},
],
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@vue/cli-plugin-babel/preset'],
},
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
auto: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
},
},
},
{
loader: 'sass-loader',
options: {
additionalData: (content, loaderContext) => {
const { resourcePath, rootContext } = loaderContext
const relativePath = path.relative(rootContext, resourcePath)
if (relativePath.replace(/\\/g, '/') !== 'src/styles/variables.scss') {
return `@import "~@/styles/variables.scss";${content}`
}
return content
},
},
},
],
},
{
test: /\.(png|jpe?g|gif|svg)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 10KB
},
},
},
{
test: /\.(woff2?|eot|ttf|otf)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 30 * 1024, // 增加到30KB
},
},
},
{
resourceQuery: /raw/,
type: 'asset/source',
},
],
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src'),
vue$: 'vue/dist/vue.esm.js',
path: 'path-browserify',
fs: false,
},
fallback: {
path: require.resolve('path-browserify'),
},
},
plugins: [
new VueLoaderPlugin(),
new DefinePlugin({
// 完全移除可能引起冲突的NODE_ENV定义让rspack.js来处理
'process.env.BASE_URL': JSON.stringify(process.env.BASE_URL),
'process.env.VUE_APP_TITLE': JSON.stringify(process.env.VUE_APP_TITLE),
'process.env.VUE_APP_MOCK_ENABLE': JSON.stringify(process.env.VUE_APP_MOCK_ENABLE),
'process.env.VUE_APP_AUTHOR': JSON.stringify(process.env.VUE_APP_AUTHOR),
'process.env.VUE_APP_UPDATE_TIME': JSON.stringify(process.env.VUE_APP_UPDATE_TIME),
}),
new HtmlRspackPlugin({
template: './public/index.html',
filename: 'index.html',
title: title || 'vue-admin-better',
inject: 'body',
templateParameters: {
BASE_URL: publicPath,
VUE_APP_TITLE: process.env.VUE_APP_TITLE,
VUE_APP_AUTHOR: process.env.VUE_APP_AUTHOR,
},
minify:
mode === 'production'
? {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true,
collapseBooleanAttributes: true,
removeScriptTypeAttributes: true,
}
: false,
}),
// 添加版权信息到打包文件头部
new BannerPlugin({
banner: webpackBanner(time),
entryOnly: false,
include: /\.(js|css)$/,
}),
// 添加CopyPlugin功能将public目录下除index.html外的文件复制到dist目录
{
apply(compiler) {
compiler.hooks.afterEmit.tap('CopyPublicFolderPlugin', (compilation) => {
// 确保目标目录存在
const targetPath = path.resolve(__dirname, 'dist');
fs.ensureDirSync(targetPath);
// 复制public目录下的所有文件除了index.html
fs.copySync(
path.resolve(__dirname, 'public'),
targetPath,
{
filter: (src) => {
// 不复制index.html文件因为HtmlRspackPlugin会处理它
return !src.endsWith('index.html');
}
}
);
});
}
}
],
optimization: {
splitChunks: {
automaticNameDelimiter: '-',
chunks: 'all',
// 增加maxInitialRequests以允许更多的初始化块
maxInitialRequests: 6,
// 减小最小块大小,允许更细粒度的分割
minSize: 20000,
cacheGroups: {
chunk: {
name: 'vab-chunk',
test: /[\\/]node_modules[\\/]/,
minSize: 131072,
maxSize: 524288,
chunks: 'async',
minChunks: 2,
priority: 10,
},
vue: {
name: 'vue',
test: /[\\/]node_modules[\\/](vue(.*)|core-js)[\\/]/,
chunks: 'initial',
priority: 20,
},
elementUI: {
name: 'element-ui',
test: /[\\/]node_modules[\\/]element-ui(.*)[\\/]/,
priority: 30,
},
// 单独拆分常用工具库
vendors: {
name: 'vendors',
test: /[\\/]node_modules[\\/](lodash|axios|qs|dayjs)[\\/]/,
chunks: 'all',
priority: 35,
},
// 拆分样式资源
styles: {
name: 'styles',
test: /\.(css|scss)$/,
chunks: 'all',
enforce: true,
priority: 40,
},
extra: {
name: 'vab-layouts',
test: resolve('src/layouts'),
priority: 40,
},
},
},
// 添加压缩配置
minimize: mode === 'production',
// 如果是生产环境增加tree shaking
usedExports: mode === 'production',
},
devServer: {
hot: true,
// 修改端口,避免冲突
port: 8090,
historyApiFallback: true,
static: {
directory: path.join(__dirname, 'public'),
},
client: {
overlay: {
errors: true,
warnings: false,
},
},
open: {
target: ['http://localhost:8090'],
},
setupMiddlewares: (middlewares, devServer) => {
if (!devServer) {
throw new Error('dev-server is not defined')
}
if (process.env.VUE_APP_MOCK_ENABLE === 'true') {
const mockServer = require('./mock/index')
mockServer(devServer.app)
}
return middlewares
},
},
}