Awaiting a dynamic import
loadLibrary
is an asynchronous function, so it returns a promise instead of a regular object. Therefore you have to do await loadLibrary()
or loadLibrary().then(...)
to get the library object.
A consequence of this is that you can't statically export something that's imported dynamically, because static imports/export are done immediately and synchronously while dynamic imports are done asynchronously. You can only export the function loadLibrary
, and let users of the module call that when they need the library.
In short, once asynchronous, always asynchronous; you can't force something asynchronous to run synchronously in JavaScript.
Also, as an aside, your loadLibrary
function could be simplied a lot, to just
const loadLibrary = () => import('library');
since a) .then((r) => r)
just creates an identical copy of a promise, b) you don't have to await before returning in an async function (it's done automatically) and c) a function that returns a promise anyways doesn't have to be marked as async
(although you still can if you wish, for readability for example).
![mthmulders](https://i.stack.imgur.com/EFBUp.jpg?s=256&g=1)
mthmulders
Enthusiastic software developer with a passion for elegant solutions. Eager to learn new things, willing to help others do the same.
Updated on July 20, 2022Comments
-
mthmulders almost 2 years
I've created a web application with React and Typescript, using create-react-app. It uses a rather heavy third party library. I want to exclude that from the main bundle by using dynamic import expressions.
So, instead of doing
import { Component } from 'library'
, I've created a little wrapper that looks like this: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, };
And then, in my app, I'd use
import { Component } from '../library-wrapper.ts'
. Because the wrapper uses dynamic import expressions, Webpack creates a separate chunk which is only downloaded by the browser then it is actually needed.\o/
.But the bad news is: my wrapper doesn't actually await the dynamic import expression. It invokes the
loadLibrary()
function but immediately continues execution, loggingtypeof Component is undefined
So when I attempt to use the
Component
, React crashes:Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.
Any suggestions what is going on?
-
mthmulders about 6 yearsI thought the whole idea of async/await is that you could actually wait for a
Promise
to be resolved. Have I been wrong in this case? -
Frxstrem about 6 yearsYes, you're right, but you still have to use the
await
keyword to wait for a promise (to tell JS that it's the result of a promise you want instead of the promise itself). And because you can't run asynchronous code in a synchronous way (which I believe is due to the single-treaded design of JavaScript), you can only useawait
inside a function marked asasync
, otherwise you would have to use.then(r => { /* do something with result */ })
.