Yasin

Yasin

打包工具怎么控制产物生成

打包工具怎么控制产物生成


可以干预的环节

1. 入口(Entry)

告诉打包工具从哪里开始分析依赖:

// webpack.config.js
module.exports = {
  entry: {
    main: "./src/main.tsx",
    admin: "./src/admin.tsx", // 多入口,生成多个 bundle
  },
};

2. 输出(Output)

控制产物放在哪里、叫什么名字

module.exports = {
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "js/[name].[contenthash:8].js", // hash 文件名
    chunkFilename: "js/chunk.[contenthash:8].js", // 懒加载分包名
    clean: true, // 每次构建清空 dist
  },
};

3. 代码分割(Code Splitting)

控制怎么拆包

module.exports = {
  optimization: {
    splitChunks: {
      chunks: "all",
      cacheGroups: {
        // 第三方库单独打包
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: "vendor",
          chunks: "all",
        },
        // React 单独打包
        react: {
          test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
          name: "react",
          chunks: "all",
        },
      },
    },
  },
};

4. Tree Shaking

自动移除没用到的代码:

// package.json
{
  "sideEffects": false // 告诉打包工具所有模块都可以 Tree Shaking
}

// 或指定哪些文件有副作用,不能 Tree Shaking
{
  "sideEffects": ["*.css", "*.global.js"]
}

开发时写法也影响 Tree Shaking:

// ✅ 支持 Tree Shaking,只打包用到的
import { add } from "lodash-es";

// ❌ 整个 lodash 都打包进去
import _ from "lodash";

5. 懒加载(动态导入)

人为控制哪些代码延迟加载

// React
const HeavyPage = lazy(() => import("./HeavyPage"));

// 手动命名 chunk
const HeavyPage = lazy(
  () => import(/* webpackChunkName: "heavy-page" */ "./HeavyPage"),
);

6. 环境变量

控制不同环境的打包产物:

// webpack.config.js
module.exports = {
  plugins: [
    new webpack.DefinePlugin({
      "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
      "process.env.API_URL": JSON.stringify(process.env.API_URL),
    }),
  ],
};
// 代码里判断环境,生产打包会移除 dev 代码
if (process.env.NODE_ENV === "development") {
  console.log("调试信息"); // 生产包里这段会被移除
}

7. Loader(资源转换)

控制各种文件怎么处理

module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: "babel-loader", // TS/JSX 转 JS
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader", "postcss-loader"],
      },
      {
        test: /\.(png|jpg)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024, // 8kb 以下转 base64
          },
        },
      },
    ],
  },
};

8. 压缩(Minify)

控制产物怎么压缩

const TerserPlugin = require("terser-webpack-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true, // 移除所有 console.log
          },
        },
      }),
      new CssMinimizerPlugin(), // CSS 压缩
    ],
  },
};

常见优化手段汇总

优化点 方式 效果
减少首屏体积 懒加载 + 代码分割 首屏只下载必要代码
第三方库缓存 单独打包 vendor 库不变则长期缓存
移除无用代码 Tree Shaking 减少包体积
图片优化 小图转 base64 减少 HTTP 请求
压缩代码 Terser + CSS Minimizer 减少文件体积
移除调试代码 drop_console 减少体积
分析包体积 webpack-bundle-analyzer 找出体积大的模块

分析打包产物

用可视化工具找出哪个包体积大:

npm install webpack-bundle-analyzer -D
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin(), // 构建后自动打开可视化页面
  ],
};