Aliases in React, Jest and VSCode
Do not duplicate aliases, follow this tutorial instead. Bonus: make it compatible for React (CRA)
After the end of this tutorial you should will get nice aliases like @components/MyComponent
instead 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.json
directly, 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.