不能将 React.lazy 与 Material UI 图标一起使用 [英] Cannot use React.lazy with Material UI icons

查看:33
本文介绍了不能将 React.lazy 与 Material UI 图标一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因为我在我的应用程序的很多地方都有很多图标,我想对它们使用代码拆分.

as I have quite a lot of icons in many places in my app, I want to use code splitting for them.

我已经创建了帮助组件来做到这一点:

I have created helper component to do that:

import React, { FunctionComponent, Suspense } from 'react';

interface LazyMuiIconProps {
  name: string;
}

export const LazyMuiIcon: FunctionComponent<LazyMuiIconProps> = ({ name }) => {
  console.log(name);
  const IconElement = React.lazy(() => import(`@material-ui/icons/${name}`));
  // const IconElement = React.lazy(() => import(`@material-ui/icons/Home`));
  return (
    <Suspense fallback={null}>
      <IconElement />
    </Suspense>
  );
};

当我对 Home 使用带有固定名称的注释行时,它可以正常工作并且延迟加载主页图标,但是一旦我将其更改为上面的行,webpack 在编译期间崩溃并出现低级错误:

When I use commented line with fixed name to Home it works and it lazy loads the Home icon, however as soon as I change it to the line above, webpack crashes during compilation with low level error:

69% 构建 15623/15657 模块 34 个活动...terial-ui/icons/AccessibleOutlined.d.ts <--- 最后几次 GC --->

69% building 15623/15657 modules 34 active ...terial-ui/icons/AccessibleOutlined.d.ts <--- Last few GCs --->

[30:0x33f4320] 77272 毫秒:清除 1142.0 (1422.8) -> 1141.5(1423.3) MB,1.4/0.0 ms(平均 mu = 0.300,当前 mu = 0.342)分配失败 [30:0x33f4320] 77275 毫秒:Scavenge 1142.3(1423.3) -> 1141.7 (1423.8) MB,1.5/0.0 毫秒(平均 mu = 0.300,当前 mu = 0.342) 分配失败 [30:0x33f4320] 77278 毫秒:清除 1142.4 (1423.8) -> 1141.9 (1424.3) MB,1.5/0.0 毫秒(平均mu = 0.300, 当前 mu = 0.342) 分配失败

[30:0x33f4320] 77272 ms: Scavenge 1142.0 (1422.8) -> 1141.5 (1423.3) MB, 1.4 / 0.0 ms (average mu = 0.300, current mu = 0.342) allocation failure [30:0x33f4320] 77275 ms: Scavenge 1142.3 (1423.3) -> 1141.7 (1423.8) MB, 1.5 / 0.0 ms (average mu = 0.300, current mu = 0.342) allocation failure [30:0x33f4320] 77278 ms: Scavenge 1142.4 (1423.8) -> 1141.9 (1424.3) MB, 1.5 / 0.0 ms (average mu = 0.300, current mu = 0.342) allocation failure

<--- JS 堆栈跟踪 --->

<--- JS stacktrace --->

==== JS 堆栈跟踪 =========================================

==== JS stack trace =========================================

0: ExitFrame [pc: 0x16ac4804fb5d] Security context: 0x02fea7a9d921 <JSObject>
1: add [0x2fea7a906c9](this=0x10fbf120c2e1 <Set map = 0x3f914303d81>,0x1a97709947e1 <DependenciesBlock map =

0x1c000787d3b1>)2:新集(又名集)[0x2fea7a90391](this=0x056d59402691 ,0x33036eb7fbe1)3:构造帧[pc:0x16ac48009e66]4:StubFrame [pc:0x16ac480f932c]5:processDependenciesBlocksForC...70% 块图致命错误:接近堆限制的无效标记压缩分配失败 - JavaScript 堆内存不足 1:0x948d20节点::中止() [/usr/local/bin/node] 2: 0x9499bcnode::OnFatalError(char const*, char const*) [/usr/local/bin/node] 3:0xb1160e v8::Utils::ReportOOMFailure(v8::internal::Isolate*, charconst*, bool) [/usr/local/bin/node] 4: 0xb11844v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, charconst*, bool) [/usr/local/bin/node] 5: 0xf0def2[/usr/local/bin/node] 6: 0xf0dff8v8::internal::Heap::CheckIneffectiveMarkCompact(unsigned long, double)[/usr/local/bin/node] 7: 0xf1a718v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector,v8::GCCallbackFlags) [/usr/local/bin/node] 8: 0xf1b22bv8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace,v8::internal::GarbageCollectionReason, v8::GCCallbackFlags)[/usr/local/bin/node] 9: 0xf1df61v8::internal::Heap::AllocateRawWithRetryOrFail(int,v8::internal::AllocationSpace, v8::internal::AllocationAlignment)[/usr/local/bin/node] 10: 0xee7​​e96v8::internal::Factory::AllocateRawArray(int,v8::internal::PretenureFlag) [/usr/local/bin/node] 11: 0xee885av8::internal::Factory::NewFixedArrayWithFiller(v8::internal::Heap::RootListIndex,int, v8::internal::Object*, v8::internal::PretenureFlag)[/usr/local/bin/node] 12: 0xee8900v8::内部::句柄v8::internal::Factory::NewFixedArrayWithMap(v8::internal::Heap::RootListIndex,int, v8::internal::PretenureFlag) [/usr/local/bin/node] 13: 0x108e547v8::internal::OrderedHashTable::Allocate(v8::internal::Isolate*, int, v8::internal::PretenureFlag)[/usr/local/bin/node] 14: 0x1091ab1v8::internal::OrderedHashTable::Rehash(v8::internal::Isolate*,v8::internal::Handle, int)[/usr/local/bin/node] 15: 0x109202bv8::internal::OrderedHashTable::EnsureGrowable(v8::internal::Isolate*,v8::内部::句柄)[/usr/local/bin/node] 16: 0x117ee2c v8::internal::Runtime_SetGrow(int,v8::internal::Object**, v8::internal::Isolate*) [/usr/local/bin/node]17: 0x16ac4804fb5d 中止(核心转储)

