Rome, a Modern Toolchain!

Rate this content

Modern JavaScript projects come in many shapes: websites, web applications, desktop apps, mobile apps, and more. For most of them, the common denominator is the technical debt that comes from settings up tools: bundlers, testing suite, code analysis, documentation, etc. I want to present you Rome, a toolchain that aims to be a all-in-one toolchain for the web, with one single tool you can maintain the health of all your projects!

Emanuele Stoppa
Emanuele Stoppa
31 min
01 Jun, 2023


Sign in or register to post your comment.

Video Summary and Transcription

Rome is a toolchain built in Rust that aims to replace multiple tools and provide high-quality diagnostics for code maintenance. It simplifies tool interactions by performing all operations once, generating a shared structure for all tools. Rome offers a customizable format experience with a stable formatter and a linter with over 150 rules. It integrates with VCS and VLSP, supports error-resilient parsing, and has exciting plans for the future, including the ability to create JavaScript plugins. Rome aims to be a top-notch toolchain and welcomes community input to improve its work.

Available in Español

1. Introduction to Rome

Short description:

Today we'll talk about Rome. Rome is a toolchain meant to replace a lot of tools. It's built in Rust and provides high-quality diagnostics. It works on IDEs and CLIs. Rome aims to provide all the tools to maintain the health of your code base.

Hello, everyone. Today we'll talk about Rome. Have you heard of it? Well, if you haven't, this is the time.

Okay, so, ciao a tutti. Hello, everyone. Emmanuele, Italian. Living in Ireland for 12 years, so it's a long time. And I'm really passionate about open source. I've been working in open source for the last six years on Webpack and now Rome. You can call me Emma. Don't use my full name. It's too long. And nobody gets it right. And of course I make the core container of Rome.

Now, Rome is a toolchain. It's meant to replace a lot of tools that you know about. Pretier, Lint, Webpack, Lintstridge, and lots of them. So quite a lot of tools. It's built in Rust. And it's been written from developers to you guys, developers.

Now, let's go into it. Why Rome? Well, we have two things quite famous. All roads lead to Rome. And Rome wasn't built in a day. So this has a lot. Why modern? Because we want to provide high-quality diagnostics, so meaningful errors. And it must work on IDEs and CLIs, which are your tools of your daily jobs. And why a tool chain? Well, we want to provide all those tools that help you to maintain the health of your code base. Formatter, linter, bundler, documentation generation, analyzer in general. So we have a lot of tools and we aim to provide most of them all.

2. Configuration and JSON Schema

Short description:

Yeah, it's a lot, but we will get there. This is an example of a modern web project. You have to maintain separately all the files for each tool, but we aim to cut them down to just two files. Our JSON schema is auto-generated from the source code, providing documentation and auto-completion. We are not an aggregator of existing tools like create React app, which can slow down your work environment.

Yeah, it's a lot, but we will get there. So, taking all these definitions, now let's see what it actually means. So first of all, a config file through the mode. So this is an example of a modern web project. As you can see, we have a lot of files for each tool, ptr, eslint, tailwind, tsconfig. I mean, you know what I mean and there's a lot going on, you know.

You have to maintain separately all of them and we want to cut them all and have just two files, eventually also the log. So that's what we aim to. And it's an example of your configuration file. As you can see, from one file you can configure all the tools, all there, formatter, linter. We also have a JSON schema, which we deem really important because it's going to give you a lot of goodies, like, for example, auto-complications.

So this is a screenshot where I'm trying to type a rule inside the style group. And as you can see, I get the auto-completion. And as well, I get also a small description that tells me what the rule is about. So you don't need to go to the website and understand what's the rule about. your IDE and, I mean, go to DX. The also good thing is that our JSON schema is auto-generated from the source code. So we managed to document everything in our source code and spread the documentation through different channels, and the JSON schema is one of them. So this is an example, the line with, check that descriptions. And we have the same exact descriptions in our RUST file. That's a documentation comment. It's a special comment in the RUST codebase. And it's like a metadata that is attached to that type, the language. And with that metadata, we are able to provide the documentation for the JSON schema. And we are not an aggregator of existing tools. An example of an aggregator of existing tools is create React app. It aggregates lots of tools and they try to make them better for us. But it's difficult because everyone has different needs and configurations. So it takes a lot of energies and it slows down your work environment. And why? Well, I tell you why.

