A bit of a mouthful of a post title, but I can assure my future self this post will be worthy of publishing because it’ll save future self many angry hours shouting at build tools.

The goal: no build tools, which leads to no config, which leads to no waiting around.

[I’ve published 38 videos for new developers, designers, UX, UI, product owners and anyone who needs to conquer the command line today.](https://training.leftlogic.com/buy/terminal/cli2?coupon=BLOG\&utm_source=blog\&utm_medium=banner\&utm_campaign=remysharp-discount)

Let’s get the lie out of the way[](#lets-get-the-lie-out-of-the-way)

There’s a little config required, but I can assure you, future Remy, it’s a copy and paste job.

Whilst I’m admitting things, it’s worth noting that I think this strategy won’t work for distributed node modules. That’s to say: this process is for application development and testing.

TL;DR[](#tldr)

Install a few bits:

$ npm i esm
$ npm i -D ava nyc

And update your package.json with my [solution](#final-solution) to use import statements without any build hassles.

1. esm[](#1-esm)

It’s been around for a while, but when I tried it originally I didn’t have much success. Lately the [esm module](https://github.com/standard-things/esm) worked right out of the box for me. If you’re not familiar:

The brilliantly simple, babel-less, bundle-less ECMAScript module loader.

This code is going to allow me to name my files as I please - that’s usually someProcess.js (not .mjs, or .cjs, .watjs). Within any of these files I can also use import like I’m a space boy from the future. Using import will work on my own files and any other package I install.

import fs from 'fs'; // node internals
import nodemon from 'nodemon'; // an "ES5-style" package made compatible
import { method } from './my-methods'; // my local code

export const number = 12;
export default () => {
  // do something magical
}

To use esm I can either include it in my code…hmm, no, yuk, or I can get node to load the esm module up front so my code never sees the library. In my package.json file I’ll have:

{
  "scripts": {
    "start": "node -r esm .",
    "dev": "DEBUG=* node -r esm ."
  },
  "main": "src/index.js"
}

That’s it. Next though, is testing, and that wasn’t so simple (at first!).

2. Testing[](#2-testing)

I’ve been a fan of [tap](https://remysharp.com/2016/02/08/testing-tape-vs-tap) for a while, I used mocha (a very old version) for nodemon (for my sins), and lately I’ve enjoyed using Jest for testing.

However Jest doesn’t support requiring an additional module during runtime the way node does. Mocha and other testing frameworks do, but not Jest. It’s a bit annoying, but it made me look around again.

I settled on [AVA](https://github.com/avajs/ava). I’m still not quite a fan, but it’s doing it’s job as a test runner. Importantly, AVA lets me include esm as part of the testing and I can define this in my package.json (again), so all this stuff lives together so far:

{
  "ava": { "require": [ "esm" ] },
  "scripts": {
    "test": "ava",
    "start": "node -r esm .",
    "dev": "DEBUG=* node -r esm ."
  },
  "main": "src/index.js"
}

Again, that’s it. My tests now work and my code remains to use import statements. No build process (or that I’m aware of, which is the way I like it).

The last part of the jigsaw puzzle is coverage. I use coverage as an indicator that I’ve not missed some important code fork (rather than aiming for 100% coverage). AVA makes it easy to use [nyc](https://istanbul.js.org/) ("the Istanbul command line interface"…whatever that means…). Except…coverage doesn’t quite work.

3. Coverage[](#3-coverage)

I found that if the codebase used require statements but my tests used import then the coverage would report. If it was 100% import statements, I’d be faced with wonderful bit of nonsense:

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |        0 |        0 |        0 |        0 |                   |
----------|----------|----------|----------|----------|-------------------|

I tried debugging it manually but it was completely useless. Thank the stars when I came across [this repo](https://github.com/andrezero/boilerplate-esm-nyc-mocha) by [Andre Torgal](https://andretorgal.com/) which gave me most of the bits I needed for nyc to pick up the imported files.

First the following is needed for esm to operate fully "esm": { "cjs": true } (I’m not completely sure why, but trust that I went through a lot of permutations!). Next nyc also needs to know to load in the esm module, so the final package.json reads as:

{
  "esm": { "cjs": true },
  "nyc": { "require": [ "esm" ] },
  "ava": { "require": [ "esm" ] },
  "scripts": {
    "start": "node -r esm .",
    "dev": "DEBUG=* node -r esm .",
    "test": "nyc --reporter=text ava"
  },
  "main": "src/index.js"
}

It’s a bit repetitive, but it works and it works without any build tool shenanigans, which is all I really want in life.

👍 23 likes

[![Marcio Gasparotto](/images/no-user.svg "Marcio Gasparotto")](![David Glassford(/images/no-user.svg "David Glassford")](![dominik.dev 🐼 #JSConfUS(/images/no-user.svg "dominik.dev 🐼 #JSConfUS")](![Fabian Cook(/images/no-user.svg "Fabian Cook")](![Benny Schudel(/images/no-user.svg "Benny Schudel")](![Yurick Hauschild(/images/no-user.svg "Yurick Hauschild")](![Pascal(/images/no-user.svg "Pascal")](![Ryan MacLean 🍩(/images/no-user.svg "Ryan MacLean 🍩")](![0gust1(/images/no-user.svg "0gust1")](![Evan 🇺🇸 Plaice(/images/no-user.svg "Evan 🇺🇸 Plaice")](![Anders Tornblad(/images/no-user.svg "Anders Tornblad")](![Paul Stefan Ort(/images/no-user.svg "Paul Stefan Ort")](![Andrew Chou(/images/no-user.svg "Andrew Chou")](![Thomas Beduneau(/images/no-user.svg "Thomas Beduneau")](![Chris Pilsworth(/images/no-user.svg "Chris Pilsworth")](![Florens Verschelde(/images/no-user.svg "Florens Verschelde")](![Sibelius Seraphini(/images/no-user.svg "Sibelius Seraphini")](![Anthony Young(/images/no-user.svg "Anthony Young")](![Jaap van Hardeveld(/images/no-user.svg "Jaap van Hardeveld")](![Raymond Julin(/images/no-user.svg "Raymond Julin")](![Ant Stanley 🤦🏻‍♂️(/images/no-user.svg "Ant Stanley 🤦🏻‍♂️")](![Tierney Cyren(/images/no-user.svg "Tierney Cyren")](![Pavel Hůza(/images/no-user.svg "Pavel Hůza")](https://twitter.com/huzic)

Comments

Lock Thread

Login

Add Comment[M ↓   Markdown]()

[Upvotes]()[Newest]()[Oldest]()

Alessandro Stamatto

0 points

4 years ago

Great ES6+ setup! I saved for later because I also dislike complex heavy builder-reliant environments.

Loved the simplicity of your approach.

[Commento](https://commento.io)