es6 in Node.js with Babel using import and IntelliSense - javascript

When using es6 import feature in Node.js there is a problem with modules written with commonjs module format. I use babel-register to run the code.
For example I want to use named exports from express module and I write:
import * as express from "express";
let app = express();
I also use TypeScript type definitions with typings and they work this way. But this code fails to run saying that express() is not a function.
When I write as if I use default export like:
import express from "express";
let app = express();
It works, but IntelliSense is not available.
What is the problem with this?

Related

When using the ES Module system in Node.js, can all Node packages be imported using the same import syntax?

This question is not whether Node.js supports the ES Module system.
That question has been answered previously, eg:
How can I use an ES6 import in Node.js?
Node.js - SyntaxError: Unexpected token import
And these answers are supported by the official Node.js docs:
ECMAScript modules are the official standard format to package JavaScript code for reuse...Node.js fully supports ECMAScript modules as they are currently specified and provides interoperability between them and its original module format, CommonJS. Node.js has two module systems: CommonJS modules and ECMAScript modules. Authors can tell Node.js to use the ECMAScript modules loader via the .mjs file extension, the package.json "type" field, or the --input-type flag.
Source
So it is clear that Node.js supports the ES Module system.
This question is:
When using the ES Module system in Node.js, can all Node packages be imported using the same import syntax?
The reason I ask is that a lot of packages' documentation does not specify how to import them using ES Module style, eg:
https://expressjs.com/en/starter/hello-world.html
https://github.com/expressjs/session
I want to avoid the situation where I am trying to figure out the correct syntax to use each time I want to import a library.
This answer seems to suggest this syntax:
import * as [ whatever_was_previously_used_as_the_variable_name ] from [ whatever_was_previously_between_the_quotes_in_the_parenthesis ]
So, using the examples above, this:
const express = require('express');
const app = express();
const session = require('express-session');
could safely be converted to:
import * as express from 'express';
const app = express();
import * as session from 'express-session';
Is that the 'universal' syntax that should be used to import all Node packages?
(Update: that session import above doesn't work, at app.use(session(sessionConfig)); it caused the error TypeError: session is not a function - I needed to define the import like this: import session from 'express-session'. I also had to import axios like this: import axios from 'axios', or i got a similar error. However, to use msal-node i had to use import * as msal from '#azure/msal-node').
Just to confuse things, I have come across other syntax examples, such as these in the Node docs (which includes node:):
import * as fs from 'node:fs/promises';
// OR:
import * as fs from 'node:fs';
Source
I am hoping a definitive answer can be provided that covers the different scenarios that may exist, eg: Node packages that live in the node_modules directory as well as one's own custom JavaScript modules that live outside of node_modules.
In this way, if I ever come across a package that does not specify installation instructions using the ES Modules style, I will still know the correct way to import it.
The import statement is indeed universal and can be used to import a module of either system, whether inside node_modules or out, or built-in to Node. When importing a CommonJS module this way, the value it would normally expose to require becomes its default export, so import name from 'url';, or any other form of import statement that retrieves the default export, will get you what you need.
The import * as name from 'url'; form you mentioned is for retrieving all of a module's named exports. This creates a module namespace object, never a function, though the function or other value that a CommonJS module exposes to require is available on the default property. There's generally no need to use import * with a CommonJS module, since everything that Node detects as a named export will be properties on the default export anyways.
You can also create a require from inside an ES module; this will work exactly the same way as require in CommonJS, but that includes the limitation of importing only CommonJS and built-in modules, not ES modules.

can't export routes in express with ES6

I was writing the backend for my project. I have noticed that it was getting really messy and was repeating a lot of code over and over again. I decided to re-write everything and use classes. I also took the decision to use ES6 modules for imports.
The first bump I have ran into is that I can't seem to get my routes working.
import express from 'express';
export const router = express.Router();
router.post('/test', async (req, res) => {
'test'
});
Importing it into server.js
import { router } from './routes/user.route'
server.use(router)
The error I get
Cannot find module
ES modules require literal specifiers (there is no magic resolution for extensionless names like in CJS).
In your original import statement, the specifier points to a module that doesn't exist (there is no file named user.route — its name is user.route.js):
import { router } from './routes/user.route'
Instead, you must provide the full path (including the extension):
import { router } from './routes/user.route.js'
See more at Mandatory file extensions - Modules: ECMAScript modules | Node.js Documentation

Use socket.io with ECMA Script modules (ESM)?

How do we use socket.io library with ecmascript module syntax?
I'm getting following error if I'm importing it like this:
import socketIO from "socket.io";
Error:
SyntaxError: The requested module 'socket.io' does not provide an export named 'default'
Try:
import {Socket} from ‘socket.io’
The socket.io package exports a server module as well so a default export won’t work here.
You can also do:
import * as SocketIO from ‘socket.io’
Then you will need to do socketIO.Socket

Why can't I "import * as readline from 'readline'" in Nodejs v10?

In the Nodejs docs, I see:
import EventEmitter from 'events';
import { readFile } from 'fs';
import fs, { readFileSync } from 'fs';
https://nodejs.org/api/esm.html
But with "readlines", I see:
const readline = require('readline');
https://nodejs.org/dist/latest-v10.x/docs/api/readline.html
But in StackOverflow, I see:
import * as readline from "readline";
TypeScript + NodeJS readline property missing
But I tried the above and other variations of import and can't make it work, so I have to use require. Could someone explain to me why this is the case, since readline is a default node module?
Thanks.
The use of import syntax is not yet available by default in Node.js LTS. You can either use a transpiler such Babel to be able to use it or use the --experimental-modules flag when running your Node.js script / server besides changing the extension of your files from .js to .mjs.

TypeScript to EcmaScript2015 supported by Node4 using gulp

I convert TypeScript to ES2015 (because I need async,await), then convert ES2015 to ES2015 supported by Node4 (Node4 not fully compatible with ES2015).
Problem is that TypeScript definition of express does not contain default field. But this field is actually exists in Javascript code. (actually express is just example, problem exists in many other libs bluebird for example)
So, If I import import {default as express} from "express";, then I have compilation TypeScript error. If I import as import * as express from "express";, then I have error when execute express(); like express is not a functionin runtime.
Simple project is here.
You need type in console:
npm install
typings install
gulp clean,build
gulp run
to see what I mean. (npm, typescript, gulp should be installed)
How to correct convert TypeScript to ES2015 supported by Node4
The express() function is conceptually the default of the express package. You'd always want to do
import express from "express";
// or this, which is identical, but longer.
import {default as express} from "express";
Using a syntax
import * as express from "express";
will import all of the exports of the module as an object. If you wanted to use that, you'd then have to do
express.default();
The problem with the first example, as you said, is that it can cause TypeScript to throw a type error. The easiest way to fix this is to tell TypeScript to be a little more flexible with it's expectations around what qualifies as a "default" export, when importing a CommonJS module. This is done by enabling the --allowSyntheticDefaultImports option on the TypeScript compiler.

Categories

Resources