3. Tool Interactions and Rome

Short description:

Each tool analyzes, transforms, and operates on your code individually. They are not aware of each other, requiring plugins and synchronization efforts. Rome simplifies this by providing a single tool that performs all operations once, generating the CST or AST.

So you have your application. Okay. Nice. Your source code. You have all these tools around your applications. I just chose some of them. The most famous ones. But surely there are even more.

What happens is that each tool just they have to analyze, pass your code, transform it, do operations. And these operations are repeated for each tool. Let's say, for example, prettyer and ESLint. You need to parse it and do the operation. Same thing for ESLint. So this is override.

Even though these tools might be really great and they are great, they do their job. The thing is they are not aware of each other. See? So the fact that they are not aware of each other also implies that the community needs to spend a lot of time to compensate this breach. An example, ESLint plugin prettier. So a plugin that was written to bridge the gap between ESLint and prettier in order to like suppress some ESLint rules so that prettier can work. Other examples, Vitt aggregates, existing tools like rollup, ESbuild, a filewatcher. And they have to spend some time to synchronize them. So the community has done a lot. Like the Tertser web hub plugin. So you name them, there's a plugin for everything.

With Rom instead, you just have your application. You have one tool, which is Rom. And it does the operation once. So you have your file. This file is part once we generate the CST or AST. In this case we generate the CST.

4. Structure Sharing and Diagnostic Anatomy

Short description:

And this structure is shared among all tools. The formatter and linter have their own jobs, and they are aware of each other. Rome aims to provide high-quality diagnostics and better errors for a better developer experience. The anatomy of a diagnostic includes the file name, error position, category, and tags.

And this structure is then shared among all tools. So we make a copy, we give it to the formatter, it does its own job. Same thing for the linter. It's own job, and that operation is done once.

Also, if you have linter and formatter enabled, and you apply the code action or the fix from a lint rule, this code action passes through the formatter and it applies the formatter of the code action based on the configuration file. So they are also aware of each other. So they know they coexist. This is not like this at the moment. So that's what ROM aims to do.

High quality diagnostic. So this is a good one. So have you ever seen this kind of diagnostic before? Like unexpected token. What's that? I mean, for you guys, CISM developers, you know already what's that. But this is not beginner-friendly. Like a beginner sees that and like what's YDR is unexpected. OK. So with ROM, we want to do like provide better errors. So this is an example of a diagnostic for the same snippet. So we try to say, listen, actually we found a return, not an R. And we expect an expression. Even though express is not still beginner-friendly, I think it's a step forward toward a better developer experience. So now, this is a ROM diagnostic. And I want to like go through the anatomy of a diagnostic.

So this is another example of diagnostic coming from a lint rule, okay, which suggests also code action. So we have the name of the file. We then have the position where the error occurs. We then have a category, in this case is the name of the rule. And that's actually a link. So you can actually go with your mouse, you can click it, and we'll go to the documentation page and we'll open a browser. Then we have these labels or we call them tags that gives more metadata to the actual diagnostic.

5. Diagnostic Fix and IDE Integration

Short description:

In this case, we have a diagnostic that can be fixed. The message and color indicate it's a warning. We provide a code frame to highlight the error and additional information to give context. Code actions are suggested fixes, but can be unsafe. In the IDE, we see the same diagnostic with a link to the rule. LSP supports code actions, including suppressing the rule with an explanation.

In this case, this is a diagnostic that can be fixed. We then have the message and the color changes based on the type of diagnostic. In this case, is a warning. It's not an error because it's yellow. We have the code frame where we highlight the error. Then we also have a section where we provide the- we try to provide more information to like give a context to the developer why we think this is actual an error for this rule.

And then eventually we get the code action. So this is a suggested fix or better called unsafe fixes, because we know JavaScript is full of side effects. So it's quite difficult to provide sometime code actions that are safe. So sometimes you have to opt in for this kind of code fixes.

