我使用create-react-app使用React和Typescript创建了一个Web应用程序。它使用了相当重的第三方库。我想使用dynamic import expressions将其从主要包中排除。
所以,我没有做import { Component } from 'library'
,而是创建了一个看起来像这样的小包装器:
const loadLibrary = async () => {
const x = await import('library').then((r) => r);
return x;
};
const {
Component,
} = loadLibrary() as any;
// tslint:disable-next-line:no-console
console.log(`typeof Component is ${typeof Component}`);
export {
Component,
};
然后,在我的应用中,我会使用import { Component } from '../library-wrapper.ts'
。
因为包装器使用动态导入表达式,所以Webpack创建了一个单独的块,只有浏览器才会下载,然后才需要它。 \o/
。
但坏消息是:我的包装器实际上并没有等待动态导入表达式。它调用loadLibrary()
函数但立即继续执行,记录
typeof Component未定义
所以当我尝试使用Component
时,React崩溃了:
元素类型无效:期望一个字符串(用于内置组件)或一个类/函数(用于复合组件)但得到:undefined。
有什么建议吗?
答案 0 :(得分:4)
loadLibrary
是一个异步函数,因此它返回一个promise而不是一个常规对象。因此,您必须执行await loadLibrary()
或loadLibrary().then(...)
才能获取库对象。
这样做的结果是您无法静态导出动态导入的内容,因为静态导入/导出是在异步完成动态导入时立即同步完成的。您只能导出函数loadLibrary
,并让模块的用户在需要库时调用它。
简而言之,一旦异步,总是异步;你不能强迫异步在JavaScript中同步运行。
另外,除此之外,您的loadLibrary
功能可能会被简化,只是
const loadLibrary = () => import('library');
因为a).then((r) => r)
只是创建一个相同的承诺副本,b)你不必等待在返回异步函数之前(它自动完成)和c)a返回一个承诺的函数无论如何都不必标记为async
(尽管如果你愿意,你仍然可以,例如,为了便于阅读)。