DEV Community

Cover image for How Pros Get Rid of Relative Imports
Tapajyoti Bose
Tapajyoti Bose

Posted on • Updated on

How Pros Get Rid of Relative Imports

If you have worked on a decently sized Node.js application regardless of whether its JavaScript or TypeScript, you will have come across long imports such as these:

import User from "../../../../models/User";
Enter fullscreen mode Exit fullscreen mode

which made you go:

Astounded

Rewriting long imports hundreds of times can get on anyone's nerves. This article with show you how to compress those long imports into compact and short imports. After all:

Shorter Code == Happier Devs πŸ˜‰

Enter jsconfig.json

What is jsconfig.json? you might be asking. Well, jsconfig.json can be thought of as a descendent of tsconfig.json, with the allowJs attribute set to true.

In simple terms, jsconfig.json is a file that specifies that the directory is the root of a JavaScript project. The tsconfig.json & jsconfig.json file specifies the root files and the compiler options required to compile the project.

For more on jsconfig.json, check out this article.

For Demonstration purpose, we would be working on a demo project with the following file structure:

.
β”‚   app.js
β”‚   jsconfig.json
β”‚   package.json
β”‚   
β”œβ”€β”€β”€models
β”‚       user.js
β”‚       
└───utils
    β”œβ”€β”€β”€colors
    β”‚       converter.js
    β”‚       generateColor.js
    β”‚       
    └───datetime
            formatter.js
            timezoneHelpers.js
Enter fullscreen mode Exit fullscreen mode

Base Url

The easiest way to get rid of the long imports is to add baseUrl in the jsconfig.json (add jsconfig.json at the root level of the project in case you don't have it).

{
    "compilerOptions": {
        "baseUrl": "."
    }
}
Enter fullscreen mode Exit fullscreen mode

Viola! Now you can directly access the files and folders at the root level of your project. So to import color related functions in the User model, you can now use:

import { hexToRgb, rgbToHex } from 'utils/colors/converter'
Enter fullscreen mode Exit fullscreen mode

in place of:

import { hexToRgb, rgbToHex } from '../utils/colors/converter'
Enter fullscreen mode Exit fullscreen mode

That's just a minor improvement in this demo, but in case your project has a lot of nested folders, it would lead to significant reductions.

But let's try to do better.

Paths

Paths allow us to aggregate a list directories under a predefined name and drastically reduce the length of the imports.

{
    "compilerOptions": {
        "baseUrl": ".",
        "paths": {
            "@models/*": [
                "./models/*"
            ],
            "@colors/*": [
                "./utils/colors/*"
            ],
            "@datetime/*": [
                "./utils/datetime/*"
            ]
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

We are aggregating all the files in the models folder under the name @models. The same is the case for colors and datetime. We would be able to reference the folders using @models, @colors, and @datetime in the import statement. So,

import { hexToRgb, rgbToHex } from '../utils/colors/converter'
Enter fullscreen mode Exit fullscreen mode

finally reduces to:

import { hexToRgb, rgbToHex } from '@colors/converter'
Enter fullscreen mode Exit fullscreen mode

Somethings worth noting:

  1. The pathname doesn't have to be the same as the actual folder name. But it's a good idea to keep them the same to avoid confusion.
  2. You can aggregate as many folders you want under any pathname. Let's take a look at a bit absurd example:

    "@colors/*": [
        "./utils/colors/*",
        "./utils/datetime/*"
    ]
    

    This would result in both the datetime and colors folders to be aggregated under the name @colors.

TypeScript

Everything we went over can be used with TypeScript as well. Just replace jsconfig.json with tsconfig.json and you are done.

Done

NOTE: As TalOrlanczyk pointed out in the comments, this doesn't work with create-react-app. The work-around is provided in the comments below.

Wrapping up

This article went through how to optimize the annoying long imports into concise small statements. I hope this helps you in your development journey! :)

Thanks for reading

Want to work together? Contact me on Upwork

Want to see what I am working on? Check out my GitHub

I am a freelancer who will start off as a Digital Nomad in mid-2022. Want to catch the journey? Follow me on Instagram

Follow my blogs for weekly new tidbits on Dev

FAQ

These are a few commonly asked questions I get. So, I hope this FAQ section solves your issues.

  1. I am a beginner, how should I learn Front-End Web Dev?
    Look into the following articles:

    1. Front End Development Roadmap
    2. Front End Project Ideas
  2. Would you mentor me?

    Sorry, I am already under a lot of workload and would not have the time to mentor anyone.

  3. Would you like to collaborate on our site?

    As mentioned in the previous question, I am in a time crunch, so I would have to pass on such opportunities.

Connect to me on

Discussion (16)

Collapse
richardeschloss profile image
Richard Schloss • Edited on

subpath patterns can also be used in package.json. I like to think of it as a cool free feature baked right in to nodejs.

For example:

{
  "exports": {
    "./features/*": "./src/features/*.js"
  },
  "imports": {
    "#internal/*": "./src/internal/*.js",
    "#root/*": "./"
  }
}
Enter fullscreen mode Exit fullscreen mode

This way, it's tied to the node project, which will work no matter what the IDE is.

Collapse
ruppysuppy profile image
Tapajyoti Bose Author

Thanks a lot for sharing! I wasn't aware of this feature

Collapse
talorlanczyk profile image
TalOrlanczyk • Edited on

Its great but unfortunately react by itse will ignore paths

Collapse
damiisdandy profile image
damilola jerugba

I read somewhere it only doesn’t work for create-react-app, did you test it on CRA?

Collapse
ruppysuppy profile image
Tapajyoti Bose Author

Since this is quite a useful trick, even though it doesn't work directly, there is a work around for it

Collapse
ruppysuppy profile image
Tapajyoti Bose Author

I think it works with React as well. Tried it in a Next.js project though

Collapse
talorlanczyk profile image
TalOrlanczyk

For react you need third party library

Thread Thread
ruppysuppy profile image
Tapajyoti Bose Author

I tested it right now, it's working with plain old react

Thread Thread
talorlanczyk profile image
TalOrlanczyk • Edited on

weird I copy this exactly and the paths didn't work
the error:Module not found: Can't resolve '@models/tests' in '/Users/talorlanczyk/Projects/react-tests/my-app/src'
I would like you to show me the code on react please

Thread Thread
ruppysuppy profile image
Tapajyoti Bose Author

Add the following in webpack.config.js:

module.exports = {
    // ...
    resolve: {
        alias: {
            // path to your models
            '@models': path.resolve(__dirname, './src/models'),
        },
    }
}
Enter fullscreen mode Exit fullscreen mode

Use yarn eject first if you are using create-react-app

Thread Thread
talorlanczyk profile image
TalOrlanczyk

Thanks,
But when i say you can't meant that you must do an additional step like eject to do this or use third party library
I think add this to your article will great for a lot of developers

Collapse
urafiz profile image
UraFIZ

You are 😎

Collapse
ruppysuppy profile image
Tapajyoti Bose Author

πŸ˜…

Collapse
pinich profile image
Pini Cheyni

I was using it in angular/nestJS project for a while. I had no idea it was such a big deal.
This works very well for shared libraries in a monorepos.

Collapse
ruppysuppy profile image
Tapajyoti Bose Author

Yeah, it helps a lot to ease repeatative directory traversal

Collapse
alfianandinugraha profile image
alfianandinugraha

Absolute path really help me when use typescript. I also make boilerplate for reactjs and typescript with absolute path create-react-typescript-app.vercel...