Now I show you the same diagnostic on the IDE. Okay. So, as I told you before, they have to work via CLI and LSP. So here we have the same code snippet. This is a screenshot from VS Code which supports LSP. As you can see, we get the same message, okay, with the actual link to the role. We don't get the actual note or description because the LSP doesn't support all this kind of information. Although we have... we can provide more code actions on the LSP because this is an interactive section. So we actually provide two code actions. The first one is the one that you saw before. And the second one, the suppression of the rule. And if you choose the second one, you get a comment that suppresses the rule. And there we have an explanation because ROM requires an explanation when you want to turn off the rule. I think this is a good practice. So we actually say why you turned off the rule. Like it's considered like a safe comment. Like you want to use the bang operator from time square, which is white and safe. But if you know that is safe, you leave the comment so your colleague goes there and knows why you turned off the rule for the bang operator. It needs to be easy to use.

6. ROM Commands and Configuration

Short description:

ROM provides two commands with really good defaults, allowing you to use it without a configuration file. It works seamlessly with the VS Code extension and CLI, providing a powerful CLI with many options. You can customize your format experience using your configuration file.

So we choose just two commands. You can use ROM like this. Actually, you can use just the second one if you want and it actually just works. And why? Because ROM has really good defaults. So we have a set of really good defaults, optionated. Okay. You're free to use ROM's defaults. And you don't need a configuration file. You don't even need like you can install it in the VS Code extension and it will just work. So you can use the bundled version of the VS Code extension and that's it. So you can also use it in the CLI and it works. We also have a really powerful CLI, so we also want to provide as much as options possible until a certain limit. So you don't need to install it as a dependency. You can use it in the CLI and it will work. And then just use your configuration file. You can turn off your lint rules, change the post style, and so on and so on.

7. App Section of the Format Command

Short description:

This is an example of the app section of the format command. ROM provides options to customize your format experience. The formatter is stable and meant to replace Prettier. The linter has almost 150 rules and supports React. Rules are categorized into groups, including a nursery group for rules under development. Import sorting is available as an analyzer.

So this is like an example of the app section of the format command. And as you can see, we try to provide all the options needed to customize your format experience. And note if you remember, that line is the same line that I showed you before at the beginning in the JSON schema. As you can see, that's also auto-generated from code. So we developers, we actually write the documentation in the source code and then we provide it to you. So it saves us a lot of time. One of the perks of the RAST language.

Now, I showed you something I want to also tell you, that ROM is quite stable. It ships a lot of features. Not that many as we hoped, but the formatter is really stable. It's production-ready. It's actually meant to be a replacement for Prettier. It doesn't support still all the options. It's a bit of controversy in some of the options. But you can chime in in the GitHub discussions and we can try to provide all the other options. We support JavaScript and all the super languages, JSON as well.

The linter has almost 150 rules. There are not as many as is Lint, but the community behind it is still working on adding new rules. We also have React 2 rules. They are still in the nursery group, so this is actually a new concept that doesn't exist in Lint, which are the groups. We try to categorize in groups the rules so you actually get to know the context of your rule. You also have to turn off the rules of the style group. Among these groups, we have a special group called the nursery. This is a concept that we borrowed from the Rust ecosystem, which it's a group of rules where they are still under development. They might be broken. It's also like a safety net for us developers and maintainers for rules that are really broken but they are like recommended by default and we can demote them to nursery because it's like there's a false positive and like a difficult to fix. So, we just demote them and they don't follow semantic versioning. So, it's also good for us developers. We also have import sorting. It's an analyzer not the formatter because JavaScript is a language with side effects.

8. Rome's Strengths and Recoverable Parser

Short description:

Rome integrates with VCS and VLSP, supporting diagnostics similar to NCIL and LSP. There are community efforts and plugins available for various editors, except IntelliJ. Rome's recoverable parser allows for error-resilient parsing, continuing parsing even in the presence of syntax errors. It borrows concepts from the Roslyn project and enables niche features like formatting code with syntax errors and linking broken code. Rome can parse configuration files and apply defaults only to broken sections.

