Rome is a JavaScript toolchain created with the promise of unifying the frontend development. We all know how difficult and tricky it can be to manage many different tools for stuff like bundling, minifying, beautifying, compiling, etc.
From the same mind behind Babel and Yarn, and following the same centralizing idea that other languages like Rust have spread, Rome was born aiming to become the all-in-one tool.
You can find the updated list of supported languages here. By the time of this writing, Rome offers support for JavaScript, TypeScript, JSON, HTML, Markdown, and CSS.
In this article, we’re going to dive a bit deeper into this toolchain and see, with some nice examples, how it performs against the most common tasks every frontend developer must address.
Its installation is pretty simple. You can install it from NPM or Yarn. For this article, we’re picking Yarn as default:
yarn add rome yarn rome init
However, if you want to go with NPM, simply run the following:
npx rome init
This will create a new Rome project and initialize it with some files (we’ll see them in detail in a minute).
This is the output generated by the previous command execution:
For the next few tests, make sure to have a index.js file created and the following content in it:
var first=["Log","Rocket"],second=["Log","Rocket","Plus"],both=first.concat(second);document.getElementById("demo").innerHTML=both;
Indenting your code is simply necessary. Tons of plugins and most IDEs provide this functionality ad-hoc. And so does Rome.
Via the command line, you can format a given file by hitting the following command:
yarn rome format index.js
Since we created the project via Yarn, the yarn
command must be added at the beginning of every Rome command.
That’s a simple minified code snippet in JavaScript. Minified files are great ways to test a format command since we expect the code to be “unminified”. After the command ends, you may see the following output:
var first = ["Log", "Rocket"], second = ["Log", "Rocket", "Plus"], both = first.concat(second); document.getElementById("demo").innerHTML = both;
Perhaps one of the most interesting and used features of Rome is its linting. Through a very intuitive and clear syntax, it shows the list of errors for your JavaScript files by simply running the rome lint
command.
Rome also keeps a list of the current supported Lint rules. If a validation rule isn’t working for you, make sure to refer to this list to check if the rule is there.
Let’s test it out! Take the following code as an example:
function abc() { console.log("what's going"); }
Here, we have two visible issues, the code indenting, and a non-used function. Let’s see how Rome analyzes this code snippet by running the command:
yarn rome lint
The following is the output:
Each problem is listed as bulleted points, being each point preceded by a red x sign. In our code, the two problems we’ve mentioned were found.
In green, you’ll find the suggested fixes, like the appropriate code formatting for our console.log()
.
To fix this, Rome gives us some great options. The first one we’ll dive into is the check apply
.
This option is great because it allows Rome to auto fix all the problems that Rome knows well and is confident in fixing for us.
So, run the following command:
yarn rome check --apply
Rome will execute a bunch of reviews over the whole codebase. Yes, since we have one single file, that’s okay. However, in larger codebases, you must be careful to choose only the files you want to check.
To do that, just place the file name after the check
command:
yarn rome check index.js --apply
Once the command is finished, you can see that the code was automatically formatted. However, a problem still remains with the console output.
Since Rome can’t find a safe and automatic way to fix this, it’ll log the error at the console.
Don’t worry, there’s another option that can help with that. It’s the check review.
This is also the safest option since it allows us to choose how and which issues we’d like to fix. So, run the following command:
yarn rome check --review
Once finished, Rome will prompt a series of options for each one of the problems that it couldn’t solve itself. This way, you can decide how the fix may be addressed.
That’s very interactive. Just select one of the options and hit enter. Rome will always provide a default option of doing nothing in case you want to fix it yourself.
Leave the first option selected and hit enter. In the end, you may see that your code has changed:
// rome-ignore lint/js/noUnusedVariables function abc() { console.log("what's going"); }
Rome has automatically formatted the code and, due to our selection, added a comment before the function to ignore this validation in future lint executions.
Nice, isn’t it?
Alternatively, you can install the VS code Rome extension to get live errors as you type and format when you save your files. That’s pretty useful, especially if you’re seeking more productivity.
For that, go to your VS Extensions Marketplace and search for Rome. There’s not a lot of options, so it’s going to be easy to find it.
Hit the Install button and there it is.
Rome automatically displays an error message over the function name alerting for the unused nature of the recently created function.
That’s a lot better since you can see all the errors while programming. It’s also what most developers look for when picking a linter.
As soon as you call the function, the error disappears:
function abc() { console.log("what's going"); } abc();
It also works well with other types of files, like TypeScript. Take the following TypeScript example:
function abc(param) { console.log("Hello TypeScript") if (param == "abc") { return true;} setTimeout(()=>{console.log("timeout!")}, 100) }
Then, hit the yarn rome check index.ts --review
command and Rome will show the following prompt.
This time, we have a real fix being suggested (rather than just adding a suppression comment). See in green how the code is going to be after the suggestion is applied.
In blue, you can find the explanations about why the code you’ve typed is not right, as well as some important observations like if the fix is safe (and under what conditions).
Plus, every time Rome finds a good way to fix something, it shows the word “FIXABLE” at the top of the issue’s title.
At the end of the execution, the code will look like this:
// rome-ignore lint/js/noUnusedVariables function abc(param) { console.log("Hello TypeScript"); if (param === "abc") { return true; } setTimeout( () => { console.log("timeout!"); }, 100, ); }
Let’s take the previous example and step it up a bit. Look at the following code:
function abc(param) { const myConst = "abc" var myVar = "abc" try { console.log("Hello TypeScript") } catch (e) { e; e = new Exception(); } if (param == "abc") { return true;} }
Here, a couple of premeditated problems were placed:
catch
blockException
)==
)Wow, that’s a lot. Let’s see what Rome tells us about our code by running the yarn rome check index.ts
command.
We’ve omitted the lint problems we’ve seen before, but the list is bigger than that. Well, that’s a good way to prove that Rome is powerful enough to deserve a place within your favorite linters.
Rome also compiles your code. Let’s say you have some TypeScript code and want to compile it into JavaScript:
interface User { id: number; name: string; } class Account { id: number; name: string; constructor(id: number, name: string) { this.id = id; this.name = name; } } const user: User = new Account("LogRocket", 1); console.log(user);
Most of this code isn’t understandable by JavaScript, which means that it needs to be converted prior to use. With Rome, simply run the following command:
yarn rome compile index.ts
And this will be the output:
class Account { constructor(id, name) { this.id = id; this.name = name; } } const user = new Account("LogRocket", 1); console.log(user);
As you may have noticed, when you start a new Rome project, a new file called rome.rjson is autogenerated under the config folder.
This is the current content:
// For configuration documentation see http://romefrontend.dev/#project-configuration name: "rome" root: true
The first attribute is your project name, and the second tells Rome that it can search for nested projects existing into the current one in order to apply Rome rules.
This file is where Rome stores the customized configurations for the toolchain. And it’s also the place you may come when needing to fine-tune the way Rome is doing things.
You can edit the file directly or manage the configurations via the command line. For example, let’s say you want to change the name of the project and disable it as a root project. These are the equivalent commands for both operations:
yarn rome config set name "logrocket-rome" yarn rome config disable root
The changes will be committed to the rome.rjson file as well.
If you want to ignore some specific paths or file extensions in your Lint configs, simply run the following command:
yarn rome config push lint.ignore "*.ts" "/build" "/output"
The syntax is pretty intuitive, so now your TypeScript files and everything within the build
and output
folders will be ignored by Rome linter. This is the rome.rjson contents after the above commands:
// For configuration documentation see http://romefrontend.dev/#project-configuration name: "logrocket-rome" lint: { ignore: [ "*.ts" "/build" "/output" ] } root: false
This an experimental feature Rome offers. Since there’s no intention of providing backward compatibility, be careful with its use.
Rome aims to provide a way to build a standalone JavaScript bundle file for a package of your application in substitution of what Webpack does today.
Let’s take the index.js example. Then, run the following command:
yarn rome bundle index.js bundle.js
The first argument is related to the source file to be bundled, while the second relates to the destination file name. It’s important to provide the name of a file that doesn’t exist yet.
Below, you can check the output of this command:
Note that three files are generated under the bundle.js folder:
And the generated bundle file contents will look something like this:
(function(res) { if (typeof module !== "undefined") { module.exports = res; } return res; })( (function(global) { 'use strict'; // logrocket-rome/index.js var ___R$logrocket$rome$index_js = {}; var ___R$$priv$logrocket$rome$index_js$first = ["Log", "Rocket"], ___R$$priv$logrocket$rome$index_js$second = ["Log", "Rocket", "Plus"], ___R$$priv$logrocket$rome$index_js$both = ___R$$priv$logrocket$rome$index_js$first.concat( ___R$$priv$logrocket$rome$index_js$second, ); document.getElementById("demo").innerHTML = ___R$$priv$logrocket$rome$index_js$both; return ___R$logrocket$rome$index_js; })(typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : this)); //# sourceMappingURL=index.js.map
Rome is just at the beginning of its life, however, it’s promising enough to earn lots of attention and expectations from the community.
Rome also has some nice features that are still in the testing stage, like testing. Which will allow developers to run tests of files whose names are under the .test.*
pattern. When you put it all together, you can spot how rich such an environment can become. You have linting, compiling, formatting, bundling, and testing altogether in one single place.
Make sure to follow up closely with the official docs of Rome to see what’s coming.
How about you? Have you tested Rome already? What are your thoughts?
There’s no doubt that frontends are getting more complex. As you add new JavaScript libraries and other dependencies to your app, you’ll need more visibility to ensure your users don’t run into unknown issues.
LogRocket is a frontend application monitoring solution that lets you replay JavaScript errors as if they happened in your own browser so you can react to bugs more effectively.
LogRocket works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app’s performance, reporting metrics like client CPU load, client memory usage, and more.
Build confidently — start monitoring for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowSOLID principles help us keep code flexible. In this article, we’ll examine all of those principles and their implementation using JavaScript.
JavaScript’s Date API has many limitations. Explore alternative libraries like Moment.js, date-fns, and the new Temporal API.
Explore use cases for using npm vs. npx such as long-term dependency management or temporary tasks and running packages on the fly.
Validating and auditing AI-generated code reduces code errors and ensures that code is compliant.