4

i'm using create-react-app + typescript, and i want to add absolute paths.

i'm trying to get to the point i can use absolute paths, like so:

instead of import x from '../../../components/shell/shell'

use import x from '@components/shell/shell';

here is tsconfig.json file:

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

I'm using extended file for paths, because from some reason npm start overrides the file. so is paths.json file:

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

i also have an .env file:

NODE_PATH=src

i installed react-app-rewire so i can config the paths, and my config-ovverrides.js file looks like this:

module.exports = {
  paths: function(paths, env) {
    // ...add your paths config
    return paths;
  }
};

im stuck with connecting all the dots, it doesn't work and i still cant see what i need to do in order to config the webpack path object;

how can i implement paths in cra, ts, and rewire?

Tamiross
  • 99
  • 2
  • 10

3 Answers3

4

You can solve it using 5 simple steps withou eject:

Step 1: Adding react-app-rewired into your devDependencies.

yarn add -D react-app-rewired or npm intall react-app-rewired --save-dev

Step 2: After installation, you'll be able to change package.json default ReactsJS scripts to:

"scripts": {  
  "start": "react-app-rewired start",  
  "build": "react-app-rewired build",  
  "test": "react-app-rewired test",  
  "eject": "react-app-rewired eject" 
}

Step 3: Creates a new file called tsconfig.paths.json on root path, with content like:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "services/*": ["./src/shared/services/*"],
      "interfaces/*": ["./src/shared/interfaces/*"]
    }
  }
}

Tip 1: you can choose which path you want to use, like: @services, @interface, @src, ~, @, etc just by changing the keys inside "paths": {}

The same is applied to it's value: ["src/shared/services/"], ["src/shared/interfaces/"], ["src/*"], use the relative path here.

Step 4: Into tsconfig.json, before "compilerOptions" you need to extends the tsconfig.paths.json you just created.

Like this:

{
  "extends": "./tsconfig.paths.json",
  ...//rest of file infos compilerOptions, include... whatever
}

Step 5: Creates a new file config-overrides.js, adding your alias and relative paths on it:

const path = require('path');

module.exports = function override(config) {
  config.resolve = {
    ...config.resolve,
    alias: {
      ...config.resolve.alias,
      'services': path.resolve(__dirname, 'src/shared/services'),
      'interfaces': path.resolve(__dirname, 'src/shared/interfaces')
    },
  };

  return config;
};

Tip 2: If you're using eslint, remember to have an .eslintignore file and add config-overrides.js within it.

Restart your IDE or text editor, in my case VSCode.

It's DONE! Now just run yarn start or npm run start

Lajos Mészáros
  • 3,756
  • 2
  • 20
  • 26
2

Do you need to use the @ syntax?

Are you able to use the syntax of:

import x from 'components/shell/shell'

?

If so, then see the documentation for CRA Absolute Imports.

For Typescript, your tsconfig.json becomes:

{
  "compilerOptions": {
    // ... usual options ...
    "baseUrl": "src",
  },
  // ... include, etc...
}

Out of the box, this will allow you to import for src as the base directory.

So your syntax becomes:

import x from 'components/shell/shell';

This would be the least friction option...

However...

If you absolutely need the @ syntax, then to get rewire to work correctly requires a little more jiggery-pokery. The only way that I have found to get rewire to work with that syntax is to include a webpack alias rewrite.

So the process is (please update the paths as required for your application):

  1. Create a tsconfig.paths.jsonnext to your tsconfig.json containing:
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@components": ["src/components/*"],
    }
  }
}
  1. Update your tsconfig.json with an extend:
{
  "compilerOptions": {
    // ... standard options ...
  },
  "include": [
    "src"
  ],
  "extends": "./tsconfig.paths.json"
}

When running the build command (npm run build), the scripts will throw the following error:

The following changes are being made to your tsconfig.json file:
  - compilerOptions.paths must not be set (aliased imports are not supported)

The extend option mitigates against this.

  1. Add a webpack alias to config-overrides.js:
const path = require('path');
const { override, addWebpackAlias } = require('customize-cra');

module.exports = override(
  addWebpackAlias({
    '@components': path.resolve(__dirname, 'src/components'),
  })
);

This example uses the package customize-cra which has a bunch of helpful resolvers for overrides. (If you don't want to use it, then you would need to set the config.resolve.alias property on the config object passed to the override function)

Now assuming you have updated all the scripts to use react-app-rewired, you should be able to use the syntax:

import x from '@components/shell/shell';
user626201
  • 1,623
  • 3
  • 19
  • 36
0

Path aliases are no longer supported

But you can do this now to directly import files relative to the src directory

go to your tsconfig.json file add baseUrl to be "."

"compilerOptions": {
    "baseUrl":".",
    ...

then you can directly import stuff from the src directory

import Myfile from "src/myfile.js"

This worked for me!

Abraham
  • 12,140
  • 4
  • 56
  • 92