9

I have a problem on set webpack alias path using create-react-app and craco, already googling it but can't solve the problem.

I got an error Module not found: Can't resolve '@app/App' in 'C:\ReactSandbox\my-project\src everytime i run application using command yarn start

Steps to reproduce:

  1. create-react-app my-project
  2. cd my-project
  3. yarn add @craco/craco
  4. cat > craco.config.js (see configuration below)
  5. replace react-scripts to craco on 'script' section on package.json (craco start, craco build, etc)
  6. edit file src/index.js (replace line 4, see code below)
  7. yarn start

craco.config.js

const path = require("path");

module.exports = {
  webpack: {
    resolve: { 
      alias: {
        "@app": path.resolve(__dirname, "src/"),
      }
    }    
  }
};

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from '@app/App'; //replace './App' into '@app/App'
import * as serviceWorker from './serviceWorker';

ReactDOM.render(<App />, document.getElementById('root'));

serviceWorker.unregister();

Current result

Module not found: Can't resolve '@app/App' in 'C:\ReactSandbox\my-project\src

Expected

I'm avoiding call relative path hell, instead of import module like ../../../../FilterComment.js, it would be clean to write @app/FilterComment.js

vsync
  • 118,978
  • 58
  • 307
  • 400
Yasin Junet
  • 108
  • 1
  • 1
  • 6

8 Answers8

10

resolve for carco:

u need install craco-alias, then will write in craco.config.js

    const CracoAlias = require('craco-alias')

    module.exports = {
      plugins: [
        {
          plugin: CracoAlias,
          options: {
            source: 'tsconfig',
            baseUrl: '.',
            tsConfigPath: './tsconfig.path.json',
          },
        },
      ],
    }

tsconfig.path.json

    {
      "compilerOptions": {
        "baseUrl": ".",
        "paths": {
          "@/*": ["src/*"],
          "@svg/*": ["src/assets/svg/*"],
          "@img/*": ["src/assets/images/*"],
          "@icons/*": ["src/assets/icons/*"],
          "@shared/*": ["src/shared/*"],
          "@components/*": ["src/components/*"],
          "@hooks/*": ["src/hooks/*"],
          "@constants/*": ["src/constants/*"],
          "@layout/*": ["src/layout/*"],
          "@services/*": ["src/services/*"]
        }
      }
    }

tsconfig.json

    {
      "extends": "./tsconfig.path.json",
      "compilerOptions": {
        "target": "es5",
        "lib": [
          "dom",
          "dom.iterable",
          "esnext"
        ],
        "allowJs": true,
        "checkJs": false,
        "skipLibCheck": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "declaration": false,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "module": "esnext",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "jsx": "react-jsx",
        "noFallthroughCasesInSwitch": true,
        "removeComments": true
      },
      "include": [
        "src",
        "src/configs",
        "react-app-env.d.ts"
      ]
    }

Paul Alexeev
  • 172
  • 1
  • 11
6

First - tell to IDE about aliases in tsconfig.json:

create separate file tsconfig.paths.json and add aliases:

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

Add created tsconfig.paths.json to main tsconfig.json

{
   "extends": "./tsconfig.paths.json",
   ... other staff ...
}

Second - tell to webpack about aliases:

Add aliases to config-overrides.js

const {
   override,
   addWebpackAlias
} = require('customize-cra');

const path = require("path");

module.exports = override(
   addWebpackAlias({
      "@utils": path.resolve(__dirname, "./src/utils"),
   }),
);
Yuriy Gyerts
  • 1,464
  • 18
  • 30
4

my craco.config.js look likes below, it works:

const path = require('path');

module.exports = {
    // ...
    webpack: {
        alias: {
            '@': path.join(path.resolve(__dirname, './src')),
        }
    }
}
lmlife
  • 41
  • 5
  • No eject is needed with craco. I use the same `craco.config.js` alias setting but without `path.join` and it works fine – Ahmed Rafik Ibrahim Apr 28 '20 at 11:19
  • Yeah, no need to wrap results of `path.resolve` in `path.join` – Parzh from Ukraine Apr 04 '21 at 21:25
  • how would this work for the case if we have node package with scope.. like `@sentry/react` etc... – Murtaza Hussain Oct 14 '21 at 11:48
  • @MurtazaHussain As per some nodejs docs somewhere, they suggest using `#` instead of `@` which is what I do... it's a bit weird but it works... and node said to do so. I feel like there was a more explicit suggestion for it but [here it is implicitly](https://www.typescriptlang.org/docs/handbook/module-resolution.html). This avoids the clash with `@` – wongz Jun 10 '22 at 03:02
