Transpiling JavaScript with Babel on Begin

avatar
Paul Chin Jr
March 30, 2020

Photo of world map

Transpilers are tools that read source code in one syntax and output it into another syntax. For example, your source could be written in TypeScript, or utilize an experimental language feature, and a transpiler will make sure it turns into standard JS. Transpilers let developers work with a wider variety tools, while also keeping the output compliant with browsers and Node.js.

In this post we’ll demonstrate using Babel to implement a great new unreleased JS feature: optional chaining.

Try out Babel with Begin right now!

Hit this button to deploy a new Node.js + Babel example app to Begin in 15 seconds:

deploy-to-begin

Setting up a new project

You can follow along with the complete example, or start from scratch:

# make a new project folder
mkdir learn-node-babel
cd learn-node-babel
# install dependencies
npm init -y
npm install @architect/architect @babel/core @babel/cli @babel/plugin-proposal-optional-chaining @babel/preset-env

Note: Here are the docs for installing Babel. I had to install Xcode Command Line Tools according to this post to have node-gyp build properly on macOS.

Create a Lambda function in a folder called /lib

# create a new folder
mkdir -p lib/http/get-index
# create a file for the Lambda handler
touch /lib/http/get-index/index.js

Now we’re going to write our Lambda function.

// lib/http/get-index/index.js
export async function handler(req) {
  return {
    headers: {
      'content-type': 'text/html; charset=utf8'
    },
    body: `<pre>req?.queryStringParameters?.foo: ${req?.queryStringParameters?.foo}</pre>`
  }
}

This function is waiting for a GET request to your application index, then it will look for queryStringParameters with the property foo and return the value back to the browser in the response body.

Normally in JavaScript, accessing a deeply nested property that doesn’t exist would throw an error.

But by using a JavaScript language feature called optional chaining (currently at Stage 4 of a TC39 proposal), we can use this syntax right now by transpiling it to existing JavaScript standards in Node with Babel.

This means your code won’t error if foo isn’t found. And if so inclined, you can also write a default value, too: req.params?.foo || 'somedefaultvalue'

Looking up at four skyscrapers

Photo by Samson on Unsplash

Set up Babel

Now we can add a babel.config.js in our project root to configure Babel to convert the function to a CommonJS module. Babel will then run it through a preset that knows how to rewrite our source to make use of the optional chaining syntax.

// babel.config.js
module.exports = function(api) {
  api.cache(false)
  return {
    presets: [[
      "@babel/preset-env",
      { targets: { node: true }, modules: 'cjs' }
    ]],
    plugins: [[
      "@babel/plugin-proposal-optional-chaining"
    ]]
  }
}

Add start and build scripts to package.json

# package.json
"scripts": {
  "build": "npx babel ./lib -d ./src --copy-files --include dotfiles",
  "start": "npm run build & npx sandbox"
}

The build script will consider the entire /lib directory and run Babel output to /src with the same folder structure. The code inside of /src is what will be deployed to the cloud.

Now we can run npm start to both run Babel and start @architect/sandbox (a local development environment that emulates AWS API Gateway, Lambda, and an in-memory instance of DynamoDB).

Drawing of hands playing with string

Photo by Allie Smith on Unsplash

Checking the output

You should see this code inside /src that was generated by Babel:

// src/http/get-index/index.js
"use strict";
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.handler = handler;
async function handler(req) {
  return {
    headers: {
      'content-type': 'text/html; charset=utf8'
    },
    body: `<pre>req?.queryStringParameters?.foo: ${(req === null || req === void 0 ? void 0 : req.queryStringParameters.foo) || 11} </pre>`
  };
}

Our original code looks a bit better, don’t you think?

That’s it!

Congrats! Now go flex your new JavaScript powers and test out more experimental JavaScript features!

Next Steps

deploy-to-begin