The end of annoying JavaScript imports

Posted on (updated Jun 14, 2023)

This week, I want to share a quick JavaScript tooling tip before I put the finishing touches on my business plan. If you ever randomly added or removed ../s from import statements until they worked, this one is for you.

When most websites had very little JavaScript, it was fine to keep it in a single file. With their explosive growth, splitting code up into several smaller files became necessary. Today, we can import code from other files thanks to the import statement.

We usually spread files across many directories to give our projects more structure. We can then import them with relative paths, like so:

import { Header } from "../../components/Header"
import { getAllPosts } from "../../lib/api/posts"
import { Header } from "../../components/Header"
import { getAllPosts } from "../../lib/api/posts"

A ../ in a path tells your code to go up a level. By chaining them, we can instruct it to “go this many directories up from here, then down this other path”. This allows us to put code in complex directory structures in a way that makes sense for our projects.

As projects grow, these imports become painful to maintain. It is never very obvious how many ../ we need when referencing another file. Counting directory levels is difficult and annoying. I often kept adding and removing levels until my imports worked.

I came across a configuration file called jsconfig.json in the [Next.js documentation]. The existence of this file declares the directory this file is in the root of a JavaScript project. As one of its features, we can define path aliases in it.

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "~/components/*": ["components/*"],
      "~/lib/*": ["lib/*"]
    }
  }
}
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "~/components/*": ["components/*"],
      "~/lib/*": ["lib/*"]
    }
  }
}

We can then refer to these directories with the ~/ prefix instead of using relative imports:

import { Header } from "~/components/Header"
import { getAllPosts } from "~/lib/api/posts"
import { Header } from "~/components/Header"
import { getAllPosts } from "~/lib/api/posts"

This works in any directory or file you’re in. You could be many layers removed, or even in entirely different parts of your project. We no longer have to count directories and have long repetitions of ../ in our import statements. It instantly cleans up imports like nothing else.

Tools like Next.js and Nuxt.js support this configuration out of the box. VS Code seems to do the same. If you’re chaining ../s until your imports work, check out this configuration. It’s totally my new favorite thing this week.

Debug
none
Grid overlay