S. Hesam
S. Hesam

Reputation: 6603

Aliased imports are not supported anymore when creating a new typescript react app

I created a new React-typescript app via this command with [email protected] and [email protected]:

npx create-react-app my-app --template typescript

Then I decided to define the alias path as I did many times before. I created the tsconfig.paths.json in the root of my app.

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

Then I added the extend property to the tsconfig.json file:

{
  "extends": "./tsconfig.paths.json",
  "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"
  ]
}

Also, I installed [email protected] and created the config-override.js:

const path = require('path');

module.exports = function override(config) {
    config.resolve = {
        ...config.resolve,
        alias: {
            ...config.alias,
            'components': path.resolve(__dirname, 'src/components/*'),
            'routes': path.resolve(__dirname, 'src/routes/*'),
            'constants': path.resolve(__dirname, 'src/constants/*'),
        }
    }
    return config;
}

So I reopened my IDE (VSCode) and ran npm start. I must mention I changed scripts in the package.json before running the start command.

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

After running the start command, this message was displayed in a terminal, and compiling failed:

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

*Failed to compile.

./src/App.tsx Module not found: Can't resolve 'components' in .......*

So I started to search about this issue to resolve it. I found many approaches, that I will mention some of them below:

1. Go to your jsconfig.json file and add the base URL to be "."

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

Then you can directly import stuff from the src directory

import Myfile from "src/myfile.js"

Result ==> DID NOT WORK!

2. This problem is solved by an alias for rewiring. Install react-app-rewire-alias then create config-override.js file:

     const {alias, configPaths} = require('react-app-rewire-alias')

     module.exports = function override(config) {
      alias(configPaths())(config)
      return config
     }

Result ==> DID NOT WORK!

3. Using [email protected] package

  1. Install craco and craco-alias npm install @craco/craco --save and npm i -D craco-alias

  2. Create tsconfig.paths.json in the root directory

    {
        "compilerOptions": {
            "baseUrl": "./src",
            "paths": {
               "@components/*" : ["./components/*"]
             }
        }
    }
    
  3. Extend tsconfig.paths.json in tsconfig.json

    { "extends": "./tsconfig.paths.json", //default configs... }

  4. Create craco.config.js in the root directory

    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.paths.json"
            }
         }
      ]
    };
    
  5. in package.json swap "start": "react-scripts start" with "start": "craco start"

Result ==> DID NOT WORK!

I'm confused because I had used the alias path many times before, but it does not work now. I don't want to eject my app but using the alias path is helpful.

Upvotes: 8

Views: 11027

Answers (3)

dave.tdv
dave.tdv

Reputation: 395

Assuming your React app was created using create-react-app and TypeScript template, I confirm the following steps working as expected with minimum configuration.

  1. Install dependencies for configuration override

    Using npm

    npm install -D @craco/craco craco-alias
    

    Using yarn

    yarn add -D @craco/craco craco-alias
    

    package.json

    It should look similar to this

    { 
      // ... 
      "devDependencies": {
        "@craco/craco": "7.1.0",
        "craco-alias": "3.0.1"
      }
    }
    
  2. Create craco.config.js at the root level of the project, the same level as tsconfig.json

    const cracoAlias = require("craco-alias");
    
    module.exports = {
      plugins: [
        {
          plugin: cracoAlias,
          options: {
            baseUrl: ".",
            source: "tsconfig",
            tsConfigPath: "./tsconfig.json",
          },
        },
      ],
    };
    

    Note

    The baseUrl in the craco.config.js should match with the baseUrl in the tsconfig.json

  3. Create path alias in tsconfig.json

    Below is the typical tsconfig.json auto-generated by CRA. Then, add paths property inside compilerOptions.

    {
      "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",
        "baseUrl": ".",
        "paths": {
          "@/*": ["src/*"]
        }
      },
      "include": ["src"]
    }   
    

    @/*: ["src/*"] means it will replace path prefix @/ with src/.

    Assuming you have a component named MyComponent that is exported using named export from ./src/components/my-component.tsx, you can import the component using import alias as

    import { MyComponent } from "@/components/my-component";
    

    which will be converted into

    import { MyComponent } from "./src/components/my-component";
    

    behind the scene. You can also create new aliases by adding extra properties in the paths object of tsconfig.json

  4. Next, replace react-scripts with craco in the scripts of package.json

    {
      "name": "my-app",
      // ...
      "scripts": {
        "start": "craco start",
        "build": "craco build",
        "test": "craco test"
      }
      // ...
    }
    
  5. Finally, test the import alias

    Using npm

    npm run start
    

    Using yarn

    yarn start
    

Upvotes: 1

Abraham
Abraham

Reputation: 15630

Here is a work around

Path alias are no longer supported.

But to avoid annoying import paths like ../../../ you can directly import files relative to the src directory

You can do the following

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

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

Then you can directly import stuff relative to the src directory

import utility from "src/Myfile.js"

Upvotes: 4

Tomas Hornak
Tomas Hornak

Reputation: 104

I was able to make it work all together (typescript + eslint) in Typescript CRA created just few days ago. This is how I did it:

Selected deps from package.json:

# react: 17.0.2
# eslint: 8.6.0
# react-scripts: 5.0.0
# eslint-import-resolver-babel-module 5.3.1

Install module resolver

yarn add eslint-import-resolver-babel-module --dev

Configuration

tsconfig

I don't have any tsconfig.paths.json

// tsconfig.json
{
  "compilerOptions": {
    //...youCompilerOptions
    "baseUrl": "src"
  },
  "include": ["src"]
}

webpack

Create new file or add to existing webpack.config.js

// webpack.config.js
module.exports = {
  resolve: {
    extensions: ["ts", "tsx", "js", "jsx"],
    alias: {
      components: path.resolve(__dirname, "src/components"),
    },
  },
};

eslint

Finally .eslintrc.json

// .eslintrc.json
{
  // ...yourConfig
  "settings": {
    "import/resolver": {
      "node": {
        "paths": ["src"],
        "moduleDirectory": ["node_modules", "src"],
        "alias": {
          "components": "./src/components"
        }
      }
    }
  },
}

Upvotes: 4

Related Questions