Pretty import paths?
We've all seen relative file import paths inside react applications. If you structure your apps like me you end up with terribly long paths to import other components. Auto-import can take care of that for you automatically, but isn't it hard to read and let's be honest, very, very error prone?
Webpack aliases
One way to solve this issue is adding webpack aliases. Now if you created your application using the create-react-app
cli, you will notice that there isn't a webpack config to mess with unless you eject it running npm run eject
, which will expose the entire configuration and makes you responsible of maintaining it. I prefer not ejecting my react application because I prefer the ease of use using react-scripts, so there must be another way.
Introducing craco
Create React App Configuration Override (CRACO) offers a way of overriding or extending configurations like webpack for example.
Bingo!
Install it running the following command
npm i @craco/craco
Next we need to configure craco. We do so adding a craco configuration file. Create the file craco.config.js
in the root of the project and add the following content
const path = require('path');
module.exports = {
webpack: {
alias: { '@': path.resolve(__dirname, './src') },
},
};
Let me explain how I intend to use this alias. I usually have a src/
folder in the root of the project containing all the components I use in a components/
subfolder. Other folders are helpers under helpers/
or custom hooks hooks/
. The alias I am setting up will point to the src/
folder. So whenever I write import Component from '@/components/myComponent'
it will resolve to 'src/components/myComponent'
, independent of the path I am currently work in.
The last thing to do is to run craco
instead of react-scripts
in our package.json
scripts section:
{
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test"
}
}
This will load the craco config for you.
ESLint
When using ESLint you will notice red squiggly line whenever you start using the new import paths. This is because ESLint doesn't know how to deal with those. I am also using the import plugin eslint-plugin-import
to keep import order clean and tidy.
Inside your eslint config add the following block to the settings
key.
settings: {
'import/resolver': {
alias: {
map: [['@', './src']],
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
}
},
},
The alias
key here will tell ESLint about the alias key we've setup in our webpack config through craco. I also want to import the extensions listed above without typing out the extension, so that's what that part is for.
If you use the import plugin, don't forget to add that to the extends
key:
extends: [
'plugin:react/recommended',
'plugin:import/recommended',
'plugin:import/typescript'],
I also use Typescript, see next section on how to add support for aliases.
Last thing which is entirely optional if you don't care about import order, is to tell the import plugin where we want to place the import statements using aliases. You do so by adding a configuration to the import rule:
rules: {
'import/order': [
'error',
{
pathGroups: [
{
pattern: '@/**',
group: 'parent',
position: 'before',
},
],
},
],
},
This tells ESLint that all import paths matching the pattern
key should be treated the same way as parent imports. Adding that last key position
with value 'before'
will move them over relative parent imports. You can read about what those keys do in the official docs of eslint-plugin-import
Typescript (Bonus)
Finally if you are using typescript, we also need to set up alias support as the TS compiler will complain about the alias paths not being valid.
For that open your tsconfig.json
and add the following:
{
"compilerOptions": {
"paths": { "@/*": ["./src/*"] },
}
}
As mentioned before this maps paths like @/*
to my src/
folder.
Conclusion
Completing the steps described above will give you cleaner import paths and reproducible and saner import order. You don't necessarily need the import order, but it's good practice and helps keeping your code more organized.
Top comments (5)
This CRACO package doesn't work with latest CRA 5 (webpack 5). Any other alternatives?
use 6.1.2 version
can someone pls explain to me why i still getting error when i'm using
import SomeComponent from '@baseComponents/SomeComponent';
this is part of my esLint
and this is part of my craco.config
this is tsconfig.paths.json
So this works at your end and the "paths" property in the compilerOptions in tsconfig.json doesn't get deleted?
Mine get deleted, the paths gets deleted when i start the app.
This doesn't work for me unfortunately.