20

I'm trying to map paths in tsconfig.json to get rid of relative paths hell. My React App is based on Create-React-App. I tried this SO thread and added paths in my tsconfig.json. My tsconfig.json is as

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

when I compile my project in VS Code, it removes the paths entry from tsconfig.json with the following message. Why alias imports are not supported in my react-scripts based React Project?

enter image description here

DevLoverUmar
  • 11,809
  • 11
  • 68
  • 98

6 Answers6

12

Path aliases are no longer supported

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

go to your jsconfig.json file add base URL to be "."

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

then you can directly import stuff from the src directory

import Myfile from "src/myfile.js"
Abraham
  • 12,140
  • 4
  • 56
  • 92
  • 2
    Where does the information come from that Path aliases are no longer supported? I have not found anything spontaneously. – Florian Falk Sep 02 '21 at 14:15
  • On React start up. `- compilerOptions.paths must not be set (aliased imports are not supported)` But there is a [workaround](https://stackoverflow.com/a/69347253/11127541) – Omar Omeiri Sep 27 '21 at 14:53
  • Welp: `Error: Your project's 'baseUrl' can only be set to 'src' or 'node_modules'. Create React App does not support other values at this time.` – Yechiam Weiss Oct 25 '21 at 13:42
  • 1
    For some reason this is the only way to make it work, my guts feeling is that react-script has different versions. – windmaomao Mar 06 '23 at 16:53
6

I made to Angelo P's answer work by changing the config-overrides.js to

const path = require('path');

module.exports = function override(config, env) {
  config.resolve = {
    ...config.resolve,
    alias: {
      ...config.resolve.alias,
      "@src": path.resolve(__dirname, 'src/'),
      "@api": path.resolve(__dirname, "src/API/"),
      "@assets": path.resolve(__dirname, "src/assets/"),
      "@components": path.resolve(__dirname, "src/components/"),
      "@containers": path.resolve(__dirname, "src/containers/"),
      "@css": path.resolve(__dirname, "src/css/"),
      "@customHooks": path.resolve(__dirname, "src/CustomHooks/"),
      "@helperFuncs": path.resolve(__dirname, "src/HelperFuncs/"),
      "@hoc": path.resolve(__dirname, "src/hoc/"),
      "@middlewares": path.resolve(__dirname, "src/middlewares/"),
      "@models": path.resolve(__dirname, "src/models/"),
      "@store": path.resolve(__dirname, "src/store/"),
      "@actions": path.resolve(__dirname, "src/store/actions"),
      "@reducers": path.resolve(__dirname, "src/store/reducers/"),
      "@sagas": path.resolve(__dirname, "src/store/sagas/"),
      "@typings": path.resolve(__dirname, "src/Typings/"),
      "@utils": path.resolve(__dirname, "src/utils/")
    },
    extensions: ['.ts', '.tsx', '.js', '.jsx', '.json', '.d.ts']
  };
  return config;
};

Works like a charm, but the only thing missing is VSCode autocompletion. React starts up with this warning:

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

So I'm assuming it removes the path field from the tsconfig.json and VSCode cannot pick up the aliases, so ESLint and TS give the following errors in VSCode, but everything works fine.

Unable to resolve path to module '@typings/...'.eslintimport/no-unresolved

Cannot find module '@typings/...' or its corresponding type declarations.ts(2307)

Anyone has a solution for this?

UPDATE

Managed to get it all working by making these changes:

tsconfig.paths.json

{
  "compilerOptions": {
    "paths": {
      "@src/*": ["./src/*"],
      "@api/*": ["./src/API/*"],
      "@assets/*": ["./src/assets/*"],
      "@components/*": ["./src/components/*"],
      "@containers/*": ["./src/containers/*"],
      "@css/*": ["./src/css/*"],
      "@customHooks/*": ["./src/CustomHooks/*"],
      "@helperFuncs/*": ["./src/HelperFuncs/*"],
      "@hoc/*": ["./src/hoc/*"],
      "@middlewares/*": ["./src/middlewares/*"],
      "@models/*": ["./src/models/*"],
      "@store/*": ["./src/store/*"],
      "@actions/*": ["./src/store/actions*"],
      "@reducers/*": ["./src/store/reducers/*"],
      "@sagas/*": ["./src/store/sagas/*"],
      "@typings/*": ["./src/Typings/*"],
      "@utils/*": ["./src/utils/*"]
    }
  }
}

Note the * at the end of @.../*

tsconfig.json

{
  "extends": "./tsconfig.paths.json",
  "compilerOptions": {
    "target": "es6",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext",
      "es2015.promise"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "plugins": [
      {
        "name": "typescript-plugin-css-modules"
      }
    ],
    "resolveJsonModule": true,
    "baseUrl": ".",
  },
  "include": [
    "src",
    "src/**/*.ts"
  ]
}

