I've written a node.js command line application that uses ECMAScript modules, top-level await, and nullish coalescing operators so it requires at least node 14.
Older node.js versions can't even parse the script and throw a SyntaxException before evaluating anything. I want to print a friendly error telling users to upgrade to a supported version but I can't get around syntax errors.
#!/usr/bin/env node
# entry.cjs
if (process.version.split('.', 1)[0].slice(1) < 14) {
console.log('too old')
process.exit(1)
}
import './index.js'
$ node8 entry.cjs
import './index.js'
^^^^^^
SyntaxError: Unexpected token import
If I switch to require('./index.js')
then it fails with modern runtimes because you cannot require()
an ES module.
$ node16 entry.cjs
entry.cjs:6
require('./index.js')
^
Error [ERR_REQUIRE_ESM]: require() of ES Module index.js from entry.cjs not supported.
Instead change the require of index.js in entry.cjs to a dynamic import() which is available in all CommonJS modules.
at Object.<anonymous> (entry.cjs:6:1) {
code: 'ERR_REQUIRE_ESM'
}
I thought an dynamic import expression would work because it would only be evaluated after parsing and after the version check, but that is a reserved keyword even in node 8
$ node8 entry.cjs
node entry.cjs
entry.cjs:6
import('./index.js')
^^^^^^
SyntaxError: Unexpected token import
CodePudding user response:
I believe this can be solved by creating a second .cjs file.
- file1.cjs does the version check, and if it didn't fail
require
file2.cjs - file2.cjs does the dynamic import.
CodePudding user response:
With NPM
You could define a package.json
file and have your start command check the node version first, and then run your script
Example from another SO Q&A:
// package.json
{
//...
"scripts": {
"start": "node check-version.js && node index.js"
},
//...
}
// check-version.js
const MIN_VERSION = 14;
const nodeVersion = process.version.replace(/^v/, '');
const [ nodeMajorVersion ] = nodeVersion.split('.');
if (nodeMajorVersion < MIN_VERSION) {
console.warn(`node version ${nodeVersion} is incompatible with this module.`, `Expected version >= ${MIN_VERSION}`);
process.exit(1);
}
Then npm start
would gracefully fail if the version is lower than required and run as expected if not. (You could define another name for the script, i.e.: npm run entry
)
Without NPM
If you do not wish to use npm/yarn, you could achieve the same result via .sh:
- Create
entry.sh
#!/bin/sh
node check-version.js && node index.js
chmod 755 entry.sh
./entry.sh