Setting Up Absolute Paths in React TypeScript Project
This guide provides a comprehensive walkthrough for setting up absolute paths in a React TypeScript project using Vite and Vitest, including necessary adjustments to ESLint and TypeScript configurations.
Prerequisites
Node.js (version 14 or later recommended)
A React TypeScript project set up with Vite
Vitest for testing
ESLint for linting
Step 1: Update tsconfig.json
Update your tsconfig.json to include path aliases and necessary types:
{
"compilerOptions": {
// ... other options ...
/* Absolute Imports */
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
/* Types */
"types": ["vitest/globals", "node"]
},
"include": ["src", "*.config.ts"]
}
The "types" array includes:
- "vitest/globals" for Vitest testing types
- "node" for Node.js types, which are often needed in config files and for certain Vite/Vitest functionalities
Step 2: Create or Update tsconfig.node.json
Create or update tsconfig.node.json to include configuration files:
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts", "vitest.config.ts"]
}
Including "vitest.config.ts" here ensures that TypeScript processes this config file correctly, which is crucial for ESLint and TypeScript to work together smoothly on configuration files.
Step 3: Install vite-tsconfig-paths
Install vite-tsconfig-paths as a dev dependency:
npm install -D vite-tsconfig-paths
# or
yarn add -D vite-tsconfig-paths
Step 4: Update vite.config.ts
Modify your vite.config.ts to use the vite-tsconfig-paths plugin:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import tsconfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
plugins: [react(), tsconfigPaths()],
});
The tsconfigPaths() plugin allows Vite to resolve imports according to the paths configuration in your tsconfig.json.
Step 5: Update vitest.config.ts
Update your vitest.config.ts to include the tsconfigPaths plugin and use the correct types:
import { defineConfig, UserConfigExport } from 'vitest/config';
import tsconfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
plugins: [tsconfigPaths()],
test: {
environment: 'jsdom',
globals: true,
setupFiles: './src/setupTests.ts',
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
include: ['src/**/*.{js,jsx,ts,tsx}'],
exclude: [
'src/**/*.{test,spec}.{js,jsx,ts,tsx}',
'src/setupTests.ts',
'src/vite-env.d.ts',
],
},
},
} as UserConfigExport);
The as UserConfigExport type assertion ensures type compatibility with Vitest’s configuration, resolving potential type conflicts between Vite and Vitest configurations.
Step 6: Update ESLint Configuration
Update your ESLint configuration (eslint.config.js or .eslintrc.js) to handle absolute imports and config files:
import { fixupPluginRules } from '@eslint/compat';
import typescript from '@typescript-eslint/eslint-plugin';
import typescriptParser from '@typescript-eslint/parser';
export default [
// ... other configurations ...
{
files: ['src/**/*.{ts,tsx}'],
// ... other settings ...
rules: {
// ... other rules ...
'import/order': [
'error',
{
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
'newlines-between': 'always',
pathGroups: [
{
pattern: '@/**',
group: 'internal',
},
],
alphabetize: { order: 'asc', caseInsensitive: true },
},
],
},
},
{
files: ['*.config.ts', 'vite.config.ts', 'vitest.config.ts'],
languageOptions: {
parser: typescriptParser,
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: './tsconfig.node.json',
},
},
plugins: {
'@typescript-eslint': fixupPluginRules(typescript),
},
rules: {
...typescript.configs.recommended.rules,
'import/no-extraneous-dependencies': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
},
},
];
These ESLint configurations:
- Handle absolute imports with the @/ prefix
- Apply specific rules to configuration files to avoid common linting issues in Vite and Vitest configs
Usage
After setting up, you can use absolute imports in your code:
// Instead of
import { SomeComponent } from '../../../components/SomeComponent';
// You can now use
import { SomeComponent } from '@/components/SomeComponent';
This works in both your source files and test files.
Step 7: Adding Custom Absolute Paths
You can create additional custom absolute paths for specific directories like components and utils. This can make your imports even more concise and organized.
Update your
tsconfig.json:
{ "compilerOptions": { // ... other options ... "baseUrl": ".", "paths": { "@/*": ["src/*"], "@components/*": ["src/components/*"], "@utils/*": ["src/utils/*"] } } }
Update your
vite.config.ts:
The
vite-tsconfig-pathsplugin will automatically read these new paths, so no changes are needed in the Vite configuration.
Update your ESLint configuration:
Add the new path patterns to your ESLint configuration to ensure proper linting:
{ // ... other configurations ... rules: { 'import/order': [ 'error', { groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'], 'newlines-between': 'always', pathGroups: [ { pattern: '@/**', group: 'internal', }, { pattern: '@components/**', group: 'internal', }, { pattern: '@utils/**', group: 'internal', }, ], alphabetize: { order: 'asc', caseInsensitive: true }, }, ], }, }
Usage with Custom Paths
Now you can use these custom paths in your imports:
// Instead of
import { Button } from '../../../components/Button';
import { formatDate } from '../../../utils/dateUtils';
// You can now use
import { Button } from '@components/Button';
import { formatDate } from '@utils/dateUtils';
This approach allows for even more concise and intuitive imports, especially in larger projects with deep directory structures.
Troubleshooting
If you encounter issues:
Ensure all configuration files are up to date.
Restart your development server and any running ESLint or TypeScript processes.
If using VS Code, reload the window or restart the TypeScript server.
Check that all necessary dependencies are installed, including
@types/nodeif you’re using Node.js types.