Intro
So, I'm making a Node - Express - Mongo server boilerplate to get the hang of it and I found out that Node now has support for es6 modules by default! :)
This post will go through the process of creating one such project with es6 support, eslint configuration and some hacks :P
Note:
This tutorial involves setting the
--es-module-specifier-resolution=node\"
flag in the command line of node, which is an experimental flag. This is the 'hack' mentioned above. This is done in order to omit the '.js' file extension while importing modules. However, if you are uncomfortable with experimental tags, you could either use '.js' extensions everywhere in the code or use Babel.
ES6 ?
Having support for es6 modules means that you could do the following:
import Stuff, {some, other, stuff} from 'some/library';
export thing;
export default anotherThing;
This breaks the monotony of require()
and IMO, this is a much cleaner syntax. Earlier, if you wanted to do this, you had to
- use TS (which although can be a good thing, adds an extra 'build' step before execution and while this pattern might suffice for frontend development, it's a completely show-killer for me.)
- use the Babel library that 'transpiles' your es6 code to it's equivalent commonJS code.
Note that although these statements are supported, currently they map to their
require()
andmodule.exports
equivalents in node, so doing essentially the same thing as Babel, but with no extra dependencies.
Also, usingimport
andexport
is the correct way forward, because at some point of time in future, node is going to adopt this way of using modules and not completely relying onrequire()
.
Also, did I mention that usingimport
andexports
is faster thanrequire()
? :)
Let's start the code now.
Project Setup
Note
This tutorial will guide you in making a simple, barebones node app with es6 support. I will not be including any other stuff like express, extra dependencies etc. for the sake of simplicity.
Do a npm init
to get the basic package.json:
{
"name": "es6-api",
"version": "1.0.0",
"description": "es6-api",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"es6",
"api"
],
"author": "",
"license": "ISC"
}
Now, we need to add a few things to package.json
:
- To add support for ES6 modules, add the line
"type": "module"
to yourpackage.json
. - Add a
"dev"
script in the"scripts"
property like:"dev":"node --es-module-specifier-resolution=node src/index.js"
- Change
"main": "index.js",
to"main": "src/index.js",
make a folder src and touch a fileindex.js
in it.
Your package.json
should look like this now:
Run npm install eslint && npx eslint --init
in the root dir (where package.json is stored) to setup eslint.
Answer all the questions according to your choice. Make sure to set the option 'What type of modules does your project use?' to 'esm'. These were my choices, but yours might differ:
It will write the config to .eslintrc.json
in the root dir and install a local copy of eslint in the node_modules
directory.
Open .eslintrc.json
and you should see the config similar to this:
Now here, we need to make some changes to make eslint work with our esm setup.
First, add the line "es6": true
to the "env"
porperty value. Then, make a new property called "globals"
and add the following line in it's value: "__dirname": true
. This we'll come to this later in the code.
The config should look like this now:
Now that eslint is setup, we can go ahead and edit the src/index.js
file. Add the following code to it:
// src/index.js
import path from 'path';
global.__dirname = path.resolve('./');
console.log(__dirname);
This code will do 2 things:
- Verify that we can in fact, use
import
statement. - In node with esm, variables like
__dirname
which are normally availabe in the global scope, are undefined. These 2 statements make it available in the global scope again. Notice that we also added the line"__dirname": true
in.eslintrc.json
. Without that, eslint will give an error saying that __dirname is not defined.
Now that our starter code is ready, return to the root dir and run npm run dev
. You should get the following output:
Exporting stuff
Let's look into making our own modules and exporting stuff.
Start by making a directory example
in the src
directory. Touch a file index.js inside it and add the following code:
const value1 = 99;
const value2 = 100;
export { value2 };
export default value1;
We're making a module here and exporting value1
as a default export and value2
as a named export. We will also import these values in the main index.js.
Replace the code of src/index.js
by:
import path from 'path';
import value1, { value2 } from './example';
global.__dirname = path.resolve('./');
console.log(value1, value2);
By now, your project should like this:
Run npm run dev
and you should see
> es6-api@1.0.0 dev /home/tushar/src/tmp/tut/es6-api
> node --es-module-specifier-resolution=node src/index.js
99 100
That confirms that our es6 module was loaded successfully in node without using babel!.
Footnotes
You can go wild with esm by using await import(...)
, module-aliases, importing commonJS modules and much more, but I think that would be out of the scope of this article.
Also note that since import
as of now is identical to require()
, you can basically load data from a JSON file by writing await import('file.json')
.
If you liked this tutorial or have some suggestions, please drop a comment below. Thank you for reading. Bye and have a nice day.
Top comments (2)
Nice article, thank you for the post.
You could add an update to the post. Now in 2021 we do not need es6 and globals lines in the .eslintrc.json.
eslint.org/docs/user-guide/configu... - es2021 - adds all ECMAScript 2021 globals and automatically sets the ecmaVersion parser option to 12.
Thanks, that is very useful. I am missing the package.json entry to run eslint, and also I would call the script "start" and not "dev".
PS: for beginners it would recommend using XO github.com/xojs/xo instead of using eslint directly.