Problem
Recently when writing a project of mine, I've written some javascript like this:
import itemA from '../items/itemA'; import itemB from '../items/itemB'; import itemC from '../items/itemC'; import itemD from '../items/itemD';
I'd really like some syntax like this:
for(const id of ['A','B','C','D']) { import (item+id) from '../items/item' + id; }
Turned out there's this stage 4 proposal of ECMAScript
called dynamic import
that goes like:
(async () => { await import('./my-app.mjs'); })();
and it's supported by all modern browsers as well as node.
Failed Attempt
Then I went on writing some line code like this:
importedItems = await Promise.all( itemNames.map(async itemName => { try { const imported = await import(`../items/${itemName}`); logger.debug(`Imported item: ${itemName}`); return imported; } catch (err) { logger.warning(`Failed to import item: ${itemName}`); return null; } }) );
But for later use of importedItems
, a TypeError
has been raised stating that the importedItems
are actually type of Module
instead of expected item
. I tried manual type casting like this:
return Item(imported);
But it didn't work and since it's not yet standardized feature (Due to be standardized in ECMAScript 2020), there's little information about it so I have to figure it out myself.
After a long time with JSON.stringify()
and console.log
I finally figured it out.
Solution
It should work like this:
return imported.default;
Full working snippet
importedItems = await Promise.all( itemNames.map(async itemName => { try { const imported = await import(`../items/${itemName}`); logger.debug(`Imported item: ${itemName}`); return imported.default; } catch (err) { logger.warning(`Failed to import item: ${itemName}`); return null; } }) );
Reason
The reason is that when we use an import
statement like this:
import item from './itemA';
it automatically loads the default export
of module 'itemA'
into the item
.
But when we do expression like dynamic import like this:
(async () => { const item = await import('./itemA'); })();
the item is a Module
, by accessing Module.default
we are able to fetch its default export, same goes for any other exports.
originally posted on: https://blog.llldar.io/Article/View/44
Top comments (2)
Let's say I have three modules.
We could write an intermediary function that will return the default exported module out of a dynamic imported one.
Of course, you can import named exported modules as well like usual.
N.B.: if you want to test this code, you'll have to run this command with a compliant version of Node.js supporting experimental modules.
Nice complement, I didn't mention I was using esm. If anyone want to use the
import export
without having to name your file.mjs
on node, try it out.