Automatically sort import statements with Prettier

Go from this

import type ComponentInterface from "./interface";
import { UIContext } from "context/ui";
import classes from "utils/classes";
import Image from "components/partials/Image";
import withPrepare from "utils/create-full-page-data/with-prepare";
import styles from "./styles.module.scss";
import PageTitle from "components/partials/PageTitle";
import getLocalizedValue from "utils/get-localized-value";
import type { PreparedComponentInterface } from "./interface";
import RichContent from "components/modules/RichContent";
import { useContext } from "react";
import BackLink from "components/partials/BackLink";

to this

import { useContext } from "react";

import type ComponentInterface from "./interface";
import type { PreparedComponentInterface } from "./interface";

import { UIContext } from "context/ui";

import classes from "utils/classes";
import withPrepare from "utils/create-full-page-data/with-prepare";
import getLocalizedValue from "utils/get-localized-value";

import RichContent from "components/modules/RichContent";
import BackLink from "components/partials/BackLink";
import Image from "components/partials/Image";
import PageTitle from "components/partials/PageTitle";

import styles from "./styles.module.scss";

all automatically!

👇 Go directly to the implementation

Introduction

For years, smart systems like Intellisense have helped developers to work more efficiently. A few years ago, Prettier came along and reduced the amount of bikeshedding by automating the formatting of code. And we love it!

At GRRR we try to do even more by automating repetitive tasks whenever it’s possible. Examples are:

  • Use Terraform to setup servers, hosting, etc instead of having to manually click through an interface
  • Use a script to automatically generate components. It creates files in the correct location with the correct filenames and some useful boilerplate code
  • Use GitHub workflows for continuous integration and every deployment. A blog post about that.

But one thing has bugged us for the past 2 years: the sorting of imports. While Prettier formats all of the if-statements, functions, indentation, etc, the imports stay just where they are.

The solution

Luckily, Ayush Sharma and Behrang Yarahmadi have made a plugin for Prettier that allows it to sort the import statements as well. Thanks for all the work!

This means the imports are grouped and alphabetically sorted. And that reduces noise in Pull Requests and creates a consistent and clear overview of the imports.

While we (GRRR) choose to accept all the default formatting options of Prettier to reduce the bikeshedding even more, this plugin needs some project-specific input. Therefore you will see our preferences in the examples below. You can change this to your own needs.

Step 1 - Add the plugin

With yarn

yarn add --dev @trivago/prettier-plugin-sort-imports

or when you use npm

npm install --save-dev @trivago/prettier-plugin-sort-imports

Step 2 - Add the settings in .prettierrc

Open .prettierrc, ours looks like this:

{}

Add a list of the types of imports that you have. To give you an example, we have the following types in our Next.js project that uses TypeScript:

  • Third-party modules
  • Interfaces (global interfaces)
  • API files (for all the connections from the applications to the CMS)
  • Context
  • Mocks (we have a setup where we can run the Next.js app without the CMS)
  • Config
  • Utils
  • Hooks (Custom React hooks)
  • Components
  • SVGs (for icons)
  • Others
  • Scoped CSS

The .prettierrc file looks like this:

{
    "importOrder": [
        "<THIRD_PARTY_MODULES>",
        "interface",
        "(?=content|api)",
        "context/",
        "mock/",
        "config",
        "utils/",
        "hooks/",
        "(components/|./index)",
        ".svg",
        "^../(.*)$",
        "(?=./styles.module.scss)"
    ]
}

Each type of import is a separate item in the importOrder array. They are regular expressions, apart from the <THIRD_PARTY_MODULES>, that’s added by the plugin. A group is created for each import type and the imports are sorted alphabetically within that group.

Your project might use different names and patterns. Therefore it’s needed that you tweak this file for your project needs.

We also like an empty line between each group of imports. You can enable this by adding the following option to the .prettierrc:

"importOrderSeparation": true

Step 3 - Update your imports from dynamic to static, for even better results

Each item in the importOrder array is a regex statement. Therefore you can go quite far with the logic behind this or keep it simple (like we did).

It does help if the paths of your import statements are static instead of dynamic.

  • Dynamic: ../../components/modules/Image
  • Static: components/modules/Image

But why?

If a module imports another module called Image. Your import will be: ../Image. The Import-sorting logic has no idea that this is a module as it’s not present in the import path. A static import path would help with this (components/modules/Image)

There is one big downside. Changing the import paths from dynamic to static isn’t an automated task. So you need to do this by hand. We use the Boy-scout rule for this change: change the import paths for every file that you touch.

To enable your code editor to create absolute imports by default, add a base-URL to your tsconfig.json file (this is in case you have a Next.js project with TypeScript setup).

// tsconfig.json
{
    "compilerOptions": {
        "baseUrl": "."
        // Your other options
    }
}

Step 4 - Testing your import order

To ensure you have the correct settings for your import order, I would recommend using a few different files (modules, utils, etc.) that contain a lot of imports. In total, you should have at least 1 file for each item in the importOrder array.

Then you can format these files with the new settings without formatting your entire project. You can use the following command to format all the files in the current directory.

npx prettier --write .

Step 5 - Format all the files (optional)

There are 2 ways of tackling the new format defaults.

  1. Format all the files within 1 big-bang
  2. Format each file that you touch

We used option 1 so other commits aren’t clouded by a change to another import order. This choice depends heavily on your project and organization.

Conclusion

It’s now possible to also sort the order of your imports automatically with a Prettier extension. You need to configure the different types of import to your .prettierrc and optionally enable the option to create newlines between each import group. Absolute imports help to make the sorting even better.

I hope this helps your team to also automate this part of their workflow.