diff --git a/admin/package-lock.json b/admin/package-lock.json index 93c4056..5eef7fb 100644 --- a/admin/package-lock.json +++ b/admin/package-lock.json @@ -22,6 +22,7 @@ "css-loader": "^5.0.0", "file-loader": "^6.2.0", "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.9.4", "style-loader": "^2.0.0", "vue-loader": "^15.9.0", "vue-style-loader": "^4.1.0", @@ -4834,6 +4835,84 @@ "node": ">=6" } }, + "node_modules/mini-css-extract-plugin": { + "version": "2.9.4", + "resolved": "https://registry.npmmirror.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.4.tgz", + "integrity": "sha512-ZWYT7ln73Hptxqxk2DxPU9MmapXRhxkJD6tkSR04dnQxm8BGu2hzgKLugK5yySD97u/8yy7Ma7E76k9ZdvtjkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", diff --git a/admin/package.json b/admin/package.json index bef44ae..6cdf37a 100644 --- a/admin/package.json +++ b/admin/package.json @@ -5,7 +5,7 @@ "scripts": { "install:deps": "npm install", "dev": "webpack serve --mode development --open", - "build": "webpack --mode production", + "build": "webpack --mode production --progress", "build:test": "webpack --mode test" }, "dependencies": { @@ -23,6 +23,7 @@ "css-loader": "^5.0.0", "file-loader": "^6.2.0", "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.9.4", "style-loader": "^2.0.0", "vue-loader": "^15.9.0", "vue-style-loader": "^4.1.0", diff --git a/admin/webpack.config.js b/admin/webpack.config.js index ba79017..e3af3a3 100644 --- a/admin/webpack.config.js +++ b/admin/webpack.config.js @@ -1,12 +1,17 @@ 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: './src/main.js', output: { path: path.resolve(__dirname, 'dist'), - filename: 'app.js', + filename: 'js/[name].[contenthash:8].js', + chunkFilename: 'js/[name].[contenthash:8].chunk.js', clean: true }, module: { @@ -22,11 +27,24 @@ module.exports = { }, { test: /\.css$/, - use: ['vue-style-loader', 'css-loader'] + use: [ + is_production ? MiniCssExtractPlugin.loader : 'vue-style-loader', + 'css-loader' + ] }, { - test: /\.(png|jpe?g|gif|svg|woff2?|eot|ttf|otf)$/, - type: 'asset/resource' + 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]' + } } ] }, @@ -35,7 +53,13 @@ module.exports = { new HtmlWebpackPlugin({ template: './public/index.html', title: 'Admin Framework Demo' - }) + }), + ...(is_production ? [ + new MiniCssExtractPlugin({ + filename: 'css/[name].[contenthash:8].css', + chunkFilename: 'css/[name].[contenthash:8].chunk.css' + }) + ] : []) ], resolve: { extensions: ['.js', '.vue', '.json'], @@ -52,6 +76,58 @@ module.exports = { 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 } }