7

Recently I am trying to optimize the performance of a web app(React). Assuming it is somewhat heavy as it consists of Code editors, Firebase, SQL, AWS SDK, etc. So I integrated react-loadable which will lazy load the components, After that, I got this Javascript heap out of memory issue.

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory in React

After some research(From a friend), I came to know that If we keep too many lazy loadings webpack will try to bundle them parallelly It might be the cause to get a Javascript heap memory issue, To confirm that I removed all Lazy loading routes in my App and built. Now build is successful. Later as suggested by the community I increased Node heap space size and got the below insights

First I increased it to 8 GB(8192) then build is success I got build time of around 72 mins, From next time onwards I am getting around 20 mins. Then I decreased heap memory size to 4 GB(4096) and getting build success it is around 15 - 20 mins. System configuration is 2vCPU, 16GB RAM(AWS EC2 Instance r5a.large).

Next, I kept build in another system (Mac book pro, i5, 8 GB RAM, 4 Cores) Now it took 30 mins, Second time it took 20 mins

So from these data points, I got a couple of questions

  1. Do we need to keep increasing heap space whenever we add some code? If yes what would be the average heap memory size in the community
  2. What would be the usual configuration for build systems for these kinds of heavy apps, Why because now I am not sure whether to increase the number of cores or RAM or Heap space or Altogether something to do with our app code.
  3. Do webpack provide any kind of solutions to avoid heap memory issue like limiting parallel processes, or any plugins?
  4. If at all it is related with our App code, Is there any standard process to debug where it is taking memory and to optimize based on that

PS : Some people suggested to keep GENERATE_SOUCREMAP=false it got worked but we need source maps as they will be helpful in debugging production issues

4

2 回答 2

2

最后,我可以在heap out of memory不增加堆内存空间的情况下解决这个问题。

正如问题中提到的,如果我删除所有懒惰的路线,构建就会成功,或者我必须保留 4GB 堆空间才能在大量构建时间的情况下成功。当使用 4GB 堆空间构建成功时,我观察到将近 8 - 10 个块文件大小接近 1MB。所以我使用Source map explorer分析了所有这些块。在所有块中包含几乎相同的库代码(在我的情况下,那些是 Firebase、视频播放器等很重)

因此,在我的假设中,当 webpack 尝试捆绑所有这些块时,它必须在每个块中构建所有这些库依赖关系图,这反过来又会导致堆内存空间问题。所以我使用可加载组件来延迟加载这些库。

在延迟加载所有这些库之后,所有块文件的大小几乎减少了一半,并且在不增加任何堆空间的情况下构建成功,构建时间也减少了。

优化后,如果我继续构建6vCPU,i7 系统大约需要3-4 分钟,我观察到基于系统中可用的核心数量,构建时间正在减少。如果我继续构建 2vCPU 系统,有时需要大约 20 - 25 分钟

于 2021-06-05T10:34:15.340 回答
0

Vanilla webpack 是为单体构建而开发的。它的主要目的是获取许多模块并将它们捆绑到一个(不是很多)中。如果你想保持模块化,你想使用webpack-module-federationWMF):

  1. WMF允许您开发可以轻松地相互依赖(和延迟加载)的独立包。
  2. 这些包将自动在彼此之间共享依赖关系。

如果没有 WMF,webpack 不允许上述任何操作。

简短的例子

  1. 库包app2提供组件Button
  2. 应用程序包使用app1它。
  3. 时机成熟时,app1使用 dynamic 请求组件import
  4. 您可以使用React.lazy包装负载,如下所示:
    const RemoteButton = React.lazy(() => import("app2/Button"));
    
    • 例如,您可以在 auseEffectRoute.render回调等中执行此操作。
  5. app1可以使用该组件,一旦它被加载。加载时,您可能希望显示加载屏幕(例如使用Suspense):
    <React.Suspense fallback={<LoadingScreen />}>
      <RemoteButton />
    </React.Suspense>
    
  • 或者,不要使用lazyand Suspense,只需获取从import(...)语句返回的承诺,并以您喜欢的任何方式处理异步加载。当然,WMF完全不限于react动态加载任何模块。

另一方面,WMF动态加载必须使用动态import(即import(...)),因为:

  1. 非动态导入将始终在加载时解析(从而使其成为非动态依赖项),并且
  2. “动态require”不能被 webpack 捆绑,因为浏览器没有这个概念commonjs(除非你使用一些 hack,在这种情况下,你将失去相关的“加载promise”)。

文档

尽管根据我的经验,WMF它是成熟的、易于使用的,并且可能已经准备好生产,但它的官方文档目前只是一个不太完善的概念注释集合。这就是为什么我会推荐它作为“入门”指南

于 2021-06-05T18:28:29.810 回答