You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何未使用的React仍被打包?死代码消除失效排查

问题

我开发了一个用于重试失败动态导入的库@fatso83/retry-dynamic-import,已拆分出无React依赖的核心模块和React专属模块,期望用户仅导入所需模块时,不会将React打包进产物。

当前主入口index.ts代码如下:

import _createDynamicImportWithRetry from "./dynamic-import-with-retry";
import _reactLazy from "./react-lazy";

export const reactLazyWithRetry = _reactLazy;
export const createDynamicImportWithRetry = _createDynamicImportWithRetry;

该入口被设置为package.json的main字段。原本以为Vite打包时会通过Tree Shaking剔除未使用的代码,但实际情况是:即便用户仅使用非React的导出,React仍会被打包进最终产物。

复现步骤:

mkdir tmp-proj && cd tmp-proj && mkdir src

echo '<script type="module" src="./src/index.js"></script>' > index.html

echo "import * as o from '@fatso83/retry-dynamic-import'
o.createDynamicImportWithRetry( () => Promise.resolve())" > src/index.js

npm i @fatso83/retry-dynamic-import; npm i vite

npx vite build 

# 输出结果:
# vite v4.3.5 building for production...
# ✓ 13 modules transformed.
# dist/index.html                0.08 kB │ gzip: 0.09 kB
# dist/assets/index-4e07d3ed.js  9.27 kB │ gzip: 3.89 kB
# 注:产物包含完整React生产包,预期仅约500字节

解决方案

1. 拆分独立入口,配置package.json的exports字段

这是最可靠的方案,通过为不同功能模块设置独立入口,让用户按需导入,从根源避免无用代码被引入。

修改package.json,添加exports字段(优先级高于main):

{
  "name": "@fatso83/retry-dynamic-import",
  "main": "./index.ts",
  "exports": {
    ".": "./index.ts",
    "./core": "./dynamic-import-with-retry.ts",
    "./react": "./react-lazy.ts"
  }
}

用户使用时可直接导入对应模块:

// 仅导入核心功能,无React依赖
import { createDynamicImportWithRetry } from '@fatso83/retry-dynamic-import/core';

// 仅导入React专属功能
import { reactLazyWithRetry } from '@fatso83/retry-dynamic-import/react';

2. 对React模块使用动态导入+条件导出

若想保留单入口的使用方式,可在主入口文件中使用动态导入,让Tree Shaking识别并剔除无用分支。

修改index.ts:

export { createDynamicImportWithRetry } from "./dynamic-import-with-retry";

// 仅当用户调用该导出时才加载React相关代码
export const reactLazyWithRetry = async () => {
  const { default: reactLazy } = await import("./react-lazy");
  return reactLazy;
};

注意:这种方式会改变API的使用形式,用户需异步调用reactLazyWithRetry,需根据库的使用场景权衡。

3. 将React标记为可选peer依赖

在package.json中把React设为peerDependencies,并标记为可选,确保库自身不会打包React,由用户项目按需提供:

{
  "peerDependencies": {
    "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
  },
  "peerDependenciesMeta": {
    "react": {
      "optional": true
    }
  }
}

4. 优化Tree Shaking触发条件

确保库采用ES模块格式,并在package.json中添加以下配置,明确告知打包工具模块无副作用,可安全进行Tree Shaking:

{
  "type": "module",
  "sideEffects": false
}

内容的提问来源于stack exchange,提问作者oligofren

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 01:47:16