Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

docs: repo integration guide #3767

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions website/src/pages/guides/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ If you are working on a project that isn't using Node.js, then the best way to i

Success! You're now ready to use Rome. 🥳

* Read the guide on how to quickly integrate the formatter and linter [into your repository](/guides/integrating-into-your-repository)
* Learn more about how to use and configure the [formatter](/formatter)
* Learn more about how to use and configure the [linter](/linter)
* Get familiar with the [CLI options](/cli)
Expand Down
373 changes: 373 additions & 0 deletions website/src/pages/guides/integrating-into-your-repository.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,373 @@
---
title: Integrating into your repository
category: guides
emoji: 🔗
description: Learn how to integrate Rome into your existing repository setup.
---

import PackageManagerRomeCommand from "/components/PackageManagerRomeCommand.astro";
import PackageManagerCommand from "/components/PackageManagerCommand.astro";

# Integrating into your repository

Rome is meant to eventually become capable of performing the same tasks that most of your current tools do, faster and easier than your current tools do. But in the meantime, you do not need to worry about Rome not playing well with your current tools. This guide provides examples to introduce Rome into an existing repository, even if your repository is a [monorepo](https://en.wikipedia.org/wiki/Monorepo) composed of different packages.

Initial installation of Rome will generally not vary with most common repository setups. Check our [Getting Started guide](/guides/getting-started) to find out how to install Rome. If you have a monorepo, you will usually want to install Rome in its root, not in an individual one of your packages.

We have compiled a list of common repository setups for you, and explanations on how to integrate Rome into each one of them follow. Make sure you have installed Rome first.

## Single package without existing formatting or linting

After following the [Getting Started guide](/guides/getting-started), you can already use the formatter and linter while developing:

<PackageManagerRomeCommand command="format --write ." />
<PackageManagerRomeCommand command="check ." />

If you would like shorter commands for these, you can add `scripts` to your `package.json`:

```json
{
"scripts": {
"format": "rome format --write .",
"lint": "rome check ."
}
}
```

### CI

If you have a CI pipeline, such as GitHub Actions, we recommend that you check formatting and linting as part of it by adding the following command:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be practical to include a guide on (or at the very least, a reference to) the Rome GitHub action & how it can be setup in a GitHub repository.


<PackageManagerRomeCommand command="ci ." />

Alternatively, they can be part of a script that your CI pipeline runs:

```json
{
"scripts": {
"ci": "rome ci ."
}
}
```

`rome ci` by default runs both formatter and linter checks. If you are not ready to adopt both, you can disable e.g. the linter in `rome.json`:

```json
{
"linter": {
"enabled": false
}
}
```

### Ignoring files

If you have files that do not require formatting or linting, such as compilation outputs in a `build` directory or scattered `generated` files, you can ignore them by extending your `rome.json` with the following:

```json
{
"formatter": {
"ignore": ["build", "**/*.generated.js"]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and similar code examples should likewise also be adapted when we ship files.ignore, again not sure if release will be before this doc merge

},
"linter": {
"ignore": ["build", "**/*.generated.js"]
}
}
```

Instead of ignoring files, it is also possible to run Rome only on specific explicitly included files. However, we recommend that you try using `ignore` if possible. If you explicitly specify which files to format or lint and later a new Rome version comes out with the capability to check even more types of files, you may lose out without noticing! To explicitly run Rome for example only on TypeScript files, run:

<PackageManagerRomeCommand command="format --write **/*.ts" />
<PackageManagerRomeCommand command="check **/*.ts" />

## Replacing Prettier and ESLint

After following the [Getting Started guide](/guides/getting-started), let's look into replacing each tool with Rome. Note that while we try to make the transition from these tools as easy as possible, there will always be some deviation from the behavior of these tools. You may see some reformatted code, missing lint rules, or lint errors from new rules when adopting Rome.

### Prettier

First, replace any script(s) you were using to check and to reformat your files using Prettier.
For example, in your `package.json`, change:

```diff
{
"scripts": {
- "format": "prettier --write ."
+ "format": "rome format --write .",
- "ci:format": "prettier --check ."
+ "ci:format": "rome format .",
Copy link
Contributor

@ematipico ematipico Nov 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is the correct transition, rome format doesn't return an error code here, while prettier does. The correct way for us to suggest the transition for CI environments should be:

rome ci --linter-enabled=false .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohh that's true, I never looked at the exit code, only assumed it would exit 1 if it prints the formatter diff. I will change this for the guide.
Are you aware of discussion threads or so on the CLI design? There have been a few design decisions now that struck me as odd compared to existing JS tools and also other CLI tools, would be good to get more context or to get involved if there are still active discussions about potential changes

Copy link
Contributor

@ematipico ematipico Nov 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There have been some issue around the unclearness/oddity of how error codes are returned from our commands.

There have been talks between the staff team about using error codes in a better way (a la' prettier), and we do want to use this Rust primitive, but we haven't had the time to look into it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to start a github discussion if you have suggestions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I commented on #3443 to keep it in one place. I think there's a good way forward.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path forward for this and the other instances of it that I have in mind: We recommend an example like

"format": "rome format --write .",
"check:format": "rome format --check .",
"lint": "rome check --fix .",
"check:lint": "rome check ."

but add a CI section like at the start of the guide to clarify that CI should run not these but rome ci (if necessary with parts of Rome disabled via rome.json)

}
}
```

Instead of `prettier --write .`, you may be giving Prettier a pattern of files to format, such as `prettier --write **/*.ts`. If this is the case, we recommend that you instead explicitly specify which files you do _not_ want formatted as ignored files, which is explained in the next section.

Instead of ignoring files, it is also possible to run Rome only on specific explicitly included files. However, we recommend that you try using `ignore` if possible. If you explicitly specify which files to format or lint and later a new Rome version comes out with the capability to check even more types of files, you may lose out without noticing! To explicitly run Rome only on specific files, use:

```diff
{
"scripts": {
- "format": "prettier --write **/*.ts"
+ "format": "rome format --write **/*.ts",
- "ci:format": "prettier --check **/*.ts"
+ "ci:format": "rome format **/*.ts",
jeysal marked this conversation as resolved.
Show resolved Hide resolved
}
}
```

Do not quote a pattern like `**/*.ts`. Most modern package managers are able to handle it correctly on all platforms.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC there's an issue to implement glob patterns in Rome. I think it would be useful to do that to reduce reliance on package managers here. Recommending to run through package manager scripts is generally a bit of an eyesore to me, because it's so much slower. It would be nice to have a better way that we can confidently recommend to people. In the meantime, any further dependency on package managers such as for globbing would be good to avoid for future-proofing


#### Ignoring files

If you use a `.prettierignore` file or otherwise wish to leave some files (such as compilation outputs) unformatted, add `ignore` patterns to your `rome.json`:

```json
{
"formatter": {
"ignore": ["build", "**/*.generated.js"]
}
}
```

This is equivalent to the `.prettierignore` file

```
build
**/*.generated.js
```

#### Configuration options

Prettier tries to avoid formatting Configuration options to reduce complexity and end debates over formatting styles, however they had to strike a balance and introduce a couple of options in order to enable widespread adoption. Rome follows the same philosophy. Our [configuration reference](/configuration/#formatter) shows the options available, which more or less directly map to Prettier options, sometimes named slightly differently. For example, your `.prettierrc` might specify the following:

```json
{
"singleQuote": true
}
```

To preserve this behavior as you introduce Rome, you can add the following to your `rome.json`:

```json
{
"javascript": {
"formatter": {
"quoteStyle": "single"
}
}
}
```

### ESLint

Similarly to formatting, replace the scripts used for linting in the `package.json` file, for example:

```diff
"scripts": {
- "lint": "eslint --fix ."
+ "lint": "rome check --apply .",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lint command is unfortunately not equivalent right now. If rome finds an error that has a suggested fix, it will print "skipped 1 suggested fix" and not highlight the problem and exit with 0. This seems unintuitive to me, does anyone know if this is intended or discussed in some issue?

Copy link
Contributor

@ematipico ematipico Nov 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's intentional. rome check is supposed to be the command to make sure the code is correct. --apply and --apply-suggested are volountary commands where the user decides to fix the code and how to fix it. It seems a bit redundant to show them diagnostics (at least the ones related to linting).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. That still seems unintuitive to me to be honest, as flags usually only alter/augment the behavior of a command and this seems to be more like a completely different command (rome apply).
I think in this guide I can still leave it as a recommendation despite the different behavior, since I'm not recommending anyone to use this command for CI or anything dangerous like that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense, thank you for the suggestion.

FYI we plan to remove --apply-suggested in the next months. This command was created as a quick workaround to allow users to apply also suggested fixes, but the correct way to do so would be to use a rome check --review argument that enables an interactive review where users can decide to:

  • apply the suggested fix
  • or suppress the rule

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

- "ci:lint": "eslint ."
+ "ci:lint": "rome check .",
jeysal marked this conversation as resolved.
Show resolved Hide resolved
}
```

#### Ignoring files

Ignoring files for the Rome linter works in the same way as ignoring them for the Rome formatter in your `rome.json`:

```json
{
"linter": {
"ignore": ["build", "**/*.generated.js"]
}
}
```

This is equivalent to the following `.eslintignore` file:

```
build
**/*.generated.js
```

#### Rules

Rome tries to provide a comprehensive set of rules out of the box, but it is still under development. Just like you may see new lint errors with Rome that ESLint missed on purpose or by accident, Rome may also not detect some issues that you'd like it to. If that happens, do not hesitate to make a suggestion on our GitHub if no one else has made the same report yet!

We try to provide reasonable default rules in our `recommended` rule set that was automatically enabled when you ran `rome init`, and explain what a rule is meant to achieve in its diagnostics. If you relied on ESLint presets curated by others and were happy with it, you can just leave the rule configuration to us!

If you would like to fine tune your rules, you can look at out corresponding [reference documentation](/lint/rules). A rule can be disabled by setting it to `off`, or enabled by setting it to `error`. Example:

```json
{
"linter": {
"rules": {
"style": {
"noUnusedTemplateLiteral": "off"
}
}
}
}
```

### All in one

Now that you have a tool that can do both formatting and linting at once, you also have the option to run overall checks on your code all-in-one, for example on a CI pipeline:

<PackageManagerRomeCommand command="ci ." />

You can also uninstall Prettier and ESLint from your repository now if you would like, unless you still use them somewhere else in the repo.

## Turborepo

After following the [Getting Started guide](/guides/getting-started) to install Rome in the root of the repository, you have two options:

1. Use Rome directly in the root of your repository. We recommend this approach if it works for your repository. Rome is meant to handle monorepo setups as it evolves to cover more and more areas of developer tooling.
2. Use Rome in individual packages. This may make sense if your packages are very different each other. You may even decide to lint with Rome in one of them, but with a different tool like ESLint in another!

We explain each option below. For more in-depth information on Rome's equivalents to Prettier and ESLint configuration, you can additionally refer to the general Prettier and ESLint guide above.

If none of these options work well for you, let us know by opening a discussion on our GitHub!

### Using Rome directly

This is the fastest way to set up Rome and will deliver the best experience. However, it is not yet adaptable to more complex repository setups.

Replace the `lint` and `format` scripts with Rome's alternatives in your root `package.json`:

```diff
{
"scripts": {
- "lint": "turbo run lint",
+ "lint": "rome check .",
- "format": "prettier --write \"**/*.{ts,tsx,md}\""
+ "format": "rome format --write ."
}
}
```

We recommend running `rome format` on the whole directory (`.`). For more details and what to do if you need to ignore files, refer to the guide section for general migration from Prettier above.

You can now use the same scripts you are used to, but they are backed by Rome's formatting and linting. You can remove your dependencies on Prettier and ESLint, as well as any `.eslintrc` files, `eslint-config-*` packages, and similar code. If you have customized your linting after the turborepo setup and would like to apply similar customizations to Rome, refer to the guide section for general migration from ESLint above.

### Using Rome in individual packages

If you would like to use Rome in some of your packages but not in others, that is also possible.

#### Formatting

Make a list of packages that you would like to keep formatting with Prettier, and configure Rome to ignore them in `rome.json`:

```json
{
"formatter": {
"ignore": ["packages/ui", "apps/web"]
}
}
```

Then, adapt your `format` script in `package.json` to run Prettier on those packages, and Rome on the rest:

```diff
{
"scripts": {
- "format": "prettier --write \"**/*.{ts,tsx,md}\""
+ "format": "prettier --write packages/ui apps/web && rome format --write ."
}
}
```

#### Linting

You can leave the root `package.json` untouched. In packages that you would like to lint using Rome, replace the `lint` script in the `package.json` file. For example, in a standard turborepo Next.js app, change:

```diff
{
"scripts": {
- "lint": "next lint"
+ "lint": "rome check ."
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we've shipped it in time, we should recommend --force-colors here. Otherwise the output looks shite calling through turbo lint in the root

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That will be part of the next release :) #3625

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup I saw, just not sure if that'll be out soon enough before this is merged

}
}
```

Or in a standard turborepo library, change:

```diff
{
"scripts": {
- "lint": "TIMING=1 eslint \"**/*.ts*\""
+ "lint": "rome check ."
}
}
```

You can run the `lint` script in your repository root or in individual packages as you are used to.

## Nx

We're still [looking into](https://github.com/rome/tools/issues/3709) integrating Rome seamlessly with [Nx](https://nx.dev). In the meantime, you can use Rome directly from the CLI or in `package.json` scripts if you would like, as described in previous sections!

## Workspaces, Lerna, etc.

After following the [Getting Started guide](/guides/getting-started) to install Rome in the root of the repository, you have two options:

1. Use Rome directly in the root of your repository. We recommend this approach if it works for your repository. Rome is meant to handle monorepo setups as it evolves to cover more and more areas of developer tooling.
2. Use Rome in individual packages. This may make sense if your packages are very different each other. You may even decide to lint with Rome in one of them, but with a different tool like ESLint in another!

We explain each option below. For more in-depth information on Rome's equivalents to Prettier and ESLint configuration, you can additionally refer to the general Prettier and ESLint guide above.
to
If none of these options work well for you, let us know by opening a discussion on our GitHub!

### Using Rome in the root

This is the fastest way to set up Rome and will deliver the best experience. However, it is not yet adaptable to more complex repository setups.

Add the following scripts to your root `package.json`:

```json
{
"scripts": {
"format": "rome format --write .",
"lint": "rome check .",
"ci": "rome ci ."
}
}
```

We recommend running `rome` on the whole directory (`.`). For more details and what to do if you need to ignore files, refer to "Ignoring Files" in the single package guide section at the start of this page.

We try to provide reasonable defaults, but if you would like to make customizations like fine tuning your lint rules, you can also refer to the single package guide section to learn how to do that.

### Using Rome in individual packages

If you would like to use Rome in some of your packages but not in others, that is also possible.

Usually, you can just run Rome directly as described immediately above, but ignore packages that you would like Rome to leave untouched.
For example, if you are not ready to format and lint your `ui` and `frontend-app` packages, or would like to use other tools for them, you can ignore those packages in your `rome.json`:

```json
{
"formatter": {
"ignore": ["packages/ui", "packages/frontend-app"]
},
"linter": {
"ignore": ["packages/ui", "packages/frontend-app"]
}
}
```

#### With a monorepo command runner

Alternatively, if you would like to keep all your tools isolated to individual packages, you can add the Rome commands to the `package.json` files of those individual packages:

```json
{
"scripts": {
"format": "rome format --write .",
"lint": "rome check .",
"ci": "rome ci ."
}
}
```

Then, you can use your package manager or monorepo management tool (such as Lerna) in the root to run the scripts across all packages. For example, `npm` offers `npm run --workspaces format` to do this.