2

Just keep your file craco.config.js just like this, and you need to add 1 more file with named jsconfig.json

it's content:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es2016",
    "jsx": "preserve",
    "checkJs": true,
    "baseUrl": "./src/",
    "paths": {
      "@app/*": ["./*"]
    }
  },
  "exclude": ["node_modules", "**/node_modules/*"]
}

then you can import from the absolute path like @app/FilterComment.js

It also worked for VSCode (editor now understand where @app point to). But if you want VSCode to do the import automatically, then you should add more config for it to force it always do the import from absolute path.

file .vscode/settings.json content:

{
  "javascript.preferences.importModuleSpecifier": "non-relative"
}
Avinash Singh
  • 4,970
  • 8
  • 20
  • 35
Huy Phan
  • 146
  • 7
  • 4
    react script does not allow you put "paths" in tsconfig.json, it remove automatically for you – Pedro Soares Apr 20 '20 at 11:33
  • To prevent the react-script script from removing the `paths` from _tsconfig.json_, create _tsconfig.path.json_ (for example), add the `paths` settings and extend in _tsconfig.json_ – darkziul Jun 29 '21 at 14:09
1

Use react-app-alias:

  • Install craco and react-app-alias and create craco config:
// craco.config.js
const {CracoAliasPlugin} = require('react-app-alias')

module.exports = {
  plugins: [
    {
      plugin: CracoAliasPlugin,
      options: {}
    }
  ]
}

Replace react-scripts with craco in package.json.

Create typescript config and alias in separated config like this:

// tsconfig.paths.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "example/*": ["example/src/*"],
      "@app/*": ["app/src/*"]
    }
  }
}
// tsconfig.json
{
  "extends": "./tsconfig.paths.json",
  // ...
}

Now you can do import like this:

   import App from '@app/App'
oklas
  • 7,935
  • 2
  • 26
  • 42
  • What's the difference between this and your other `react-app-rewire-alias`? Which one will you be supporting? – wongz Jun 10 '22 at 02:56
1

An example (which I'm using) without using dependency:

//craco.config.js
const path = require('path')

const tsconfig = require('./tsconfig.base.json')

const removeAsterisk = path => path.replace('/*', '')

const aliasProps = Object.entries(tsconfig.compilerOptions.paths).map(([key, value]) => {
  const newKey = removeAsterisk(key)
  let newValue = removeAsterisk(value[0])
  newValue = path.resolve(__dirname, newValue)
  return [newKey, newValue]
})

const alias = Object.fromEntries(aliasProps)

module.exports = {
  webpack: {
    alias,
  },
}

//tsconfig.base.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "~/*": ["./src/*"],
      //...
    }
  }
}

// tsconfig.json
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {/*...*/}
}

darkziul
  • 356
  • 3
  • 5
0

Maybe the OP had a different version of React / Webpack (I'm using today's current versions), but putting the alias object directly inside the webpack object (without nesting it in the resolve object) did the trick for me:

const path = require("path");

module.exports = {
  webpack: {
    alias: {
      "@app": path.resolve(__dirname, "src"),
    }
  }
};
Parzh from Ukraine
  • 7,999
  • 3
  • 34
  • 65
0

I am using craco-alias plugin for automatic aliases generation for Webpack and Jest. (I am just an intern but that's how senior developers in my company are using absolute imports in react)

Install

yarn add @craco/craco
yarn add craco-alias

craco.config.js

const CracoAlias = require('craco-alias');

module.exports = {
  plugins: [
    {
      plugin: CracoAlias,
      options: {
        source: 'tsconfig',
        baseUrl: './src',
        tsConfigPath: './tsconfig.paths.json', // or wherever you have defined your paths
      },
    },
  ],
};

And make sure that you scripts in package.json look like the following

"scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test",
    "eject": "craco eject",
    ...
  },

Then It'll work as specified in tsconfig.json.

FYI I have, "react-scripts": "4.0.3" "@craco/craco": "^6.3.0" "craco-alias": "^3.0.1"