为何未使用的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
相关产品推荐
相关产品推荐