0x1c000787d3b1>) 2: new Set(aka Set) [0x2fea7a90391](this=0x056d59402691 ,0x33036eb7fbe1 ) 3: ConstructFrame [pc: 0x16ac48009e66] 4: StubFrame [pc: 0x16ac480f932c] 5: processDependenciesBlocksForC... 70% chunk graphFATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory 1: 0x948d20 node::Abort() [/usr/local/bin/node] 2: 0x9499bc node::OnFatalError(char const*, char const*) [/usr/local/bin/node] 3: 0xb1160e v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node] 4: 0xb11844 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node] 5: 0xf0def2 [/usr/local/bin/node] 6: 0xf0dff8 v8::internal::Heap::CheckIneffectiveMarkCompact(unsigned long, double) [/usr/local/bin/node] 7: 0xf1a718 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/usr/local/bin/node] 8: 0xf1b22b v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/usr/local/bin/node] 9: 0xf1df61 v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/usr/local/bin/node] 10: 0xee7e96 v8::internal::Factory::AllocateRawArray(int, v8::internal::PretenureFlag) [/usr/local/bin/node] 11: 0xee885a v8::internal::Factory::NewFixedArrayWithFiller(v8::internal::Heap::RootListIndex, int, v8::internal::Object*, v8::internal::PretenureFlag) [/usr/local/bin/node] 12: 0xee8900 v8::internal::Handle v8::internal::Factory::NewFixedArrayWithMap(v8::internal::Heap::RootListIndex, int, v8::internal::PretenureFlag) [/usr/local/bin/node] 13: 0x108e547 v8::internal::OrderedHashTable::Allocate(v8::internal::Isolate*, int, v8::internal::PretenureFlag) [/usr/local/bin/node] 14: 0x1091ab1 v8::internal::OrderedHashTable::Rehash(v8::internal::Isolate*, v8::internal::Handle, int) [/usr/local/bin/node] 15: 0x109202b v8::internal::OrderedHashTable::EnsureGrowable(v8::internal::Isolate*, v8::internal::Handle) [/usr/local/bin/node] 16: 0x117ee2c v8::internal::Runtime_SetGrow(int, v8::internal::Object**, v8::internal::Isolate*) [/usr/local/bin/node] 17: 0x16ac4804fb5d Aborted (core dumped)

我的 Babel 插件:

My Babel plugins:

plugins: [
                // plugin-proposal-decorators is only needed if you're using experimental decorators in TypeScript
                "@babel/plugin-syntax-dynamic-import",
                ['@babel/plugin-proposal-decorators', { legacy: true }],
                ['@babel/plugin-proposal-class-properties', { loose: true }],
                'react-hot-loader/babel',

据我所知,它正在尝试加载所有图标,而不仅仅是一个(我将使用的实例减少到一个以更轻松地找到解决方案),然后它崩溃了.

From what I see it is trying to load all icons, not just one (I reduced the used instance to one to find the solution easier) and then it crashes.

更新

如果我尝试使用 react-loadable...

Exactly the same happens if I try to use react-loadable...


return Loadable({
    loader: () => import(`@material-ui/icons/${props.name}`),
    loading: () => <span>icon</span>
  });

推荐答案

如果你使用 Webpack,问题是如果你想动态加载一个文件,在这种情况下是图标,webpack 默认为那个模块生成一个 chunk.如果你使用的是 Webpack 4 或更高版本,你可以使用 webpackMode:eager 来解决这个问题.因此,在这种情况下,导入将如下所示:

If you are using Webpack, the problem is if you want to dynamic load a file, in this case the icon, webpack by default generate a chunk for that module. If you are using Webpack 4 or later, you can use webpackMode: eager to solve this problem. So, in this case, the import will look something like this :

const IconElement = React.lazy(() => import(/* webpackMode: "eager" */`@material-ui/icons/${name}`));

这基本上会强制 Webpack 将块包含到您的包中(减少 http 请求的数量) - 我认为这使得使用 Lazy/Suspense 的整个点毫无用处,但这 Github issue 与您的问题类似,表明不值得单独加载每个图标,即,您应该宁愿导入 @material-ui/icons 包并使用您需要的图标.

This will basically force Webpack to include the chunk into your bundle ( reducing the number of http requests ) - which I think renders the whole point of using Lazy / Suspense useless but this Github issue is similar to your problem and indicates that it is not worth loading each icon separately, .i.e, you should rather import the @material-ui/icons package and use the icons which you need.

更新(因为关于 react-loader 的更新有问题):

UPDATE ( because of update in question with reference to react-loader ) :

在使用 react-loader 时,您还需要指定文件的扩展名.我曾经遇到过这个问题,并通过导入指定文件的扩展名来解决它.在这种情况下:

While using react-loader you also need to specify the extension of the file. I had faced this issue once and solved it by importing with extension for the file specified. In this case :

return Loadable({
    loader: () => import(`@material-ui/icons/${props.name}.ts`),
    loading: () => <span>icon</span>
  });

但我不确定它是否仍然有效,正如我在关于 Webpack 和延迟加载的回答中已经建议的那样.

But I am not sure if it will still work, as I already suggested in my answer regarding Webpack and lazy loading.

这篇关于不能将 React.lazy 与 Material UI 图标一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