123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729 |
- const path = require('path')
- const fs = require('fs')
- const webpack = require('webpack')
- const HtmlWebpackPlugin = require('html-webpack-plugin')
- const MiniCssExtractPlugin = require('mini-css-extract-plugin')
- const { VueLoaderPlugin } = require('vue-loader')
- const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
- const TerserPlugin = require('terser-webpack-plugin')
- const CopyWebpackPlugin = require('copy-webpack-plugin')
- // 预加载插件用于资源预加载
- const PreloadWebpackPlugin = require('@vue/preload-webpack-plugin')
- // 资源压缩插件
- const CompressionWebpackPlugin = require('compression-webpack-plugin')
- // 读取环境变量文件
- function loadEnvFile(envPath) {
- if (fs.existsSync(envPath)) {
- const envContent = fs.readFileSync(envPath, 'utf8')
- const envVars = {}
- envContent.split('\n').forEach(line => {
- // 跳过注释和空行
- const trimmedLine = line.trim()
- if (!trimmedLine || trimmedLine.startsWith('#')) return
-
- const equalIndex = trimmedLine.indexOf('=')
- if (equalIndex > 0) {
- const key = trimmedLine.substring(0, equalIndex).trim()
- const value = trimmedLine.substring(equalIndex + 1).trim()
- // 移除首尾的引号(单引号或双引号)
- const cleanValue = value.replace(/^["']|["']$/g, '')
- envVars[key] = cleanValue
- }
- })
- return envVars
- }
- return {}
- }
- // 根据环境加载对应的 .env 文件
- // 确保 NODE_ENV 有正确的值
- const nodeEnv = process.env.NODE_ENV || 'development'
- const isDevelopment = process.env.NODE_ENV === 'development'
- const isProduction = process.env.NODE_ENV === 'production'
- let envVars = {}
- if (isProduction) {
- envVars = loadEnvFile('.env.production')
- } else if (isDevelopment) {
- envVars = loadEnvFile('.env.development')
- }
- // 合并到 process.env
- Object.assign(process.env, envVars)
- // 获取 public path
- const getPublicPath = () => {
- const routerBase = process.env.VUE_ROUTER_BASE || process.env.VUE_APP_ROUTER_BASE || '/'
- // 确保路径以斜杠结尾
- const normalizedPath = routerBase.endsWith('/') ? routerBase : routerBase + '/'
- const publicPath = isProduction ? normalizedPath : '/'
- console.log('==========',process.env.NODE_ENV)
- console.log(`🔧 构建环境: ${process.env.NODE_ENV || 'development'}`)
- console.log(`📁 Public Path: ${publicPath}`)
- if (isProduction && (process.env.VUE_ROUTER_BASE || process.env.VUE_APP_ROUTER_BASE)) {
- console.log(`📖 从 .env.production 读取路由基础路径: ${routerBase}`)
- }
-
- return publicPath
- }
- // 验证并设置正确的 mode 值
- const getMode = () => {
- const validModes = ['development', 'production', 'none']
- if (validModes.includes(nodeEnv)) {
- return nodeEnv
- }
- // 如果 NODE_ENV 不是有效值,根据情况设置默认值
- console.warn(`⚠️ NODE_ENV "${nodeEnv}" 不是有效的 webpack mode,默认使用 development`)
- return 'development'
- }
- module.exports = {
- mode: getMode(),
- // 添加这个配置来抑制特定警告
- stats: {
- warnings: isDevelopment ? false : true, // 开发环境完全关闭警告,生产环境显示
- warningsFilter: [
- /export .* was not found in/,
- /Deprecation Warning/,
- /sass-lang\.com\/d\/import/,
- /Global built-in functions are deprecated/,
- /@import rules are deprecated/,
- /Invalid deprecation/,
- /Module Warning \(from \.\/node_modules\/sass-loader/,
- /Sass @import rules are deprecated/,
- /More info and automated migrator/,
- /downloadByUrl.*was not found/,
- /possible exports:/,
- /WARNING in/,
- /Module not found/,
- /Can't resolve/,
- /\[BABEL\] Note:/,
- /code generator has deoptimised/,
- /exceeds the max of/
- ]
- },
- // 缓存配置 - 大幅提升重新构建速度
- cache: {
- type: 'filesystem',
- buildDependencies: {
- config: [__filename],
- },
- cacheDirectory: path.resolve(__dirname, 'node_modules/.cache/webpack'),
- compression: 'gzip',
- profile: false,
- maxMemoryGenerations: isDevelopment ? 5 : Infinity,
- maxAge: 1000 * 60 * 60 * 24 * 7, // 7天
- allowCollectingMemory: isDevelopment,
- },
- entry: {
- main: path.resolve(__dirname, 'src/main.js')
- },
-
- output: {
- path: path.resolve(__dirname, 'dist'),
- filename: isDevelopment ? 'js/[name].js' : 'js/[name].[contenthash:8].js',
- chunkFilename: isDevelopment ? 'js/[name].chunk.js' : 'js/[name].[contenthash:8].chunk.js',
- publicPath: getPublicPath(),
- clean: true,
- assetModuleFilename: 'assets/[name].[hash:8][ext]'
- },
-
- resolve: {
- alias: {
- '@': path.resolve(__dirname, 'src'),
- '@components': path.resolve(__dirname, 'src/components'),
- '@views': path.resolve(__dirname, 'src/views'),
- '@utils': path.resolve(__dirname, 'src/utils'),
- '@lib': path.resolve(__dirname, 'src/components/lib'),
- '@assets': path.resolve(__dirname, 'src/assets'),
- '@api': path.resolve(__dirname, 'src/api'),
- '#': path.resolve(__dirname, 'public'),
- 'vue$': 'vue/dist/vue.esm.js',
- 'element-ui/lib/el-tooltip': 'element-ui/lib/tooltip',
-
- // Component Gallery 别名
- '@component-gallery/assets': path.join(__dirname, 'src/components/common-assets'),
- '@component-gallery/utils': path.join(__dirname, 'src/components/common-inner-utils'),
- '@component-gallery/theme-chalk': path.join(__dirname, 'src/components/theme-chalk'),
- '~@component-gallery/theme-chalk': path.join(__dirname, 'src/components/theme-chalk'),
- "@component-gallery/build-event-bus-path": path.join(__dirname, 'src/components/build-event-bus-path/lib/main'),
- "@component-gallery/base-components": path.join(__dirname, 'src/components/common-base-components'),
- "@component-gallery/base-art-player": path.join(__dirname, 'src/components/common-base-art-player'),
- "@component-gallery/base-video-player": path.join(__dirname, 'src/components/common-base-component-video-player'),
- "@component-gallery/video-map-camera-position": path.join(__dirname, 'src/components/common-comp-video-map-camera-position/src/entry/CommonVideoMapCameraPosition.vue'),
- "@component-gallery/video-map-view": path.join(__dirname, 'src/components/common-comp-video-map-view/src/entry/CommonVideoMapView.vue'),
- "@component-gallery/horn-shout": path.join(__dirname, 'src/components/common-comp-horn-shout/src/entry/CommonHornShout.vue'),
- "@component-gallery/lib": path.join(__dirname, 'src/components/lib'),
- "@component-gallery/one-key-alarm": path.join(__dirname, 'src/components/common-comp-one-key-alarm/src/entry/CommonOneKeyAlarm.vue'),
- "@component-gallery/alarm-list": path.join(__dirname, 'src/components/common-comp-alarm-list'),
- "@component-gallery/alarm-detail": path.join(__dirname, 'src/components/common-comp-alarm-detail/src/entry/CommonAlarmDetail.vue'),
- "@component-gallery/horn-tree": path.join(__dirname, 'src/components/common-comp-horn-tree/src/entry/CommonHornTree.vue'),
- "@component-gallery/horn-broadcast": path.join(__dirname, 'src/components/common-comp-horn-broadcast/src/entry/CommonHornBroadcast.vue'),
- "@component-gallery/map": path.join(__dirname, 'src/components/common-comp-map/src/entry/CommonMap.vue'),
- "@component-gallery/tool-box": path.join(__dirname, 'src/components/common-comp-tool-box/src/entry/CommonToolBox.vue'),
- "@component-gallery/kanzheli": path.join(__dirname, 'src/components/common-comp-kanzheli/src/entry/CommonKanzheli.vue'),
- "@component-gallery/alarm-filte": path.join(__dirname, 'src/components/common-comp-alarm-filte/src/entry/CommonAlarmFilte.vue'),
- "@component-gallery/camera-choose": path.join(__dirname, 'src/components/common-comp-camera-choose/src/CommonCameraChoose.vue'),
- "@component-gallery/coordinate-picking": path.join(__dirname, 'src/components/common-comp-coordinate-picking/src/entry/CommonCoordinatePicking.vue'),
- "@component-gallery/coordinate-positioning": path.join(__dirname, 'src/components/common-comp-coordinate-positioning/src/entry/CommonCoordinatePositioning.vue'),
- "@component-gallery/layers-control": path.join(__dirname, 'src/components/common-comp-layers-control/src/entry/CommonLayersControl.vue'),
- "@component-gallery/slope-aspect-analysis": path.join(__dirname, 'src/components/common-comp-slope-aspect-analysis/src/CommonSlopeAspectAnalysis.vue'),
- "@component-gallery/spot-detail": path.join(__dirname, 'src/components/common-comp-spot-detail/src/entry/SpotDetail.vue'),
- "@component-gallery/tool-camera-filte": path.join(__dirname, 'src/components/common-comp-tool-camera-filte/src/CommonCameraFilte.vue'),
- "@component-gallery/tool-config-item": path.join(__dirname, 'src/components/common-comp-tool-config-item/src/entry/CommonToolConfigItem.vue'),
- "@component-gallery/tools-plot": path.join(__dirname, 'src/components/common-comp-tools-plot/src/CommonToolsPlot.vue'),
- "@component-gallery/viewshed-analysis": path.join(__dirname, 'src/components/common-comp-viewshed-analysis/src/CommonViewshedAnalysis.vue'),
- "@component-gallery/tool-measure": path.join(__dirname, 'src/components/common-comp-tool-measure/src/entry/CommonCompToolMeasure.vue'),
- "@component-gallery/tool-section-analyse": path.join(__dirname, 'src/components/common-comp-tool-section-analyse/src/entry/CommonCompToolSectionAnalyse.vue'),
- "@component-gallery/layer-style-config": path.join(__dirname, 'src/components/common-comp-layer-style-config/src/entry/CommonLayerStyleConfig.vue'),
- "@component-gallery/azimuthal-measurement": path.join(__dirname, 'src/components/common-comp-azimuthal-measurement/src/entry/AzimuthalMeasurement.vue'),
- "@component-gallery/terrain-dig": path.join(__dirname, 'src/components/common-comp-terrain-dig/src/entry/TerrainDig.vue'),
- "@component-gallery/lnglat-select-point": path.join(__dirname, 'src/components/common-comp-lnglat-select-point/src/entry/CommonLnglatSelectPoint.vue'),
- "@component-gallery/tool-spot": path.join(__dirname, 'src/components/common-comp-tool-spot/src/entry/SpotSearch.vue'),
- "@component-gallery/dialog-tool": path.join(__dirname, 'src/components/common-comp-dialog-tool/src/entry/CommonDialogTool.vue'),
- "@component-gallery/layers-tool": path.join(__dirname, 'src/components/common-comp-layers-tool/src/entry/CommonLayersTool.vue'),
- "@component-gallery/horn-circle-selection": path.join(__dirname, 'src/components/common-comp-horn-circle-selection/src/entry/CommonHornCircleSelection.vue'),
- "@component-gallery/around-analysis": path.join(__dirname, 'src/components/common-comp-around-analysis/src/CommonAroundAnalysis.vue'),
- "@component-gallery/video-inspection-polygon": path.join(__dirname, 'src/components/common-comp-video-inspection-polygon/src/entry/CommonVideoInspectionPolygon.vue'),
- "@component-gallery/footer": path.join(__dirname, 'src/components/common-comp-footer/src/entry/CommonFooter.vue'),
- "@component-gallery/multimodal-assistant": path.join(__dirname, 'src/components/common-comp-multimodal-assistant/src/entry/CommonMultimodalAssistant.vue'),
- "@component-gallery/alarm-detail-large": path.join(__dirname, 'src/components/common-comp-alarm-detail-large/src/entry/AlarmDetailLarge.vue'),
- "@component-gallery/alarm-transfer-event": path.join(__dirname, 'src/components/common-comp-alarm-transfer-event/src/entry/AlarmTransferEvent.vue'),
- "@component-gallery/tree": path.join(__dirname, 'src/components/common-comp-tree/src/entry/CommonTree.vue'),
- "@component-gallery/iot-tree": path.join(__dirname, 'src/components/common-comp-iot-tree/src/entry/CommonIotTree.vue'),
- "@component-gallery/radar-tree": path.join(__dirname, 'src/components/common-comp-radar-tree/src/entry/CommonRadarTree.vue'),
- "@component-gallery/uav-tree": path.join(__dirname, 'src/components/common-comp-uav-tree/src/entry/CommonUavTree.vue'),
- "@component-gallery/source-tree": path.join(__dirname, 'src/components/common-comp-source-tree/src/entry/CommonSourceTree.vue'),
- "@component-gallery/grid-tree": path.join(__dirname, 'src/components/common-comp-grid-tree/src/entry/CommonGridTree.vue'),
- "@component-gallery/grid-operator-tree": path.join(__dirname, 'src/components/common-comp-grid-operator-tree/src/entry/CommonGridOperatorTree.vue'),
- "@component-gallery/track-popup": path.join(__dirname, 'src/components/common-comp-track-popup/src/entry/TrackPopup.vue'),
- "@component-gallery/tree-recorder": path.join(__dirname, 'src/components/common-comp-tree-recorder/src/entry/CommonTreeRecorder.vue'),
- "@component-gallery/multiple-device-search": path.join(__dirname, 'src/components/common-comp-multiple-device-search/src/entry/CommonMultipleDeviceSearch.vue'),
- "@component-gallery/camera-circle-selection": path.join(__dirname, 'src/components/common-comp-camera-circle-selection/src/CommonCameraCircleSelection.vue'),
- "@component-gallery/algorithm-configuration": path.join(__dirname, 'src/components/common-comp-algorithm-configuration/src/entry/AlgorithmConfiguration.vue'),
- "@component-gallery/algorithm-configuration-dialog": path.join(__dirname, 'src/components/common-comp-algorithm-configuration-dialog/src/entry/index.vue'),
- "@component-gallery/satellite-sense": path.join(__dirname, 'src/components/common-comp-tool-satellite-sense/src/entry/CommonSatelliteSense.vue'),
- "@component-gallery/tool-space": path.join(__dirname, 'src/components/common-comp-tool-space/src/entry/SpotSpace.vue'),
- "@component-gallery/tool-compound": path.join(__dirname, 'src/components/common-comp-tool-compound/src/entry/SpotCompound.vue'),
- "@component-gallery/tool-complex": path.join(__dirname, 'src/components/common-comp-tool-complex/src/entry/ToolComplex.vue'),
- "@component-gallery/tool-swiper": path.join(__dirname, 'src/components/common-comp-tool-swiper/src/entry/ToolSwiper.vue'),
- "@component-gallery/sense-time-line": path.join(__dirname, 'src/components/common-comp-sense-time-line/src/entry/SenseTimeLine.vue'),
- "@component-gallery/weather-small": path.join(__dirname, 'src/components/common-comp-weather-small/src/entry/CommonWeatherSmall.vue'),
- "@component-gallery/search-map": path.join(__dirname, 'src/components/common-comp-search-map/src/entry/CommonSearchMap.vue'),
- "@component-gallery/inspection-task-list": path.join(__dirname, 'src/components/common-comp-inspection-task-list/src/entry/CommonInspectionTaskList.vue'),
- },
- extensions: ['.js', '.vue', '.json', '.ts', '.tsx'],
- // 解决 webpack 5 严格模块解析问题
- fullySpecified: false,
- fallback: {
- path: require.resolve('path-browserify'),
- crypto: false,
- stream: false,
- fs: false,
- net: false,
- tls: false,
- buffer: require.resolve('buffer'),
- util: require.resolve('util')
- }
- },
-
- module: {
- rules: [
- // 处理第三方库的严格模块解析问题
- {
- test: /\.m?js$/,
- resolve: {
- fullySpecified: false
- }
- },
- // 处理 @ct 相关的 ES6 语法问题
- {
- test: /\.m?js$/,
- include: [
- // 指定需要转译的 node_modules 包
- /node_modules\/@ct/,
- /node_modules\/marked/,
- /node_modules\/@ct\/ais-js-kit/
- ],
- use: {
- loader: 'babel-loader',
- options: {
- presets: [['@babel/preset-env', { modules: false }]],
- plugins: [
- '@babel/plugin-proposal-nullish-coalescing-operator',
- '@babel/plugin-proposal-optional-chaining',
- ],
- },
- },
- },
- // Vue 文件处理
- {
- test: /\.vue$/,
- loader: 'vue-loader',
- options: {
- compilerOptions: {
- preserveWhitespace: false
- }
- }
- },
-
- // JavaScript 文件处理
- {
- test: /\.js$/,
- exclude: /node_modules(?!\/(@ct|marked))/,
- use: {
- loader: 'babel-loader',
- options: {
- presets: ['@babel/preset-env'],
- plugins: [
- "@babel/plugin-proposal-optional-chaining",
- "@babel/plugin-proposal-nullish-coalescing-operator",
- "@babel/plugin-proposal-class-properties"
- ],
- // 启用缓存
- cacheDirectory: true,
- cacheCompression: false
- // plugins: [
- // [
- // 'babel-plugin-component',
- // {
- // libraryName: 'element-ui',
- // libraryDirectory: 'lib',
- // styleLibraryName: 'theme-chalk'
- // },
- // 'element-ui'
- // ]
- // ]
- }
- }
- },
-
- // CSS 文件处理
- {
- test: /\.css$/,
- use: [
- isProduction ? MiniCssExtractPlugin.loader : 'vue-style-loader',
- {
- loader: 'css-loader',
- options: {
- sourceMap: true,
- // 处理CSS中的URL引用
- url: {
- filter: (url, resourcePath) => {
- // 对于第三方包中的静态资源路径,返回false让webpack跳过处理
- // 我们将通过CopyPlugin来复制这些资源
- if (resourcePath.includes('node_modules/@ct/component-gallery-theme-chalk') &&
- url.startsWith('./static/')) {
- return false;
- }
- return true;
- },
- },
- }
- },
- {
- loader: 'postcss-loader',
- options: {
- postcssOptions: {
- plugins: [
- require('postcss-pxtorem')({
- rootValue: 100,
- propList: ['*'],
- // exclude: /node_modules/i
- exclude(file) {
- if (file.indexOf("component-gallery-theme-chalk") !== -1 || file.indexOf("common-base-component-video-player-listener") !== -1) {
- return true;
- } else {
- return false;
- }
- }
- })
- ]
- }
- }
- }
- ]
- },
-
- // SCSS 文件处理
- {
- test: /\.scss$/,
- use: [
- isProduction ? MiniCssExtractPlugin.loader : 'vue-style-loader',
- {
- loader: 'css-loader',
- options: {
- sourceMap: true,
- }
- },
- // {
- // loader: 'postcss-loader',
- // options: {
- // sourceMap: true,
- // postcssOptions: {
- // plugins: [
- // require('postcss-pxtorem')({
- // rootValue: 16,
- // propList: ['*'],
- // exclude: /node_modules/i
- // })
- // ]
- // }
- // }
- // },
- {
- loader: 'resolve-url-loader',
- options: {
- sourceMap: true,
- }
- },
- {
- loader: 'sass-loader',
- options: {
- sourceMap: true,
- sassOptions: {
- // 抑制 Sass 弃用警告
- quietDeps: true,
- verbose: false,
- // 使用通配符抑制所有弃用警告
- silenceDeprecations: ['*']
- }
- },
- },
- ]
- },
-
- // 图片文件处理
- {
- test: /\.(png|jpe?g|gif|svg|webp|tiff?)$/i,
- type: 'asset',
- parser: {
- dataUrlCondition: {
- maxSize: 4 * 1024 // 4KB以下的图片转为base64,减少小图片请求
- }
- },
- generator: {
- filename: 'img/[name].[hash:8][ext]'
- }
- },
-
- // 字体文件处理
- {
- test: /\.(woff|woff2|eot|ttf|otf)$/i,
- type: 'asset',
- parser: {
- dataUrlCondition: {
- maxSize: 8 * 1024
- }
- },
- generator: {
- filename: 'font/[name].[hash:8][ext]'
- }
- },
-
- // 媒体文件处理
- {
- test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)$/i,
- type: 'asset',
- generator: {
- filename: 'media/[name].[hash:8][ext]'
- }
- }
- ]
- },
-
- plugins: [
- new VueLoaderPlugin(),
-
- new HtmlWebpackPlugin({
- template: path.resolve(__dirname, 'public/index.html'),
- filename: 'index.html',
- inject: true,
- templateParameters: {
- BASE_URL: getPublicPath(),
- VUE_APP_ROUTER_BASE: getPublicPath()
- },
- publicPath: getPublicPath(),
- // 优化资源加载优先级
- scriptLoading: 'defer',
- minify: isProduction ? {
- removeComments: true,
- collapseWhitespace: true,
- removeRedundantAttributes: true,
- useShortDoctype: true,
- removeEmptyAttributes: true,
- removeStyleLinkTypeAttributes: true,
- keepClosingSlash: true,
- minifyJS: true,
- minifyCSS: true,
- minifyURLs: true
- } : false
- }),
-
- new webpack.DefinePlugin({
- // 创建一个干净的环境变量对象,避免冲突
- 'process.env': JSON.stringify({
- NODE_ENV: process.env.NODE_ENV || 'development',
- VUE_APP_ROUTER_BASE: getPublicPath(),
- VUE_ROUTER_BASE: process.env.VUE_ROUTER_BASE || process.env.VUE_APP_ROUTER_BASE || '/', // 确保VUE_ROUTER_BASE被传递
- // 只包含需要的环境变量,避免泄露敏感信息
- ...Object.keys(process.env)
- .filter(key => key.startsWith('VUE_APP_') || key === 'NODE_ENV' || key === 'VUE_ROUTER_BASE')
- .reduce((env, key) => {
- env[key] = process.env[key];
- return env;
- }, {})
- }),
- 'process.browser': true,
- 'process.version': JSON.stringify(process.version),
- 'process.platform': JSON.stringify(process.platform),
- 'process.type': JSON.stringify('renderer')
- }),
- new CopyWebpackPlugin({
- patterns: [
- {
- from: path.resolve(__dirname, 'public'),
- to: path.resolve(__dirname, 'dist'),
- globOptions: {
- ignore: ['**/index.html']
- }
- },
- // 复制本地assets到static目录,以匹配第三方CSS包中的相对路径引用
- {
- from: path.resolve(__dirname, 'src/components/common-assets/image'),
- to: path.resolve(__dirname, 'dist/static/image'),
- globOptions: {
- ignore: ['**/.DS_Store']
- }
- }
- ]
- })
- ].concat(isProduction ? [
- new MiniCssExtractPlugin({
- filename: 'css/[name].[contenthash:8].css',
- chunkFilename: 'css/[name].[contenthash:8].css',
- ignoreOrder: true // 忽略 CSS 顺序警告
- }),
- // 预加载关键资源 - 只在生产环境使用,排除图片资源
- new PreloadWebpackPlugin({
- rel: 'preload',
- as(entry) {
- if (/\.css$/.test(entry)) return 'style';
- if (/\.woff2?$/.test(entry)) return 'font';
- // 移除图片的 preload,让它们按需加载
- // if (/\.(png|jpg|jpeg|gif|svg)$/.test(entry)) return 'image';
- return 'script';
- },
- include: ['vue-vendor', 'element-ui', 'main'], // 预加载关键chunk
- fileBlacklist: [
- /\.map$/,
- /hot-update\.js$/,
- /\.(png|jpg|jpeg|gif|svg|webp|ico)$/ // 排除所有图片文件
- ]
- }),
- // 预获取其他资源 - 只在生产环境使用,排除图片资源
- new PreloadWebpackPlugin({
- rel: 'prefetch',
- include: 'asyncChunks', // 预获取异步chunk
- fileBlacklist: [
- /\.map$/,
- /hot-update\.js$/,
- /\.(png|jpg|jpeg|gif|svg|webp|ico)$/ // 排除所有图片文件
- ]
- }),
- // Gzip压缩 - 提高加载速度,减少带宽消耗
- new CompressionWebpackPlugin({
- algorithm: 'gzip',
- test: /\.(js|css|html|svg)$/,
- threshold: 8192, // 8KB以上的文件才压缩
- minRatio: 0.8,
- deleteOriginalAssets: false // 保留原文件
- }),
- // Brotli压缩 - 比Gzip更高的压缩率
- new CompressionWebpackPlugin({
- algorithm: 'brotliCompress',
- test: /\.(js|css|html|svg)$/,
- compressionOptions: {
- level: 11,
- },
- threshold: 8192,
- minRatio: 0.8,
- filename: '[path][base].br',
- deleteOriginalAssets: false
- })
- ] : []),
-
- optimization: {
- minimize: isProduction,
- minimizer: [
- new TerserPlugin({
- terserOptions: {
- compress: {
- drop_console: isProduction,
- drop_debugger: isProduction
- }
- },
- parallel: 2 // 减少并行处理数量,降低内存使用
- }),
- // 添加CSS压缩器
- new CssMinimizerPlugin({
- parallel: 2,
- minimizerOptions: {
- preset: [
- 'default',
- {
- discardComments: { removeAll: true },
- },
- ],
- },
- })
- ],
- splitChunks: {
- chunks: 'all',
- maxInitialRequests: 6, // 减少初始请求数量
- maxAsyncRequests: 8, // 减少异步请求数量
- minSize: 100000, // 100KB 最小包大小,避免过小的包
- maxSize: 8000000, // 8MB 最大包大小,允许更大的包
- cacheGroups: {
- // Vue 生态系统合并打包
- vue: {
- test: /[\\/]node_modules[\\/](vue|vue-router|vuex|@vue)[\\/]/,
- name: 'vue-vendor',
- chunks: 'all',
- priority: 30,
- enforce: true // 强制打包,不受大小限制
- },
- // Element UI 完整生态
- elementUI: {
- test: /[\\/]node_modules[\\/](element-ui|element-theme-|@element)[\\/]/,
- name: 'element-ui',
- chunks: 'all',
- priority: 25,
- enforce: true
- },
- // 大型第三方库合并
- largeLibs: {
- test: /[\\/]node_modules[\\/](echarts|artplayer|hls\.js|mpegts\.js|fabric|@ct\/ct_map_ol|@ct\/icons-v2)[\\/]/,
- name: 'large-libs',
- chunks: 'all',
- priority: 23,
- enforce: true
- },
- // 工具库合并
- utils: {
- test: /[\\/]node_modules[\\/](lodash|moment|dayjs|axios|crypto-js|uuid|classnames|immer)[\\/]/,
- name: 'utils',
- chunks: 'all',
- priority: 21,
- enforce: true
- },
- // CT组件库合并
- ctComponents: {
- test: /[\\/]node_modules[\\/]@ct[\\/]/,
- name: 'ct-components',
- chunks: 'all',
- priority: 20,
- enforce: true
- },
- // 其他第三方库
- vendor: {
- test: /[\\/]node_modules[\\/]/,
- name: 'vendors',
- chunks: 'all',
- priority: 10,
- minSize: 200000, // 200KB 最小大小
- enforce: true
- },
- // 公共代码 - 更宽松的条件
- common: {
- name: 'common',
- minChunks: 2,
- chunks: 'all',
- priority: 5,
- reuseExistingChunk: true,
- minSize: 50000, // 50KB
- maxSize: 3000000 // 3MB
- }
- }
- }
- },
-
- devServer: {
- host: '0.0.0.0',
- historyApiFallback: true,
- static: [
- {
- directory: path.join(__dirname, 'public'),
- publicPath: getPublicPath()
- },
- // 添加静态资源服务,支持第三方CSS包的相对路径访问
- {
- directory: path.join(__dirname, 'src/components/common-assets/image'),
- publicPath: '/static/image'
- }
- ],
- // open: true,
- compress: true,
- hot: true, // 只使用HMR,不用liveReload
- port: 3000,
- allowedHosts: 'all',
- // 开发服务器性能优化
- devMiddleware: {
- writeToDisk: false, // 不写入磁盘,提高速度
- stats: 'errors-only', // 只显示错误
- },
- client: {
- logging: 'error', // 只显示错误级别的日志
- overlay: {
- errors: true,
- warnings: false, // 不显示警告
- runtimeErrors: false // 减少运行时错误覆盖
- },
- progress: false, // 关闭进度条减少内存
- webSocketTransport: 'ws' // 使用更高效的WebSocket传输
- },
- proxy: [
- {
- context: ['/api'],
- target: 'http://localhost:3000',
- changeOrigin: true,
- pathRewrite: { '^/api': '' }
- }
- ]
- },
-
- // 文件监听优化 - 减少内存使用
- watchOptions: {
- ignored: ['**/node_modules/**', '**/.git/**', '**/dist/**', '**/.webpack/**', '**/.cache/**'], // 使用glob模式
- aggregateTimeout: 500, // 增加延迟,减少编译频率
- poll: false, // 使用原生文件监听,更高效
- followSymlinks: false // 不跟随符号链接
- },
-
- devtool: isDevelopment ? 'eval-cheap-module-source-map' : false,
-
- performance: {
- hints: false,
- maxAssetSize: 2000000,
- maxEntrypointSize: 2000000
- },
-
- // 内存优化
- cache: {
- type: 'filesystem',
- cacheDirectory: path.resolve(__dirname, '.webpack'),
- compression: 'gzip',
- // 限制缓存大小,防止内存溢出
- maxMemoryGenerations: isDevelopment ? 1 : 0,
- // 内存管理配置
- memoryCacheUnaffected: true,
- buildDependencies: {
- config: [__filename]
- }
- }
- }
|