无法将React.lazy与Material UI图标一起使用

时间:2019-02-23 06:13:39

标签: node.js reactjs webpack react-hot-loader

由于我的应用程序中很多地方都有很多图标,因此我想对它们使用代码拆分。

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

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就会在编译期间崩溃,并出现低级错误:

  

69%的建筑15623/15657模块34处于活动状态   ... terial-ui / icons / AccessibleOutlined.d.ts <---后几个GC --->

     

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

     

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

     

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

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

0x1c000787d3b1>)       2:新集(又名Set)[0x2fea7a90391](this = 0x056d59402691,0x33036eb7fbe1)       3:ConstructFrame [pc:0x16ac48009e66]       4:StubFrame [pc:0x16ac480f932c]       5:processDependenciesBlocksForC ...                                                                    70%的块图致命错误:无效的标记压缩接近堆限制   分配失败-JavaScript堆内存不足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 :: CheckInvalidMarkCompact(无符号长整数,双精度)   [/ 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:0xee7​​e96   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中止(核心已转储)

我的Babel插件:

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',

从我看到的结果来看,它试图加载所有图标,而不仅仅是加载一个图标(为了简化解决方案,我将使用的实例减少为一个),然后它崩溃了。

更新

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


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

1 个答案:

答案 0 :(得分:2)

如果使用的是Webpack,则问题在于是否要动态加载文件,在这种情况下,默认情况下,图标webpack会为该模块生成一个块。如果您使用的是Webpack 4或更高版本,则可以使用webpackMode: eager解决此问题。因此,在这种情况下,导入将如下所示:

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

这基本上将迫使Webpack将块包含在您的包中(减少http请求的数量)-我认为这使使用Lazy / Suspense的整个观点毫无用处,但这Github issue与您的问题类似,并且表示不值得单独加载每个图标,即,您应该导入@material-ui/icons程序包并使用所需的图标。

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

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

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

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