What am I'm doing wrong when trying to use dynamic import in Node.js code?
I am making a small CLI application. I am using dynamic module import (ES6). When using import at the beginning of the code, everything works as expected. Please see the code below:
#!/usr/bin/env node
const printf = console.log;
/*
* Module dependencies
*/
import os from 'node:os';
import fs from 'node:fs';
import util from 'node:util';
import chalk from 'chalk'; // Chalk 5 has changed to ESM
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers'
const usage = '\nUsage: $0 [options]';
const version = '0.0.1';
const argv = yargs(hideBin(process.argv))
.usage(usage)
.option('c', {
alias: 'colors',
description: 'Colored output',
type: 'boolean',
default: false,
demandOption: false
})
.help('help', 'Show help message')
.alias('help', 'h')
.version('version', version)
.alias('version', 'v')
.parse()
/*
Colored output if option 'colored' is true
*/
if (argv.colors == true) {
printf(chalk.green(' https://nodejs.org'));
} else {
printf(' https://nodejs.org');
}
printf(' ' + process.version);
printf('');
process.exit(0)
But I want to import the chalk
module only if the option '-c/--colored' is set at startup and the variable argv.colors
value is true. I want to use dynamic import with import() keyword code is below:
if (argv.colors == true) {
// console.log(argv.colors);
import('chalk')
.then(chalk => {
// let msg = chalk.green.bold(final_text);
// console.log(msg);
console.log(chalk.green.bold('https://nodejs.org'));
})
.catch(err => {
console.error(err);
});
}
But the import fails, no errors occur, this code block doesn't work. If it is possible to do as I want, please tell me how and what is my mistake.
Node version is:
$ node --version
v18.14.2
I tried to use async(), but also didn't get the result:
(async () => {
const colored = await import('chalk');
console.log(colored);
})().catch(err => console.error(err));
After @Quentin's comment I made the following changes in the code, and the import()
worked as it should. Final version:
// import chalk from 'chalk'; // Chalk 5 has changed to ESM
// import * as format from 'chalk';
if (argv.colors == true) {
console.log(argv.colors);
import('chalk')
.then(({default: chalk}) => {
console.log(chalk.green.bold(' https://nodejs.org'));
})
.catch(err => {
console.error(err);
});
} else {
printf(' https://nodejs.org');
}
// process.exit(0)
Console output:
true
v18.14.2
https://nodejs.org
But the import fails, no errors occur, this code block doesn't work.
When I run that code it errors with:
TypeError: Cannot read properties of undefined (reading 'bold')
If I read the MDN documentation it says:
Each module specifier corresponds to a unique module namespace object, so the following is generally true:
import * as mod from "/my-module.js"; import("/my-module.js").then((mod2) => { console.log(mod === mod2); // true });
Note the difference between your original code (import chalk from
) and the MDN documentation (import * as mod from
).
Here (.then(chalk => {
) the value of chalk
is all the exports and not just the default export.
Thus you should be explicit about what you are exporting (and rename it to a meaningful name):
.then(({default: chalk}) => {
Then you have a secondary problem:
process.exit(0);
You're explicitly quitting the program because the asynchronous import
has finished and triggered the then
callback.
Don't do that.