Getting On with ES6 & NodeJS & eslint (without Babel !)
Tags: es6, node, tutorial, javascript
Published: 2020-08-24 17:58:00

## 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
1. 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.)  
2. 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()` and `module.exports` equivalents in node, so doing essentially the same thing as Babel, but with no extra dependencies. 
Also, using `import` and `export` 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 on `require()`.  
Also, did I mention that using `import` and `exports` is faster than `require()` ?  :)

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 your `package.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 file `index.js` in it.  

Your `package.json` should look like this now:  
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/a7giig6pvcwrbtwe3vqh.png)


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:  

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/cjbiy7i8m5y55cqlrkr4.png)  

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:  
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/192m1gih4fx1b4y7lbmp.png)  

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:  
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1ehre2k2pzi6w8jsayj9.png)  

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:  
1. Verify that we can in fact, use `import` statement.
2. 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:  
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/y4tfrgq8r9en2qjbtyrc.png)  

## 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:  

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ohg9o1nhdwixcs9v3q6o.png)  

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.