// 引入 Node.js 的 path 模块,用于处理文件路径
const path = require('path');
// 引入 HTML Webpack 插件,用于自动生成 HTML 文件并注入打包后的资源
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 引入 Vue Loader 插件,用于处理 .vue 单文件组件
const { VueLoaderPlugin } = require('vue-loader');

/**
 * Webpack 配置导出函数
 * @param {Object} env - 环境变量对象
 * @param {Object} argv - 命令行参数对象,包含 mode 等信息
 * @returns {Object} Webpack 配置对象
 */
module.exports = (env, argv) => {
  // 判断当前是否为开发环境
  const isDevelopment = argv.mode === 'development';

  return {
    // ==================== 入口配置 ====================
    // 指定应用的入口文件,Webpack 从这里开始构建依赖图
    entry: './src/main.ts',

    // ==================== 输出配置 ====================
    output: {
      // 输出目录的绝对路径,所有打包后的文件都会放在这里
      path: path.resolve(__dirname, 'dist'),
      // 输出文件的命名规则:
      // - 开发环境:使用 [name].js(如 main.js)
      // - 生产环境:使用 [name].[contenthash].js(如 main.abc123.js),利用内容哈希实现缓存优化
      filename: isDevelopment ? '[name].js' : '[name].[contenthash].js',
      // 每次构建前自动清空输出目录,确保没有旧文件残留
      clean: true,
    },
    // ==================== 模块解析配置 ====================
    resolve: {
      // 导入文件时可省略的文件扩展名,Webpack 会按顺序尝试这些扩展名
      extensions: ['.ts', '.js', '.vue', '.json'],
      // 路径别名配置,简化导入路径
      alias: {
        // '@' 指向 src 目录,例如 '@/components/HelloWorld.vue' 等同于 './src/components/HelloWorld.vue'
        '@': path.resolve(__dirname, 'src'),
        // 指定使用 Vue 的完整版本(包含模板编译器),支持运行时编译模板
        vue: 'vue/dist/vue.esm-bundler.js',
      },
    },
    // ==================== 模块处理规则 ====================
    // 定义不同文件类型的处理规则(loader)
    module: {
      rules: [
        // 规则 1:处理 Vue 单文件组件 (.vue)
        {
          test: /\.vue$/,           // 匹配所有 .vue 文件
          loader: 'vue-loader',     // 使用 vue-loader 处理
        },
        // 规则 2:处理 TypeScript 文件 (.ts)
        {
          test: /\.ts$/,            // 匹配所有 .ts 文件
          use: 'ts-loader',         // 使用 ts-loader 将 TypeScript 编译为 JavaScript
          exclude: /node_modules/,  // 排除 node_modules 目录,提高构建速度
        },
        // 规则 3:处理 JavaScript 文件 (.js)
        {
          test: /\.js$/,            // 匹配所有 .js 文件
          use: 'babel-loader',      // 使用 Babel 转译 ES6+ 语法,确保浏览器兼容性
          exclude: /node_modules/,  // 排除 node_modules 目录
        },
        // 规则 4:处理 SCSS/Sass 样式文件 (.scss)
        {
          test: /\.scss$/,          // 匹配所有 .scss 文件
          // 使用多个 loader,从右到左执行:
          // 1. sass-loader:将 SCSS 编译为 CSS
          // 2. css-loader:解析 CSS 中的 import 和 url()
          // 3. style-loader:将 CSS 注入到 DOM 中(通过 <style> 标签)
          use: [
            'style-loader',
            'css-loader',
            'sass-loader',
          ],
        },
        // 规则 5:处理普通 CSS 文件 (.css)
        {
          test: /\.css$/,           // 匹配所有 .css 文件
          use: [
            'style-loader',         // 将 CSS 注入 DOM
            'css-loader',            // 解析 CSS 模块
          ],
        },
        // 规则 6:处理静态资源文件(图片等)
        {
          test: /\.(png|jpe?g|gif|svg)$/i,  // 匹配常见图片格式(不区分大小写)
          type: 'asset/resource',           // 使用 Webpack 5 的资源模块,将文件输出到 dist 目录
        },
      ],
    },
    // ==================== 插件配置 ====================
    // Webpack 插件用于执行更广泛的任务,如打包优化、资源管理等
    plugins: [
      // Vue Loader 插件:必须添加,用于应用 Vue 文件中定义的 loader 规则
      new VueLoaderPlugin(),
      // HTML Webpack 插件:基于模板生成 HTML 文件,并自动注入打包后的 JS/CSS 资源
      new HtmlWebpackPlugin({
        template: './public/index.html',  // HTML 模板文件路径
        title: 'Webpack Vue3 TS App',     // 页面标题(可在模板中使用 <%= htmlWebpackPlugin.options.title %> 引用)
      }),
    ],
    // ==================== 开发服务器配置 ====================
    // webpack-dev-server 的配置选项,用于本地开发环境
    devServer: {
      // 静态文件服务配置
      static: {
        directory: path.join(__dirname, 'public'),  // 提供静态文件的目录
      },
      port: 8080,                // 开发服务器监听的端口号
      hot: true,                 // 启用热模块替换(HMR),修改代码后无需刷新页面
      open: true,                // 启动服务器后自动打开浏览器
      historyApiFallback: true,  // 当使用 HTML5 History API 时,所有路由都回退到 index.html(适用于 SPA 路由)
    },
    // ==================== Source Map 配置 ====================
    // 控制是否以及如何生成 source map,用于调试
    // - 开发环境:使用 'eval-source-map',构建速度快,调试信息完整
    // - 生产环境:使用 'source-map',生成独立的 .map 文件,便于线上问题排查
    devtool: isDevelopment ? 'eval-source-map' : 'source-map',
  };
};

更多推荐