英文:
React is not being used, yet is still pulled in into a bundle
问题
以下是您要的翻译:
tldr; 什么阻止了在我的项目中消除 React 的死代码?
它没有被使用,除了在我所使用的库的一个未使用的工具中。
我最近创建了一个用于重试失败的动态导入的小库。我创建了一个与 React 无关的模块,另一个专门处理了 React 的特殊情况。这是为了确保消费者在不使用 React 工具时不会引入 React。然后,我创建了一个索引模块,它引入了这两个模块并导出了命名常量。
import _createDynamicImportWithRetry from "./dynamic-import-with-retry";
import _reactLazy from "./react-lazy";
export const reactLazyWithRetry = _reactLazy;
export const createDynamicImportWithRetry = _createDynamicImportWithRetry;
这是 package.json
中的 main
字段。
我之前的阅读中认为,当 Vite 使用这个库时,它应该能够了解只导入命名导出 createDynamicImportWithRetry
只需要引入 "./dynamic-import-with-retry",而不需要引入其他导入。不幸的是,事实似乎并非如此:我发布了一个项目,显示情况并非如此:无论是否使用它,都会捆绑传递性的 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.reactLazyWithRetry( () => 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
这里的问题是那 9KB。它应该更接近 500 字节,但它引入了 React 的全部生产构建 :/
英文:
tldr; what is preventing React from being dead-code eliminated in my project?
It is not being used, apart in an unused utility in a library I am consuming.
I recently created a little library for retrying failing dynamic imports. I made a non-react-dependant module and another one that just handled the react specifics. This was to ensure a consumer would not pull in React if not using the react utils. I then created an index module that pulled the two in and exported named constants
import _createDynamicImportWithRetry from "./dynamic-import-with-retry";
import _reactLazy from "./react-lazy";
export const reactLazyWithRetry = _reactLazy;
export const createDynamicImportWithRetry = _createDynamicImportWithRetry;
This is the main
field in package.json
.
I assumed from previous reading that when Vite consumes this library it should be able to gather that just importing the named export createDynamicImportWithRetry
would only require pulling in "./dynamic-import-with-retry", not the other import. Unfortunately, that does not seem to be the case: I published a project that shows it not to be the case: the transitive React dependency is being bundled, no matter if it is unused.
I would have assumed that dead-code analysis during bundling for production would have pruned the unused imports of the tree. How can I ensure pruning of dead branches take place?
Reproduction:
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.reactLazyWithRetry( () => 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
The 9KB there is the problem. It should be closer to 500 bytes, but it pulls in all of the React production build :/
答案1
得分: 2
你需要告诉你正在使用的打包工具,React 应该由你库的客户端提供,而不应该与你的库一起打包。这被称为外部化。
要了解如何在 package.json 和你的打包工具中完成这个操作的一般思路,你可以查看我的之前的回答,使用 Rollup。如果你正在使用 Vite,外部化配置更加简单,可以参考这里。
英文:
You've got to tell whichever bundler you are using that react is supposed to be provided by the client of your lib, ie. that it shouldn't be bundled with your lib. This is called externalization.
To get a general idea how this is done in both package.json and in your bundler, you can check my previous answer using Rollup. If you are using Vite, the externalization is even simpler to configure.
答案2
得分: 1
我在Vite讨论板上发布了这个问题,结果发现Rollup目前还不能跟踪赋值操作(截止到2023年5月)。
> Rollup目前还不能跟踪赋值操作,因此在赋值操作的右侧,所有属性都会被取消优化。另外,Rollup取消优化不了解执行流程,因此它假设lazy可能是require$$0.lazy=()=>{}中的一个setter,这是一个副作用。可能不太容易修复。
由于Vite依赖于Rollup进行捆绑,除了将导出移出根模块并在package.json中单独导出它(这是我在版本2中所做的),没有其他办法。
英文:
I posted this on the Vite discussion board and it turns out that Rollup cannot track assignments yet (per May 2023).
> Rollup cannot track assignments (yet), so we deoptimize all properties of the right-hand side on assignments. Also, Rollup deoptimization does not know the execution flow, so it assumes that lazy might be a setter in require$$0.lazy=()=>{}, and that is the side effect. Probably not too easy to fix.
Since Vite relies on Rollup for bundling, there is nothing to do, apart from moving the export out of the root module and exporting it as its own specific export in package.json (which is what I did for version 2).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论