So, we need to analyze your code in order to move your imports. It integrates with VCS and, well, VLSP as I showed you before, it works out of the box. So, diagnostics works in the same like NCIL and LSP. And there are ready like some community efforts around there. So, there's a plugin for Nix, Helix, NeoVim.

So, there's a radio community where they developed plugins for editors that support LSP. Still not IntelliJ, unfortunately, it doesn't support LSP. So, I want to show you now also some of the strengths of from. So, some things that you might not have seen, they are a bit controversial and but just bear with me. And I mean, I think they're good but it's for you to judge.

So, Rome has a recoverable parser. So, a recoverable parser is a parser that when encounters a syntax error doesn't stop. So, it tries to resume the correct parsing as much as they can, and then tries to finish the actual parsing until the end of the file. It must be error resilient because this kind of parser must work in the IDs. And the parser that we have in the IDs, they are the best parsers at all because they are error resilient. When Rome's parser sees a token or a character that doesn't belong in that position, he starts eating those tokens until they find a token that actually makes sense. I don't know, a curly bracket that belongs to the body of a function. There, they start, the parser starts to resume the correct parsing and all those tokens that were eaten were actually gone in this bogus node.

Bogus is actually a term that we borrowed from the Roslyn project. Roslyn is the compiler that pumps .NET essentially. So, we borrowed a lot of concepts from .NET, from this Roslyn project. It's a great project if you are into compilers. So, what about it? I mean, okay, we have this recordable parser, what can you do with that? Well, we can do a lot of niche stuff, like we can format code that has syntax errors. Now, this is quite controversial, because a lot of developers, myself included, used the formatter to understand if the code is actually syntactically correct or not. So, this is an opt-in feature. We can also link the broken code. So, I think this is quite good. Okay. So, you don't need to have a perfect code in order to receive diagnostics. And then, we are also able to parse the configuration file and apply our defaults only for the sections that are broken.

9. Analyzing a Broken Configuration File

Short description:

Now, I'm going to show you a small video where we have a broken configuration file with syntax and semantic errors. Despite not having a recordable parser, Rome is able to provide meaningful diagnostics and suggestions for fixing the broken file. Rome can analyze and inspect sections of code even within a broken file. Additionally, Rome is fast, as demonstrated in our benchmark.

Now, I'm going to show you a small video. It might be fast, but then I'm going to break it down and show you what it means. So, in this video, on the left, there's a configuration file that it's broken. So, there's a syntax error. And on the right, I'm going to try to format some code based on the code style single. Theoretically, for a tool that doesn't have a recordable parser, we should see some error, like, oh, the file doesn't work. But here, we have some result. Now, I want to show you what happened.

Okay. Now, so, that's the configuration file. So, we have some missing comma there before the linter and also after the outro. Okay. Now, when I ran the command, the first diagnostic was about parsing the JSON file. So, we have the file, we have the category, which is the parse. And then, a meaningful message that tries also to guess a possible suggestion on how to fix the broken file. It doesn't need to be right, but as you can see, it's a guessing game with a recordable parser. Then, we also have a semantic error. So, the configuration file also, for example, in this case doesn't allow a set of options like recommended all cannot both be true. So, during the visualization of the configuration file, there was an error. Now, the good thing is that we were able to actually analyze like a node or a section that was actually broken. Okay. So, we managed to actually inspect like a good code that was inside the bad code. So, Romtex, you look, this is not an error, but Lisa will prime my, will apply my own defaults for you. And then we have the code action of the formatter that they show you the code style single. So, if we go back, we add code style single and here that's what we have. So, we actually managed to actually apply the correct formatter. Now, Rome is fast, okay? This is a screenshot of our benchmark. So, in our repository, we have a benchmark folder where you can run it. It works with Docker and I leave it to you, but I want to show you a small demo. So, this is the TypeScript repository and I'm going to try now to run Pretier, okay, on the TypeScript repository.

10. Rome Usage and Future Plans

Short description:

I don't have enough time to explain, but I tried Rome and it's fast. The project is still active with exciting plans. You can't convert existing configuration files or reuse custom rules from other libraries yet. We're working on it and there are community efforts. Contributing to Roam is easier than doing it yourself.

