DEV Community

Lucas Wolff
Lucas Wolff

Posted on • Originally published at wolff.fun

Path Mapping in TypeScript with Vite

Working with imports in JavaScript applications can be a mess if you have deeply nested folder structures.

This can be even worse if your editor or IDE doesn't have intellisense or if it's not configured properly.

So you end up with some imports like this:

// ❌
import { useForm } from "../../../../hooks/useForm";
import { TextInput } from "../../../form/TextInput";
import { Button } from "../../../ui/Button";
import { loginValidations } from "../../../../utils/validations";
import { routes } from "../../../../config/routes";
Enter fullscreen mode Exit fullscreen mode

This will work but doesn't scale nor is readable to the developer.

TypeScript Path Mapping

When using TypeScript it's very common to use path mapping. This is useful because you can omit the relative paths from the import and then get the module using an absolute import.

// ✅
import { useForm } from "@hooks/useForm";
import { TextInput } from "@components/form/TextInput";
import { Button } from "@components/ui/Button";
import { loginValidations } from "@utils/validations";
import { routes } from "@config/routes";
Enter fullscreen mode Exit fullscreen mode

This can be achieved adding the paths config to your tsconfig.json:

// tsconfig.json

{
  "compilerOptions": {
    "baseUrl": "./src", // This is to avoid adding the ./src prefix to each path below.
    "paths": {
      "@components/*": ["components/*"],
      "@hooks/*": ["hooks/*"],
      "@utils/*": ["utils/*"]
      "@config/*": ["config/*"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

This improves the readability a lot, and also if you move your components or modules to another folder, the chances that you need to update the imports are very low.

Vite + TypeScript Path Mapping

If you try to create paths using Vite you'll notice that it's not possible, since Vite doesn't know how to build the imports by default.

There are two solutions to this issue: adding the paths manually to the Vite build config or using a third-party package.

Adding paths manually

In order to add the paths manually to Vite build you'll need to configure all the aliases in vite.config.ts:

// vite.config.ts

// ...
import path from "path";

export default defineConfig({
  // ...
  resolve: {
    alias: [
      {
        find: "@components",
        replacement: path.resolve(__dirname, "src/components"),
      },
      {
        find: "@utils",
        replacement: path.resolve(__dirname, "src/utils"),
      },
      {
        find: "@hooks",
        replacement: path.resolve(__dirname, "src/hooks"),
      },
      {
        find: "@configs",
        replacement: path.resolve(__dirname, "src/configs"),
      },
    ],
  },
});

// OR EVEN BETTER:

const aliases = ['components', 'utils', 'hooks', 'configs'];

export default defineConfig({
  // ...
  resolve: {
    alias: aliases.map(alias => (
      {
        find: `@${alias}`,
        replacement: path.resolve(__dirname, `src/${alias}`),
      },
    ))
  },
});
Enter fullscreen mode Exit fullscreen mode

The downside of this approach is that every time the paths on tsconfig.json change you'll need to update the vite.config.ts too. This is not an ideal workflow.

Using vite-tsconfig-paths

To solve that you can use a package called vite-tsconfig-paths which does all that boring and repetitive work.

It's very simple to use. All the configuration can be done in 2 steps:

  1. Install it as a dev dependency:
# npm
npm i vite-tsconfig-paths --save-dev

# yarn
yarn add -D vite-tsconfig-paths
Enter fullscreen mode Exit fullscreen mode
  1. Then add it as a Vite plugin:
// vite.config.ts

import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
  plugins: [tsconfigPaths()],
});
Enter fullscreen mode Exit fullscreen mode

And that's it! Every new path added will work without any changes needed.


If you have any feedback or suggestions, send me an email

Great coding!

Top comments (0)