Make imports more readable. JS/TS and ESLint solutions.
Tags: javascript, typescript, tooling, tutorial
Published: 2023-05-11 20:49:06

## Introduction
Many challenges are encountered as a product scales. One of the most important is to ensure code maintainability. The depth of imports increases as the codebase grows. They becoming to look really messy. 

Sometimes your imports become looks like this, especially in complex projects. Just look at those imports, it’s really difficult to understand.


![A lot of slashes and periods "../../../../how/deep/are/those/omg"](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/il0pqpt3o5lols9cgj0j.png)
<figcaption>A lot of slashes and periods "../../../../how/deep/are/those/omg"
</figcaption>
---


> In this article, I will not touch architecture and dependency injection, but will simply talk about how imports can be made more readable.

In a Unix-style file system, a period "." refers to the current directory, a double period ".." refers to the directory up a level. By default, if we need to import something from up level directory we need to write it as relative path. Like, from current directory we need to jump to 3 levels up and find here specific file: "../../../service/{filename}".

**But what if I say, that we can actually write imports as non-relative paths like "app/service/{filename}".**

---

## First solution – Path mapping via JS/TS compilers


My friend notices the same problem with messy imports and remembered “aliases for imports”, but he got some difficulties.


![Chat with my friend about messy imports problem](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xh3sl68c7mv8j4w6pwph.png)
<figcaption>Screenshot of chat with my friend about messy imports problem</figcaption>
---

So let’s try to beautify our imports with first solution.

JavaScript and TypeScript compilers resolving our relative imports, but we can change configuration to make it resolve non-relative imports too. So we just need to add «baseUrl» and «paths» directives in jsconfig.json or tsconfig.json file.

Setting **«baseUrl»** informs the compiler where to find modules. All module imports with non-relative names are assumed to be relative to the «baseUrl». 

And via **«paths»** we setting up compiler to use a mapping configuration to map module names to files at run-time.

Imagine we have file structure like this, so we can apply config like this:

![Example of file structure and equal configuration below
](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a7y1vx9d4e4vevmnfvwl.png)
<figcaption>Example of file structure and equal configuration below</figcaption>
---


So we can apply config like this:
```json
{
   "compilerOptions": {
      "baseUrl": ".",
      "paths": {
         "@features*": [
            "./features/*"
         ],
         "@core*": [
            "./core/*"
         ],
         "@auth*": [
            "./auth/*"
         ],
         "@store*": [
            "./store/*"
         ],
      },
   }
}
```

**Please notice that «paths» are resolved relative to «baseUrl».**

This configuration will give us readable imports like this. We got rid of periods and slashes.


![Nice imports with non-relative paths by manual config for JS/TS compilers](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t0czx2x0fq14q0i0yn5e.png)
<figcaption>Nice imports with non-relative paths by manual config for JS/TS compilers</figcaption>
---

If you noticed, we still can use relative paths as well as non-relative. My personal preference is to use non-relative paths for deep imports to another logic parts of project, and use relative paths for 1–2 level imports within a current logical part.

Looking good! But we have to manually configurate it. 

And next solution will work automatically. So comment your «paths» directive and move forward!

---

## Second solution – ESLint import resolver

ESLint is super powerful tool! And it's also has plugin for linting import/export syntax. And there is also imports resolver than can help us with to upgrade our imports.

We need to install eslint and import plugin:
```sh
yarn add --dev eslint eslint-plugin-import
```

And add this configuration in ESLint config file:
```json
{
  "settings": {
      "import/resolver": {
         "typescript": {
            "project": "./tsconfig.json"
         },
         "node": {
            "paths": [ "." ]
         }
      }
   }
}
```

And that's all!

After this we getting automatically resolved non-relative imports!

![Nice non-relative imports resolved by ESLint import plugin](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dtjeq7mshv3kl1kobnch.png)<figcaption>Nice non-relative imports resolved by ESLint import plugin</figcaption>

---

Thanks for reading this article! By following it, you’ll develop more maintalable code with readable imports. I hope it will help you to develop greatest projects!

I’m progressive software engineer with over 5 years of development experience and I love to share it! So follow me and stay tuned!

Incoming topics:
* WebAssembly (Wasm): when and how to use it
* Client API code-gen, from OpenAPI Specs to TypeScript
* Getting frames from video files on frontend

References:
* [ESLint](https://eslint.org/)
* [ESLint import plugin](https://www.npmjs.com/package/eslint-plugin-import)
* [TypeScript module resolution](https://www.typescriptlang.org/docs/handbook/module-resolution.html)
* [TypeScript docs: paths](https://www.typescriptlang.org/tsconfig#paths)