I don't have enough time. I have to stop it. It takes too long. Now, I'm going to try with Rome. I'm going to set the max size of the file because there's a checker file which is two megs and that's it. Like 644 files in the few milliseconds. Thanks.

Okay, another small one, a fast one. Well, actually we have already the result but I want to show you, do it again. So, AntDesign, if you know it, uses Roam, okay. So, I'm going to run their command. I mean, it actually worked like it's so fast sometimes that I think like it didn't work but no, it worked.

So, what's next for Roam? So, the project is still active. This is a small but really focused and excited community. So, we want to leave JSON files, add new languages and so, and set up the base for the builder. The bundler, more intros and so on. So, there's a lot of going on. Few personal info if you want to follow me or the Roam community and thanks.

Okay, the first question that we have is, can it convert existing configuration files? Can you reuse custom rules from other libraries easily? Quote's important. Oh, not at the moment no. You can't use other rules from other projects at the moment, no. What would you suggest for someone who has a bunch of rules configured in another project and then would want to use Roam? So, we are working on imparting all the ESLint rules that are recommended by the tool to Roam. So, we have a roadmap with an umbrella issue to try to port all of them. And then, as I said, there are some community efforts to try to port also other rules, also from TypeScript, ESLint. So, if you want, just start a discussion and we can surely. Okay. So, then it's probably easier for someone to contribute to Roam rather than trying to do that themselves within their own project. Yes. Even though it's Rust, like, we have a really good documentation, contributed section, I mean, and also the language, we can help everyone to tackle the issue and the language. Yeah.

11. Future of Roam Tools and Comparison to Other Tools

Short description:

The future of Roam tools includes the ability to create JavaScript plugins. The community is asking for this feature, and we have a proof of concept created by an ex-colleague. We want to set up the foundations of the most important and challenging sections. When comparing RUM to other tools like TurboPack and SWC, we aim to be a toolchain that allows you to use your CLI and maintain your source code in different angles.

Yeah. Great. All right. Next question. And you touched on this a bit, but would love to know, how do you see the future of Roam tools looking? Like, where would you like to see it go? You mentioned, kind of, what's coming up next, but maybe even, like, further into the future.

Well, that's a nice question. So, what we really like to do, it's also being able to create JavaScript plugins. This is something that the community is asking a lot. We have questions on here about plugins. So, this is great. Yeah. Yeah. But first, we would like to try to set up the foundations of the most important the most challenging sections, but I think also the most important ones. We also have, like, a proof of concept to create a JavaScript plugin created by an ex-colleague of mine. There's a branch there that was created. I haven't looked at it yet, but... It's there. You know it's there. And it works. Okay, pass.

Great. All right. Next one. How does RUM compare to other tools like TurboPack, SWC, BUN, similar, et cetera? That's a lot of tools. How does it compare to other tools? Yeah. In our ecosystem. SWC as far as I understood, it wants to be like a replacement of BUBBLE. Okay. We want to be that as well, but we are a toolchain. So you want to use your CLI and maintain your source code in all different angles.

12. ROAM's Ambition and Diagnostic Assumptions

Short description:

ROAM aims to be a toolchain, providing more ambitious and top-notch work compared to SWC and TurboPack. While ROAM doesn't yet have TypeScript ESLint with type checking, they are attempting to use TypeScript to gather typing information and convert it into a data structure readable in Rust. When deciding which diagnostics to provide more context for, ROAM goes with assumptions and aims to give good suggestions, borrowing descriptions from existing tools and giving them credit. They are open-minded and welcome community input to improve their work.

So for Martin, this is something that SWC doesn't have. And also TurboPack. TurboPack is meant to do one job very well, and that's it. ROAM wants to be like something different, a toolchain. So it's more ambitious, there's going to be more work, and also the quality of this work needs to be top-notch. But that makes sense. The scope's completely different in that way. Yeah. All right.

