Aliases in React, Jest and VSCode

Do not duplicate aliases, follow this tutorial instead. Bonus: make it compatible for React (CRA)

Lucas Ennouchi
3 min readDec 19, 2021

After the end of this tutorial you should will get nice aliases like @components/MyComponentinstead of ../../MyComponent .

This will be compatible for npm run start ,npm run build , npm run test (with JEST) and the auto imports in VSCode.

This is a tutorial for Typescript with (TSConfig) but it should also work with JSConfig.

1. Aliases

Create a file tsconfig.aliases.json (does not have to be this name) where we are going to store all of our aliases.

{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@api/*": ["src/api/*"],
"@assets/*": ["src/assets/*"],
"@components/*": ["src/components/*"],
"@contexts/*": ["src/contexts/*"],

...
}
}
}

As you can see it uses the object structure of tsconfig.

2. VSCode: Add aliases to tsconfig.json

Go to tsconfig.json and extends the configuration with our aliases:

{
"extends": "./tsconfig.aliases.json",
"compilerOptions": {
...
},
"include": ["src"]
}

If you wonder why we don’t include the aliases in tsconfig.jsondirectly, it is become they will get remove by typescript automatically when trying to compile.

At that time, VsCode should now auto import modules with your aliases.

3. Webpack

Webpack aliases are defined with resolve.alias in webpack.config.js

alias: {
Utilities: path.resolve(__dirname, 'src/utilities/'),
Templates: path.resolve(__dirname, 'src/templates/'),
}

Instead of duplicating our aliases, we’re going to take the ones defined in tsconfig.aliases.json and transform them to the syntax above.

Here is a sample function to do this:

function getWebpackAliasesFromPaths(configPaths) {
const alias = Object.entries(configPaths).reduce(
(webpackAliases, [configAlias, configPathList]) => {
const [aliasKey] = configAlias.split("/");
const [relativePathToDir] = configPathList[0].split("/*");
return {
...webpackAliases,
[aliasKey]: path.resolve(__dirname, relativePathToDir),
};
},
{}
);
return alias;
}

Yourwebpack.config.js should look like:

const aliases = require("./tsconfig.aliases.json")module.export = {
...
resolve: {
...
alias: getWebpackAliasesFromPaths(aliases.compilerOptions.paths)
...
}
...
}

If you are using create-react-app, you can jump to CRACO set up instead.

4. Jest

Jest aliases are defined with moduleNameMapper in jest.config.js:

"moduleNameMapper": {
...
"^@components$": "<rootDir>/shared/components/"
}

Same here, instead of duplicating aliases, we can use a function to transform our aliases OR use the provided one by ts-utils (pathsToModuleNameMapper):

module.exports = {
...
moduleNameMapper: {
...pathsToModuleNameMapper(aliases.compilerOptions.paths, {
prefix: "<rootDir>/",
})
,
...
},
...
}

If you are using create-react-app, please continue to CRACO configuration.

Using CRACO for create-react-app

CRACO is a configuration layer for create-react-app (CRA). It’s really useful for CRA as you can’t change much of the configuration without doing an npm run eject . When building or starting the server it will make sure to take the paths set up in TSConfig / JSConfig and include them in the webpack configuration.

Use CRACO in package.json

Add craco with npm install @craco/craco --save

Then, go to package.json and change your scripts to use craco instead of react-scripts

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

Configure CRACO

We’re going to add 2 configurations for CRACO: one for webpack, one for Jest. This is all done in craco.config.js to add to the root folder of your project.

Your craco.config.js file should look like:

const path = require("path");
const { pathsToModuleNameMapper } = require("ts-jest/utils");
const aliases = require("./tsconfig.aliases.json")
function getWebpackAliasesFromPaths(configPaths) {
const alias = Object.entries(configPaths).reduce(
(webpackAliases, [configAlias, configPathList]) => {
const [aliasKey] = configAlias.split("/");
const [relativePathToDir] = configPathList[0].split("/*");
return {
...webpackAliases,
[aliasKey]: path.resolve(__dirname, relativePathToDir),
};
},
{}
);
return alias;
}
module.exports = {
jest: {
configure: {
...
moduleNameMapper: {
...pathsToModuleNameMapper(aliases.compilerOptions.paths, {
prefix: "<rootDir>/",
})
,
"\\.(css|scss)$": `<rootDir>/src/__mocks__/styleMock.js`,
},
...
},
},
webpack: {
alias: getWebpackAliasesFromPaths(aliases.compilerOptions.paths),
},
};

Finally, configure Jest to use the CRACO config in jest.config.json:

const { createJestConfig } = require("@craco/craco");
const cracoConfig = require("./craco.config.js");
const jestConfig = createJestConfig(cracoConfig);
module.exports = jestConfig;

That’s it! You should now have a fully functional environment for starting, building and testing your React application.

--

--

Lucas Ennouchi

Hi 👋. I’m a Lead Software Manager & Engineer for a global financial institution in London. I design large scale systems and help teams perform at their best.