path alias react typescript
| |

How to Configure a Path Alias in a React Typescript App for cleaner imports

Introduction

As your Typescript React project grows with everything neatly separated in their own folder, the importing processes starts to become messy. This is specially true if we are following a project structure like react-bulletproof.

Problem

Your project strucure may look like this:

and for us to import Button.tsx in TodoItem.tsx, our import statement will look something like this:

import React from 'react';
import { Button } from '../../../components/elements/Button';

export const TodoItem = () => {
  return <div></div>;
};

our issue here is that we are doing way too many ../../../ statements in the path, and this can get longer if we are importing from a deeper sturcture level. This is specially frustrating as we won’t always import from the same level, causing us to try to figure out where we are to reach that other path. It’s true that intellisense in VS Code will let us know at which folder we are as we are importing, but there is a better approach to this.

Solution

Setting a Path Alias will help us have a more definite and clearer way to import in react:

import React from 'react';
import { Button } from '@/components/elements/Button';

export const TodoItem = () => {
  return <div></div>;
};

The beauty of this is that regardless of at which depth level we are at, the import statement will always be the same.

What is a Path Alias?

A path alias in typescript allows us to define a word or a path to represent an absolute path in the project.

so, in our case, we want to represent ./src with the alias @/.

Configuring an Alias

to configure an alias, we firstly need a new file at our project’s root (not inside ./src).

we will call it tsconfig.paths.json , and add the following configuration to it:

{
    "compilerOptions": {
        "baseUrl": ".",
        "paths": {
            "@/*": [
                "./src/*"
            ]
        }
    }
}

to be able to use this configuation in our project, we will extend it in our tsconfig.json file, which is also located at our project’s root.

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ],
  "extends": "./tsconfig.paths.json" // 👈 add this line
}

Why are we not putting this configuation in tsconfig.json right away instead?

this is because on startup, react (and later, craco) cleans up tsconfig.json to only keep the configuration that it expects to be there for it to work properly. paths property is one of those that it removes when it starts up.

creating tsconfig.paths.json and extending it in tsconfig.json will help us work around that issue.

Testing the Path Alias

You can immediately notice that intellisense will resolve the path alias we defined, and our imports seemingly work.

path alias resolved

However, the moment we use the component,

import React from 'react';
import { Button } from '@/components/elements/Button';

export const TodoItem = () => {
  return (
    <div>
      <Button onClick={() => {}} label='Click Me' />
    </div>
  );
};

this error will come up:

so what is going on here?

We need to do an additional configuration for CRA (Create React App).

Using Storybook? then you very likely will face a similar issue to this one, and you can find the solution in “How to resolve a path alias in Storybook”

Resolving the Alias in CRA (Create React App)

Under the hood, CRA is using webpack. Among many other things, it is using it to resolve imports.

What we need to do is to modify that webpack configuration for it to resolve the alias we just defined in our tsconfig.json.

There are multiple ways to achieve that, but the most convenient way, and the way I recommend will be CRACO.

CRACO

CRACO is a package that helps us override CRA’s configurations without the need to eject.

Install CRACO

yarn add @craco/craco

Override the Webpack Configuration

Create craco.config.js at your project’s root. (not inside src/)

and put in the following configuration:

const path = require('path');
module.exports = {
  webpack: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
};

Change the react scripts to CRACO

in package.json , change from react-scripts to craco to each of start, build, test and eject.

"scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test",
    "eject": "craco eject"
 }

this means that we will need to restart our react app if it was already running, as we won’t be using react-scripts to start it up anymore.

Start React App with CRACO’s start script

It’ll be just like how we always started our react app.

yarn start

and this time, our react app will not be throwing any errors for not being able to resolve our path alias!

Conclusion

Path aliases are a very good way to have more consistent import statements across our typescript projects. We can have more

Sing up to get an email notification when new content is published

Subscription Form

10 Comments

  1. I spent a whole day trying to solve the CRA issue, nothing pointed to the right direction until I found your post.

    Really thanks

Leave a Reply

Your email address will not be published. Required fields are marked *

Similar Posts