基于webpack5搭建前端工程

webpack.config.js

const path = require('path');
const webpack = require('webpack');
const { VueLoaderPlugin } = require("vue-loader")
const CopyWebpackPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const { ModuleFederationPlugin } = require('webpack').container;

const isProdEnv = process.env.NODE_ENV === "production";
const publicPath = isProdEnv ? "/test/"  : '/';

module.exports = {
    stats: {
        // 禁用所有警告
        warnings: false
    },
    mode: isProdEnv ? 'production' : "development",
    entry: path.resolve(__dirname, 'src/main.js'),
    output: {
        publicPath: publicPath,
        // 打包产物的输出目录
        path: path.join(__dirname,"dist"),
        filename: 'static/js/[name].[contenthash:8].js',
        // 清空产物文件夹
        clean: true,
    },
    devtool: isProdEnv ? false : 'eval-cheap-source-map',
    devServer: {
        port: 8080,
        open: true,
        hot: true,
        proxy: [
          {
            context: '/api',
            target: 'http://127.0.0.1:9000',
            headers: {
                Referer: 'http://127.0.0.1:9000', 
            },
            secure: false,
            changeOrigin: true,
            pathRewrite: {
                '^/api': '/api'
            }
          }
        ],
        headers: {
            'Access-Control-Allow-Origin': '*',
            'Cross-Origin-Opener-Policy': 'same-origin',
            'Cross-Origin-Embedder-Policy': 'require-corp',
            'Cross-Origin-Resource-Policy': 'cross-origin'
        },
        historyApiFallback: true,
        client: {
            overlay: {
                warnings: false,
                errors: false,
            },
        },
    },
    plugins: [
        new VueLoaderPlugin(),
        new HtmlWebpackPlugin({
            title: '标题',
            template: './public/index.html',
            // 自定义属性
            prodPublicPath: publicPath,
        }),
        // 用于分析 Webpack 打包后的文件体积和依赖关系
        new BundleAnalyzerPlugin({
            // 禁用默认启动,手动触发
            // server, static, json, disabled
            analyzerMode: "disabled",
            // 是否自动打开浏览器
            openAnalyzer: false,
            analyzerPort: 8888,
            analyzerHost: "127.0.0.1",
            defaultSizes: "parsed",
            reportFilename: "report.html",
            // 是否生成 stats.json 文件
            generateStatsFile: false,
            statsFilename: "stats.json",
            // 控制 stats 文件的输出内容
            statsOptions: {
                source: false
            },
            logLevel: "info",
            // 排除 .map 文件
            excludeAssets: /\.map$/,
        }),
        new CopyWebpackPlugin({
            patterns: [
                {
                    from: path.join(__dirname, `/public/favicon.ico`),
                    to: 'favicon.ico',
                },
            ]
        }),
        new webpack.DefinePlugin({
            // Vue 3 必需的定义
            __VUE_OPTIONS_API__: JSON.stringify(true),
            __VUE_PROD_DEVTOOLS__: JSON.stringify(false),
            // 环境变量定义
            'process.env': JSON.stringify({
                BASE_URL: publicPath,
                NODE_ENV: process.env.NODE_ENV === 'production' ? 'production' : 'development',
            })
        }),
        new ModuleFederationPlugin({
            shared: {
                'vue': {
                    singleton: true,
                    requiredVersion: '^3.2.40',
                    eager: true
                },
                'vue-router': {
                    singleton: true,
                    requiredVersion: '^4.0.12',
                    eager: true
                },
                'vuex': {
                    requiredVersion: '^4.0.2',
                    eager: true
                },
                'axios': {
                    singleton: true,
                    requiredVersion: '^1.12.0',
                    eager: true
                },
                'vue-i18n': {
                    requiredVersion: '^9.1.7',
                    eager: true
                },
                'echarts': {
                    requiredVersion: '^5.4.0',
                    eager: true
                },
            }
        })
    ],
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader',
                exclude: /node_modules/
            },
            {
                test: /\.(js|mjs|jsx|cjs)$/i,
                exclude: /node_modules/,
                include: [path.resolve(__dirname, 'src'), path.resolve(__dirname, "../public")],
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'],
                        plugins: [
                            ['@vue/babel-plugin-jsx', { compositionAPI: true }]
                        ]
                    }
                },
                generator: {
                    filename: 'static/js/[name].[hash:8][ext]'
                }
            },
            // 处理css资源
            {
                test: /\.css$/i,
                use: ['style-loader', 'css-loader'],
                generator: {
                    filename: 'static/css/[name].[hash:8][ext]'
                }
            },
            // 处理图片资源
            {
                test: /\.(png|jpg|svg|jpeg|gif)$/i,
                type: 'asset/resource',
                generator: {
                    filename: 'static/img/[name].[hash:8][ext]'
                }
            },
            // 样式文件规则:重点在这里
            {
                test: /\.module\.less$/,
                use: [
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            modules: {
                                // Vue CLI 默认使用
                                auto: true,
                                localIdentName: '[name]_[local]_[hash:base64:5]',
                            },
                            importLoaders: 2,
                            sourceMap: true,
                            esModule: false, // 关键:让 default export 为 locals
                        },
                    },
                    {
                        loader: 'less-loader',
                        options: {
                            sourceMap: true,
                        }
                    },
                ],
            },
            {
                test: /\.less$/,
                exclude: /\.module\.less$/,
                use: [
                    'style-loader',
                    'css-loader',
                    {
                        loader: 'less-loader',
                        options: {
                            sourceMap: true,
                            additionalData: `
                                @isDev: ${process.env.NODE_ENV === 'development'};
                            lessOptions: {
                                modifyVars: {
                                    "font-size-base": "12px",
                                },
                                javascriptEnabled: true,
                            },
                        }
                    }
                ],
                generator: {
                    filename: 'static/css/[name].[hash:8][ext]'
                }
            }, {
                test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
                use: {
                    loader: 'file-loader',
                    options: {
                        name: 'static/fonts/[name].[ext]',
                        esModule: false
                    }
                },
                generator: {
                    filename: 'static/fonts/[name].[hash:8][ext]'
                }
            }
        ]
    },
    resolve: {
        // 指定模块导入时,可省略的扩展名
        extensions: ['.js', '.vue', '.jsx', '.json'],
        // 路径别名
        alias: {
            'vue$': 'vue/dist/vue.esm-bundler.js',
            '@': path.join(__dirname, 'src'),
        },
        modules: [path.resolve(__dirname, "node_modules"), path.resolve(__dirname, "../node_modules")],
    },
    optimization: {
        // 提取 webpack runtime 到一个单独的 chunk
        runtimeChunk: 'single',
        // 代码分割配置
        splitChunks: {
            chunks: 'async',
            cacheGroups: {
                // 异步导入的图标组件打包成一个js
                asyncComponents: {
                    test: /[\\/]public[\\/]components[\\/]IconSvg[\\/]/,
                    name: 'IconSvg-AsyncComponents',
                    minChunks: 1,
                    priority: 20,
                    chunks: 'all',
                    reuseExistingChunk: true,
                    enforce: true,
                }
            }
        },
        minimize: true,
        minimizer: [
            new TerserPlugin({
                terserOptions: {
                    compress: {
                        // 可选:移除 console
                        // drop_console: true,
                    },
                },
                // 打包产物不提取注释到 .LICENSE.txt
                extractComments: false,
            }),
        ],
    },
}

package.json

{
    "name": "test",
    "version": "0.1.0",
    "private": true,
    "scripts": {
        "serve": "cross-env NODE_ENV=development node --max-old-space-size=2048 ./node_modules/webpack/bin/webpack.js serve",
        "build": "cross-env NODE_ENV=production node --max-old-space-size=4096 ./node_modules/webpack/bin/webpack.js"
    },
    "dependencies": {},
    "devDependencies": {
        "@babel/core": "^7.28.5",
        "@babel/preset-env": "^7.28.5",
        "@vue/babel-plugin-jsx": "^2.0.1",
        "babel-loader": "^10.0.0",
        "copy-webpack-plugin": "^12.0.2",
        "cross-env": "^10.1.0",
        "css-loader": "^7.1.2",
        "eslint": "^8.57.1",
        "eslint-plugin-vue": "^10.5.1",
        "html-webpack-plugin": "^5.6.3",
        "less": "^4.5.1",
        "less-loader": "^12.3.0",
        "style-loader": "^4.0.0",
        "terser-webpack-plugin": "^5.3.16",
        "vue-loader": "^17.4.2",
        "webpack": "^5.99.9",
        "webpack-bundle-analyzer": "^4.10.2",
        "webpack-cli": "^6.0.1",
        "webpack-dev-server": "^5.2.2"
    },
    "browserslist": [
        "> 1%",
        "last 2 versions",
        "not dead",
        "Chrome >= 78"
    ]
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容