Description
Node 8.5 added support for ES modules behind the --experimental-modules
flag. Node 10, expected to be released in April 2018, will supposedly drop the flag. Here’s a great overview.
Adding ES modules was mostly Node finally supporting the import
and export
syntax from ES2015, that CoffeeScript already supports. There is at least one caveat, though: Node only supports importing files with an .mjs
extension, from files with an .mjs
extension.
This raises the issue of how to use the CoffeeScript compiler to generate output JavaScript files with .mjs
extensions. If you’re using the coffee
command to compile a single file, you can specify the output filename, including extension, explicitly:
coffee --compile --output module.mjs module.coffee
But for folders, the compiler automatically outputs all .coffee
files as .js
files. It doesn’t take much effort to add a post-compilation step that renames these extensions, but should this perhaps be something the compiler handles?
One way to do it would be to introduce a new .mcoffee
file extension, that the compiler would output as .mjs
. Straightforward, though the greater ecosystem around CoffeeScript would need to be updated. (Syntax highlighters, etc.)
Another way to do it would be with a new CLI flag, e.g. --output-extension mjs
. This might be useful in its own right, to allow outputting JSX files with a .jsx
extension (if for some reason you wanted to simply save them, rather than immediately transpiling them into JavaScript). But @jashkenas and others (including me) feel strongly against adding yet more flags to the CLI, except as a last resort.
Are there any other ways to handle this situation? Unfortunately we can’t simply output all files with import
or export
statements as .mjs
, because a lot of people will want the current behavior for quite a while, as Babel’s treatment of those statements is different than Node’s and many people won’t want to refactor their code anytime soon. (A great lesson in why not to start using features before they’re both standardized and implemented!)
The other thing on my mind regarding this is that I want to rewrite the modules tests to use actual import
and export
statements that Node evaluates, rather than comparing strings; but I think the only way to do this would be to spawn a new Node process with an .mjs
file as its entrypoint. (This is regardless of whether the --experimental-modules
flag is still around.) This would add considerable complexity to the test runner, but I think would be worth it.