So then is there something like TypeScript ESLint with type checking for ROAM? Not yet. Not good? Not yet? Does that mean it's coming? So we wanted to try to use actually TypeScript to gather all the typing information and then convert them in a data structure that can be read in Rust, and then try to use this metadata to provide meaningful rules. Because a type checker is quite difficult, especially TypeScript, because even though it's a type checker, it's still a dynamic typing language, so it's very, very difficult to implement. That's our first attempt, so to try to use the existing tool and then borrow. That makes sense. All right.

This one is one I was excited about. So how did you decide which diagnostics to provide more context for? So did you go off of assumptions, maybe user research? Yeah, we go with assumptions, actually. So we have some pillars in our documentation page where we try to say, okay, errors, they need to be as most context as possible. They have to use beginner-friendly words. So we try to be mindful and try to assume that the user is actually a beginner. And then based on that, we try to give good suggestions. But, yeah, we go with assumptions. And in case we borrow and we try to replicate a rule from existing tools, we actually borrow their description. We make it a little bit different, but we provide the credits and the source of the rule, because they invented the rule, they deserve a credit. So that's the actual assumptions that we do when we try to provide diagnostics. So... Yeah, that makes sense. I work in documentation to get that question all the time. Like, kind of like, if you're going to put in that effort, how do you even know where to start? But I think like maybe dealing with some of the problems that obviously you face, like using these other tools, where might someone who's coming into the project need that assumption? Like we had a case where we had the role that was under a section, and then the community came to help. And with the discussion we actually changed the wording and also the category. So we are open-minded. We are not closed. We want the community to help us if we are doing the wrong. So we want to fix it. That's a great note to end on. Thank you so much, Ema.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

The Future of Performance Tooling
JSNation 2022JSNation 2022
21 min
The Future of Performance Tooling
Top Content
Our understanding of performance & user-experience has heavily evolved over the years. Web Developer Tooling needs to similarly evolve to make sure it is user-centric, actionable and contextual where modern experiences are concerned. In this talk, Addy will walk you through Chrome and others have been thinking about this problem and what updates they've been making to performance tools to lower the friction for building great experiences on the web.
Server Components with Bun
Node Congress 2023Node Congress 2023
7 min
Server Components with Bun
Top Content
An early look at using server components via Bun’s new bundler, with and without React.
Improving Developer Happiness with AI
React Summit 2023React Summit 2023
29 min
Improving Developer Happiness with AI
GitHub Copilot is an AI pair programmer that can help you write code faster and spend less time writing repetitive code.This session will cover some interesting use cases for Copilot that could shine a light on its possibilities. This ranges from prompting Copilot to suggest a function based on a comment, learning how to use a new framework, tackling a security or accessibility bug, better documenting your code, translating  code from one language to another, etc.Agenda:
Introduction to CoPilot
- What is Copilot
- How can you use it
- How it can help you write code faster
- Copilot Labs experimental features I will pick examples from the React ecosystem and show how we can fix Security Vulnerabilities and Accessibility issues in some components.
Static Analysis in JavaScript: What’s Easy and What’s Hard
JSNation 2023JSNation 2023
23 min
Static Analysis in JavaScript: What’s Easy and What’s Hard
We are all using static analysis tools like ESLint every day to ensure the better quality of our code. How does it work, and what is tricky about JavaScript, making writing a proper rule often not trivial?
How I Automated Code Changes for 100 Repositories: Getting Started With Codemods
React Day Berlin 2022React Day Berlin 2022
28 min
How I Automated Code Changes for 100 Repositories: Getting Started With Codemods

Workshops on related topic

Solve 100% Of Your Errors: How to Root Cause Issues Faster With Session Replay
JSNation 2023JSNation 2023
44 min
Solve 100% Of Your Errors: How to Root Cause Issues Faster With Session Replay
Ryan Albrecht
Ryan Albrecht
You know that annoying bug? The one that doesn’t show up locally? And no matter how many times you try to recreate the environment you can’t reproduce it? You’ve gone through the breadcrumbs, read through the stack trace, and are now playing detective to piece together support tickets to make sure it’s real.
Join Sentry developer Ryan Albrecht in this talk to learn how developers can use Session Replay - a tool that provides video-like reproductions of user interactions - to identify, reproduce, and resolve errors and performance issues faster (without rolling your head on your keyboard).