vincentdnl

First steps with Rome: a dependency-free Javascript toolchain by Facebook

March 2nd, 2020

A few days ago, I saw from multiple sources (including ycombinator and Reddit) that a team from Facebook was working on a experimental Javascript toolchain called Rome.

It seems to include a compiler, a linter, a formatter a bundler and a testing framework despite not being based on any of the "usual" tools that are standard in the industry (Babel, Webpack, etc.).

The project was started by Sebastian McKenzie, the author of Babel and Yarn.

This article is from the perspective of a developer discovering a new tool. I'm not from the dev team! I wrote this Rome tutorial while learning the tool!

Installation

At the moment, Rome isn't a package yet:

The only way to use it is to build from source.

So let's get started with it:

git clone https://github.com/facebookexperimental/rome.git
cd rome

Let's see what options are available on the CLI tool for the moment (assuming you have NodeJS already installed):

node scripts/vendor/rome.cjs --help

There are a bunch of Options that I won't talk about here. The other categories are Code Quality Commands (ci, lint and test), Internal Commands (I don't know what they are yet), Process Management Commands to control the daemon, Project Management Commands (some of them like publish and run are not implemented yet) and Source Code Commands (like bundle, compile, etc.)

I'll just create an alias as rome for this command to play with it anywhere else. I don't know if this is the right method as there is no installation documentation yet.

alias rome='node <path_to_your_folder>/rome/scripts/vendor/rome.cjs'

Project files

Rome is written mostly in Typescript which is surprising, considering that Facebook is putting a lot of effort into ReasonML.

Looking at packages.json:

{
  "name": "rome-root",
  "license": "MIT",
  "version": "0.0.2",
  "//": "Look! No deps!",
  "dependencies": {},
  "///": "Only used for static type checking",
  //...
}

The project clearly wants to be dependency-free.

Hello World bundle with Rome

Let's initialize a project:

mkdir hello-world
cd hello-world
rome init

It asks me if I want the recommended settings, let's agree.

Note: You can also use the shortcut rome init --defaults

It created a file called rome.json that will probably act like config files from other tools like .prettierrc, .babelrc, etc.

{
  "version": "^0.0.52",
  "lint": {
    "enabled": true
  }
}

Let's add a simple index.js file containing some javascript using modern features:

const who = () => "Rome"

console.log(`Hello ${who()}!`)

Note: it also works with typescript out of the box!

And enter the command:

rome parse index.js

Output:

Program {
  comments: Array []
  diagnostics: Array []
  directives: Array []
  filename: 'project-hello-world/index.js'
  hasHoistedVars: false
  mtime: 1_583_158_150_325.729
  sourceType: 'script'
  syntax: Array [
    'jsx'
    'flow'
  ]
  body: Array [
    VariableDeclarationStatement {
      declaration: VariableDeclaration {
        kind: 'const'
        declarations: Array [
          VariableDeclarator {
            id: BindingIdentifier {name: 'who'}
            init: ArrowFunctionExpression {
              body: StringLiteral {value: 'Rome'}
              head: FunctionHead {
                async: false
                hasHoistedVars: false
                params: Array []
              }
            }
          }
        ]
      }
    }
    ExpressionStatement {
      expression: CallExpression {
        callee: MemberExpression {
          object: ReferenceIdentifier {name: 'console'}
          property: StaticMemberProperty {value: Identifier {name: 'log'}}
        }
        arguments: Array [
          TemplateLiteral {
            expressions: Array [
              CallExpression {
                arguments: Array []
                callee: ReferenceIdentifier {name: 'who'}
              }
            ]
            quasis: Array [
              TemplateElement {
                cooked: 'Hello '
                raw: 'Hello '
                tail: false
              }
              TemplateElement {
                cooked: '!'
                raw: '!'
                tail: true
              }
            ]
          }
        ]
      }
    }
  ]
}

Cool! Let's try to create a bundle the bundle command:

rome bundle index.js bundle

It creates a bundle/ folder containing index.js, index.js.map and a bundlebuddy.json that probably contains some kind of bundling info:

[
  {
    "source": "project-hello-world/index.js"
  }
]

Now let's execute the freshly created bundle/index.js:

node bundle/index.js

Returns:

Hello Rome!

Kind of what we expected, right?

Conclusion

I hope this article helped you do your first steps with Rome. Rome is still experimental and in development and it aims to replace a lot of existing tools! Maybe it wants to solve too many problems at the same time and it's not a good idea to break the single responsibility principle? We will see in the future how it succeeds in the Javascript ecosystem and how it finds its place.