Absolute paths in React using craco (feat. TypeScript and ts-jest)
Tags: createreactapp, craco, typescript, jest
Published: 2021-12-16 15:20:42

Even though many helper extensions exist out there on VSCode to address the "dot-dot-slash recursive hell", the relational paths are painful to write if you have a folder structure with multiple layers. You may see some projects that are using absolute paths, and it looks cool right? So, why not? Let's use it. 😄
I ended up spending a lot of time configuring absolute paths for Jest (webpack part was rather easy), so I'd like to share how I made it work.

> Before we start, "/" really matters when setting paths, TypeScript compiler will viciously throw errors on your face so if yours complains, see if there are any mistakes made on the forward slash or try to give some tweaks with "/" and "."

Suppose you have React app installed on your local machine using,

`npx create-react-app myApp --template typescript`


#### Step 1. Create a file `tsconfig.path.json` in your root folder for your TypeScript compiler
let TS know what @page, @components, ... means (of course you can use other than @, it's up to you 🙂)
```json
// tsconfig.path.json (in root)
{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@pages": ["pages"], // this doesn't work for @pages/smth
      "@pages/*": ["pages/*"],
      "@components": ["components"],
      "@components/*": ["components/*"],
      ...
    }
}
```
If you don't use Jest, putting just `"@*": ["*"]` in `"paths"` is going to work, but I prefer not to use it because of readability.

#### Step2. Add the path of `tsconfig.path.json` in `tsconfig.json` as `"extends"`

```json
// tsconfig.json
{
  "extends": "./tsconfig.path.json",
  "compilerOptions": {
    ...
  }
}
```
Now your TS compiler knows what `@path` means.
> You can write all what's in `tsconfig.path.json` in `tsconfig.json`, but I prefer to separate it because the part is used for a different(or unique per se) functionality.

### Step3. Install `craco` and `ts-jest`
```
# npm
$ npm install @craco/craco
$ npm install --dev ts-jest

# yarn
$ yarn add @craco/craco
$ yarn add --dev ts-jest
```

#### Step4. Create `craco.config.js` in your root folder and configure it for your bundler and testing library to know what `@paths` means
```javascript
// craco.config.js (in root)
const path = require('path');
const { pathsToModuleNameMapper } = require('ts-jest');
const { compilerOptions } = require('./tsconfig.path.json');

module.exports = {
  webpack: {
    alias: {
      '@components': path.resolve(__dirname, 'src/components'),
      '@pages': path.resolve(__dirname, 'src/pages'),
      ...
    }
  },
  jest: {
    configure: {
      preset: 'ts-jest',
      moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {
        prefix: '<rootDir>/src/',
      }),
    },
  },
};
```
There are other ways around to declare `moduleNameMapper` in `jest.configure`. You can find it by following the `ts-jest` link below.

#### Step5. Add the path of `craco.config.js` in `package.json` to let your app know where to find craco configurations
```json
{
   ...,
   "cracoConfig": "craco.config.js"
}
```

#### Step6. Lastly, change your `react-scripts` command to `craco` in `package.json`
```json
{
 ...
 "scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test",
    "eject": "react-scripts eject",
    ...
 }
}
```

It's DONE! 🙌

Please comment down below if anything is mispresented. 
I hope you find it helpful. ☕️  Happy Coding!

[CRACO - NPM page](https://www.npmjs.com/package/@craco/craco#setting-a-custom-location-for-cracoconfigjs)
[ts-jest Documentation - Paths mapping](https://kulshekhar.github.io/ts-jest/docs/getting-started/paths-mapping)

Cover Photo by <a href="https://unsplash.com/@jack_1?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Rémi Jacquaint</a> on <a href="https://unsplash.com/s/photos/path?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>