npm i -D eslint-plugin-import @typescript-eslint/parser eslint-import-resolver-typescript

.eslintrc.json

{
    ...,
    "settings": {
      "import/resolver": {
        "node": {
          "extensions": [".js", ".jsx", ".ts", ".tsx", ".d.ts"]
        },
        "typescript": {}
      }
    }
}
Omar Omeiri
  • 1,506
  • 1
  • 17
  • 33
4

In the end, i figured out this is not the issue of tsconfig. Instead different build system reads this file and operate a bit differently. For instance, a NextJS build does most of the stuff according to the doc, but a Create React App build actually does not follow this exactly. For instance, I can only make the following work.

  import Avatar from 'src/components/Avatar'
{
  "compilerOptions": {
    "baseUrl": ".",

But nothing else with react-scripts. I hope this helps a bit in this crazy world.

windmaomao
  • 7,120
  • 2
  • 32
  • 36
3

You have to add "baseUrl": ".", to you compiler options and than you can use the import src/your/path directly.

morpet
  • 106
  • 1
  • 5
3

you've probably already figured this one out but here's a solution while we wait for a pull request that adds this to tsconfig Currently having the same issue with create-react-app react v 17.0.2,

I've had a similar issue with gatsby applications where you're not able to just set up alias imports without changing the web pack config

this thread has a good explanation on alias imports within cra without typescript, but it should lead to the same configuration at the end of the day.

you'd have to either eject(don't do this unless you have other issues you need to solve inside of your webpack config.) or use another package like CRACO or React-App-Rewired to configure your aliases through webpack.

This Stackoverflow answer is most likely what you're looking for.

install react-app-rewired then create config-overrides.js and place this code in there ->

//config-overrides.js
const { alias, configPaths } = require('react-app-rewire-alias');

module.exports = function override(config) {
  return alias(configPaths('./tsconfig.paths.json'))(config);
};

create your paths object inside of tsconfig.paths.json

//tsconfig.paths.json
{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@components": ["components"],
      "@styles": ["styles"],
      "@config": ["config"]
    }
  }
}

then extend these options inside of tsconfig (not inside compilerOptions)

//tsconfig.js

 "extends": "./tsconfig.paths.json"

finally, replace each react-scripts script in your package.json with react-app-rewired

//package.json
"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-app-rewired eject"
},

You should be all set to go after this. Hoping this helps anyone else who runs into this problem with create-react-app.

Enzo
  • 5
  • 1
  • 3
Angelo P
  • 39
  • 2
  • Funnily enough, after testing this for a while and finally posting this it broke for me, so if anyone tries this out please do let me know if it works for them. – Angelo P Jul 11 '21 at 00:51
  • Hey! this did work for me! But I had to change the config-overrides.js. Checkout my [answer](https://stackoverflow.com/a/69347253/11127541). – Omar Omeiri Sep 27 '21 at 13:13
  • Oh sick, Thanks a ton – Angelo P Sep 27 '21 at 21:12
3

You don't need craco for fixing the problem like that anymore. I've solved this issue by moving the baseUrl to the main tsconfig.json file like below:

tsconfig:

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

tsconfig.path.json:

{
    "compilerOptions": {
        "paths": {
            "api/*": ["api/*"],
            "assets/*": ["assets/*"],
            "config/*": ["config/*"],
            "components/*": ["components/*"],
            "hooks/*": ["hooks/*"],
            "pages/*": ["pages/*"],
            "store/*": ["store/*"],
            "constant/*": ["constant/*"],
            "types/*": ["types/*"],
            "utils/*": ["utils/*"]
        }
    }
}


Jamal
  • 811
  • 5
  • 15
  • This is the best solution. Works with react-scripts 5.0 and does not require any additional plugins (craco, react-app-rewired etc). Thank you! – bbb Apr 15 '22 at 11:38
  • 2
    This does not actually work... it still strips out the `paths`... Here is what it prints out as it gets build... "The following changes are being made to your tsconfig.json file: - compilerOptions.paths must not be set (aliased imports are not supported)" – codenamezero Jun 01 '22 at 14:09
  • @codenamezero, please check the order and exact paths, for example, start the wildcard on the end of the path. – Jamal Jul 24 '23 at 11:22