How should I compile ES modules and run them without package.json and tsconfig.json? - node.js

I created a minimalistic example of using ES modules in Typescript, using only the tsc and node commands. It works fine but I'm not sure I did it correctly.
I created two files like the following.
// test.mts
export function test(s: string) {
console.log('test, s:' + s);
}
// main.mts
import {test} from './test.mjs'
test('a')
console.log('done')
And I compiled and ran like the following.
$ tsc --module es6 test.mts main.mts && node main.mjs
It seems I have to use the 'mts' extension instead of the 'ts' for source files, and have to import the 'test.mts' module with the 'mjs' extension. Am I correct? Is there any better method?
I am not a seasoned JS developer and the official documentation does not help in my case.

Related

How to use hardhat with ES module?

I wanted to add hardhat to a project that uses ES modules. Hardhat complains that I can't use require in the hardhat.config.js file, so I renamed it to import, but it still won't compile with the following error:
require() of ES modules is not supported.
There isn't a place where require is being called (I have replaced it with import), but it says otherwise. Any solution?
I have "type": "module", in my package.json
I am using the "hardhat": "^2.12.0-esm.1" package. It's a new package that was specially written to support ESM.
In my test, if I need some HH function, I do something like:
import pkg from 'hardhat'
const { ethers } = pkg
My hardhat.config.js is renamed to hardhat.config.cjs but the inside is unchanged and has lots of requires in it, and they work, even though my package.json has type: "module".
In my scripts, I have lines like:
async function main() {
const [deployer] = await ethers.getSigners()
but I don't have any import nor require at the beginning. I guess calling hardhat run script/my_script.js does the import magic.

Dynamic import - import() - fails when the code is packaged into an executable

I am working in a commonjs environment trying to dynamically import an es module
Consider the below code :
const mysqlController = (async function () {
try{
var {default:dateformat}= await import('dateformat');
// also tried await import('../../../node_modules/dateformat/lib/dateformat.mjs')
}
catch(e){
console.error('Line 31 of db_controller');
console.error(e);
}
// More stuff
})()
The statement await import('dateformat'); works fine when debugging. But when using pkg to produce a standalone executable, it gives the following error:
TypeError: Invalid host defined options
Could somebody tell me what is going on here?
Okay, for some reason node executables made with package pkg doesn't honor import() statements.
As a temporary workaround, I made cjs alternatives for the es modules which I was trying to import using rollup.
Then, I copied the bundle locally and required those.
Vercel/pkg does not (yet) support import of ES6 modules.
The reason seems to be that pkg must traverse all require()-calls in your program to know what exactly needs to be packaged together into the exe it creates. It does not know it should do a similar thing with all and any import-statements in your program as well.
SEE: https://github.com/vercel/pkg/pull/1323

Using es6 modules in coffeescript

es6 modules are supposed to work in coffeescript (see https://coffeescript.org/#modules), but even with an extremely simple project, it doesn't work for me. I:
Created a new directory
Ran 'npm init -y' in it
Added the key "type": "module" in my package.json
Created 2 files: index.coffee and utils.coffee
import {myprint} from 'utils.coffee'
myprint("Hello, World!")
export myprint = (str) ->
   console.log(str)
when I try to execute index.coffee (via 'coffee index.coffee' - I've tried both git's bash shell - on Windows and PowerShell), I get the following error message:
(node:1856) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
and later:
SyntaxError: Cannot use import statement outside a module
This is all correct as far as I understand. Coffeescript transpiles the import/export statements correctly, but does not provide an environment to run them.
From the documentation:
Note that the CoffeeScript compiler does not resolve modules; writing an import or export statement in CoffeeScript will produce an import or export statement in the resulting output. It is your responsibility to transpile this ES2015 syntax into code that will work in your target runtimes.
You won't be able to run this code via either coffee or node --require coffeescript/register. I believe you will have to transpile your code and run the resulting JS via node

SyntaxError: The requested module 'graphql-relay' does not provide an export named 'fromGlobalId' [duplicate]

I've installed Node 8.9.1 (same problem happens in v10.5.0).
I'm trying to use named imports from npm packages in a file with the .mjs
import { throttle } from lodash;
I run:
node --experimental-modules index.mjs
and I get:
SyntaxError: The requested module 'lodash' does not provide an export named 'throttle'
at ModuleJob._instantiate (internal/modules/esm/module_job.js:80:21)
--experimental-modules are supposed to stop being experimental in v10 LTS, so why haven't more module authors jumped on the bandwagon?
EDITED NEW (AND MUCH BETTER) ANSWER
The Node team is ... slow. Meanwhile, the same guy who brought us Lodash (John-David Dalton) imagined a brilliant solution, and his idea is the best way to get full ES6 module support in 2019.
(In fact, I want to delete my earlier answer, but I've left it for historical purposes.)
The new solution is SUPER simple.
Step #1:
npm i esm
(https://www.npmjs.com/package/esm for package details)
Step #2:
node -r esm yourApp.js
That's the entirety of it: it's really just that easy. Just add -r esm as a Node arg, and everything just magically works (it's even less typing than --experimental-modules!) Thank you John-David Dalton!!!
As I said in my original answer, presumably someday Node will finally release full ES6 support, but when that happens adopting it will be as easy as removing "-r esm" from a few scripts :D
Finally, to give credit where due, while I didn't find it through his answer, #Divyanshu Rawat actually provided an answer with the precursor to this library long before I made this update.
ORIGINAL ANSWER
--experimental-modules does not have support for named exports yet:
--experimental-modules doesn't support importing named exports from a commonjs module (except node's own built-ins).
https://github.com/apollographql/graphql-tools/issues/913
This is why you are unable to use the syntax:
import { throttle } from 'lodash';
Instead (for now at least) you have to destruct what you need:
import lodash from 'lodash';
const { throttle } = lodash;
Presumably someday Node will add support for all of the ES Module features.
I just had this error with nodejs express *.mjs file and --experimental-modules flag enabled for googleapis.
import { google } from "googleapis";
SyntaxError: The requested module 'googleapis' does not provide an export named 'google'
Solution
//not working!
//import { google } from "googleapis";
//working
import googleapis from "googleapis";
const { google } = googleapis;
I do not understand why this is the case; if anyone knows why, please comment.
You have to use .mjs extension.
Once this has been set, files ending with .mjs will be able to be loaded as ES Modules.
reference: https://nodejs.org/api/esm.html
Update:
Looks like you haven't export the method yet.
Suppose i have hello.mjs with content
export function sayHello() {
console.log('hello')
}
i can use it in index.mjs like this
import {sayHello} from './hello.mjs'
sayHello()
For me loading lodash as ES Library did the job, here is the NPM Package for the same.
The Lodash library exported as ES modules.
https://www.npmjs.com/package/lodash-es
Then you can import utils in normal way.
import { shuffle } from 'lodash-es';
If lodash had been written as modules, and lodash/index.mjs exported throttle: export const throttle = ...;, then you'd be able to import { throttle } from lodash;
The problem here is that in commonjs there's no such thing as a named export. Which means that in commonjs modules export one thing only.
So think that lodash exports an object containing a property named throttle.
For the second part of the question, I believe people will slowly start adopting ES Modules once it's not experimental anymore. At the time of this writing, it still is (Node.js v11.14).
#machineghost answer works. I remember also adding 'type':'module' to package.json along with using esm with node v12(LTS) and it worked fine.## Heading ##
I updated my node to v14(current) and I got an error
C:\Users\andey\Documents\Project\src\app.js:1
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module:
C:\Users\andey\Documents\Project\src\app.js
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1217:13) {
code: 'ERR_REQUIRE_ESM'
}
To fix it I had to remove 'type':'module' from package.json.
source

node --experimental-modules, requested module does not provide an export named

I've installed Node 8.9.1 (same problem happens in v10.5.0).
I'm trying to use named imports from npm packages in a file with the .mjs
import { throttle } from lodash;
I run:
node --experimental-modules index.mjs
and I get:
SyntaxError: The requested module 'lodash' does not provide an export named 'throttle'
at ModuleJob._instantiate (internal/modules/esm/module_job.js:80:21)
--experimental-modules are supposed to stop being experimental in v10 LTS, so why haven't more module authors jumped on the bandwagon?
EDITED NEW (AND MUCH BETTER) ANSWER
The Node team is ... slow. Meanwhile, the same guy who brought us Lodash (John-David Dalton) imagined a brilliant solution, and his idea is the best way to get full ES6 module support in 2019.
(In fact, I want to delete my earlier answer, but I've left it for historical purposes.)
The new solution is SUPER simple.
Step #1:
npm i esm
(https://www.npmjs.com/package/esm for package details)
Step #2:
node -r esm yourApp.js
That's the entirety of it: it's really just that easy. Just add -r esm as a Node arg, and everything just magically works (it's even less typing than --experimental-modules!) Thank you John-David Dalton!!!
As I said in my original answer, presumably someday Node will finally release full ES6 support, but when that happens adopting it will be as easy as removing "-r esm" from a few scripts :D
Finally, to give credit where due, while I didn't find it through his answer, #Divyanshu Rawat actually provided an answer with the precursor to this library long before I made this update.
ORIGINAL ANSWER
--experimental-modules does not have support for named exports yet:
--experimental-modules doesn't support importing named exports from a commonjs module (except node's own built-ins).
https://github.com/apollographql/graphql-tools/issues/913
This is why you are unable to use the syntax:
import { throttle } from 'lodash';
Instead (for now at least) you have to destruct what you need:
import lodash from 'lodash';
const { throttle } = lodash;
Presumably someday Node will add support for all of the ES Module features.
I just had this error with nodejs express *.mjs file and --experimental-modules flag enabled for googleapis.
import { google } from "googleapis";
SyntaxError: The requested module 'googleapis' does not provide an export named 'google'
Solution
//not working!
//import { google } from "googleapis";
//working
import googleapis from "googleapis";
const { google } = googleapis;
I do not understand why this is the case; if anyone knows why, please comment.
You have to use .mjs extension.
Once this has been set, files ending with .mjs will be able to be loaded as ES Modules.
reference: https://nodejs.org/api/esm.html
Update:
Looks like you haven't export the method yet.
Suppose i have hello.mjs with content
export function sayHello() {
console.log('hello')
}
i can use it in index.mjs like this
import {sayHello} from './hello.mjs'
sayHello()
For me loading lodash as ES Library did the job, here is the NPM Package for the same.
The Lodash library exported as ES modules.
https://www.npmjs.com/package/lodash-es
Then you can import utils in normal way.
import { shuffle } from 'lodash-es';
If lodash had been written as modules, and lodash/index.mjs exported throttle: export const throttle = ...;, then you'd be able to import { throttle } from lodash;
The problem here is that in commonjs there's no such thing as a named export. Which means that in commonjs modules export one thing only.
So think that lodash exports an object containing a property named throttle.
For the second part of the question, I believe people will slowly start adopting ES Modules once it's not experimental anymore. At the time of this writing, it still is (Node.js v11.14).
#machineghost answer works. I remember also adding 'type':'module' to package.json along with using esm with node v12(LTS) and it worked fine.## Heading ##
I updated my node to v14(current) and I got an error
C:\Users\andey\Documents\Project\src\app.js:1
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module:
C:\Users\andey\Documents\Project\src\app.js
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1217:13) {
code: 'ERR_REQUIRE_ESM'
}
To fix it I had to remove 'type':'module' from package.json.
source

Resources