由于我的应用程序中很多地方都有很多图标,因此我想对它们使用代码拆分。
我已经创建了帮助程序组件来做到这一点:
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: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中止(核心已转储)
我的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>
});
答案 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和延迟加载的答案中已经建议的那样。