Have you ever found yourself typing so many ../../../ in typescript files? The deeper your project is the more typing is required to access modules in higher layers.
Paths Aliases to the rescue! They make the code look much cleaner. We can go from ugly to fancy paths/imports like so by declaring aliases that map to a certain absolute path in your application.
// Ugly path 😭
import { Button } from './../../../components/Button.tsx';
// Fancy path 🤩
import { Button } from '@components/Button.tsx';
Setup
Imagine we have the following project structure:
src
├── rest
│ ├── complex-components
│ │ └── auth
│ │ └── UserAuth.tsx
│ └── components
│ ├── Button.tsx
│ └── User.tsx
├── services
│ └── user-data-service.ts
└── setupTests.js
Step 1: Install TS
Let's first install typescript in our project as a root dependency.
yarn add -D typescript
Step 2: Configure Path Mappings
Next step is to create or update the tsconfig.json
file with the path mapping. The TypeScript compiler supports the declaration of path mappings using paths property in tsconfig.json
files.
{
"compilerOptions": {
"baseUrl": ".", // This must be specified if "paths" is.
"paths": {
"@...": ["..."] // This mapping is relative to "baseUrl"
}
}
}
☝️ Please notice that paths are resolved relative to baseUrl. When setting baseUrl to a value other than ".", i.e. the directory of
tsconfig.json
, the mappings must be changed accordingly.
We are going to build our paths in a new file tsconfig.extend.json
to make them more readable when importing and extend it from the tsconfig.json
file. So,
Create the
tsconfig.extend.json
file at your project’s root.Establish our baseUrl to be used as a reference.
{
"compilerOptions": {
"baseUrl": "./src"
}
}
- Define your paths mapping. We want typescript to import all files located in paths-to-search-for as @new-path-alias.
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@new-path-alias": ["paths-to-search-for"]
}
}
}
Like so:
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"@components/*": [
"./rest/components/*"
],
"@complex-components/*": [
"./rest/complex-components/*"
],
"@services/*": [
"./services/*"
]
}
}
}
- Extend the
tsconfig.extend.json
file from thetsconfig.json
file:
{
"compilerOptions": {
...
},
"extends": "./tsconfig.extend.json",
"exclude": ["node_modules", "**/*.test.*", "build/**/*"]
}
,
Now, you can use the new path aliases for module imports in your application. Let's run our code! 🎉
As soon as we run the code we get an error. What is going on here...? 🤔
Error: Can't resolve import '@complex-components/auth/UserAuth'
A project created with create-react-app
includes, in addition to React, other libraries like:
- Webpack which is in charge of processing and packaging our JavaScript code (with its dependencies), CSS files and other static files such as images and fonts.
- Babel which allows us to use new features of ECMAScript and JSX (JavaScript XML).
- PostCSS which is a library for CSS processing.
- Jest which is a library for testing.
Webpack it's also used to resolve imports so 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, like:
- Running
npm run eject
command: it's used to release all the tools behind Create React App, so that we can customize how it works. All the libraries mentioned remain hidden and cannot be customized. If your project needs a more specific configuration of any of these tools, you can launch the "eject" command, which brings all the hidden Create React App configuration out. Just keep in mind that the "eject" action cannot be undone! - Overriding Create React App configuration with CRACO. This is the most convenient way because we can override
create-react-app
configurations without the need to eject.
Step 3: Resolving alias with CRACO
First, we need to install CRACO
npm install --save @craco/craco
&&
npm install --save-dev craco-alias
Then, create craco.config.js
file at your project’s root (not inside src/) with the following configuration
const CracoAlias = require("craco-alias");
module.exports = {
plugins: [
{
plugin: CracoAlias,
options: {
source: "tsconfig",
// baseUrl SHOULD be specified
// plugin does not take it from tsconfig
baseUrl: "./src",
// tsConfigPath should point to the file where "baseUrl" and "paths" are specified
tsConfigPath: "./tsconfig.extend.json"
}
}
]
};
The last thing is that we won’t be using react-scripts to start up our app anymore. We have to switch from react-scripts to craco to each of start, build, test and eject in package.json
file.
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "craco eject"
}
Start React App with CRACO
Let's run our app
yarn start
This time, our react app will not be throwing any errors for not being able to resolve our path alias!
Top comments (0)