DEV Community

Cover image for How to transpile with light speed 💫
Dirk Holtwick
Dirk Holtwick

Posted on

How to transpile with light speed 💫

For every developer there comes the moment where speed matters. It saves you a relevant amount of time and keeps the flow going.

esbuild is definitely fast and reduces the built time significantly. And it is nice and simple too, when it comes to set up.

Build

It can be started from command line or nicely being integrated in a node.js script like this:

const esbuild = require('esbuild')

const options = {
  target: 'node12',
  platform: 'node',
  jsxFactory: 'h',
  jsxFragment: 'hh',
  bundle: true,
  outfile: 'out.js',
  sourcemap: 'inline',
  loader: {
    '.js': 'jsx',
    '.css': 'text',
  },
  entryPoints: [sitePath + '/index.js'],
}

await service.build(options)

This will build a single JS file containing everything that is needed to run. It also translates JSX and uses the function h to create elements. It also loads files ending on .css as plain text. A source map will be written as well. All this is done in a fragment of a second! This is because esbuild is written in Go instead of Javascript, because speed matters sometimes.

Sitemaps

Speaking of source maps the same author of esbuild also wrote a module to support them on node: node-source-map-support.

Testing

Now the setup is almost complete, but how about testing? I usually use jest for testing and therefore I wanted to get it working here as well. The solutions available did not fit my case, therefore I wrote my own transform:

First make sure to tell Jest what to do in a package.json section:

"jest": {
  "transform": {
    "^.+\\.jsx?$": "./src/jest-transform.js"
  },
  "testEnvironment": "node",
  "testPathIgnorePatterns": [
    "node_modules/",
    "dist/"
  ]
}

The transformer looks like this:

// Inspired by https://github.com/aelbore/esbuild-jest#readme

const fs = require('fs')
const pkg = require('../package.json')
const esbuild = require('esbuild')

const external = [
  ...Object.keys(pkg.dependencies ?? {}),
  ...Object.keys(pkg.devDependencies ?? {}),
  ...Object.keys(pkg.peerDependencies ?? {}),
]

module.exports = {

  getCacheKey() { // Forces to ignore Jest cache
    return Math.random().toString()
  },

  process(content, filename) {
    esbuild.buildSync({
      target: 'node14',
      platform: 'node',
      jsxFactory: 'h',
      jsxFragment: 'h',
      bundle: true,
      outfile: 'out-jest.js',
      sourcemap: 'inline',
      loader: {
        '.js': 'jsx',
        '.css': 'text',
      },
      entryPoints: [filename],
      external,
    })
    let js = fs.readFileSync(file, 'utf-8')
    fs.unlinkSync(file)
    return js
  },
}

Competition

Why would you want to you use esbuild and not webpack, babel, rollup, etc.? Well, because it is fast and easy to use. The other solutions are blown up and become pretty complex after a while. They have many 3rd party dependencies, which can cause troubles as well.

If you want to experience the blatant acceleration, then try esbuild.


Photo by Traf on Unsplash

Top comments (3)

Collapse
 
daveirvine profile image
Dave Irvine

Hi,

Can you check your code sample? I get an undefined variable for file on these lines:

let js = fs.readFileSync(file, 'utf-8')
    fs.unlinkSync(file)
Enter fullscreen mode Exit fullscreen mode

and if I change this to filename which was the closest variable I could find, it deletes my test files :D

Collapse
 
starpebble profile image
starpebble

Thanks for sharing this tip. My first reaction: looks useful to deploy javascript to the edge of the network. Example: a lambda at edge function. Memory and CPU are tighter, less code is better, and a nifty builder can only help. Is this interpretation right? 🙂

Collapse
 
holtwick profile image
Dirk Holtwick

Sure that could be a use case. But to be clear, the speed I'm referring to is the transpilation time and not the execution time of the resulting code. I did not look at memory consumption though.