Instead of using relative import paths, which can be cumbersome, you can use path aliases:

import { Counter } from '../../../../components/Counter'
import { Counter } from '#root/components/Counter'

Where #root/ denotes your project's root directory.

You may need to define your path aliases at up to three different places:

  • vite.config.js#resolve.alias (for files processed by Vite)
  • package.json#imports (for Node.js files that aren't processed by Vite)
  • tsconfig.json#compilerOptions.paths (for TypeScript)

Example:

Vite

// vite.config.js
 
export default {
  resolve: {
    alias: {
     "#root": __dirname,
    }
  }
}

The Vite config resolve.alias only applies to files that are processed by Vite. Note that some of your server files may not be processed by Vite, see the Node.js section below.

We recommend following the Node.js convention to prefix path aliases with the special character #.

See also:

Node.js

// package.json
 
{
  "imports": {
    // JavaScript:
    "#root/*": "./*.js",
    // TypeScript:
    "#root/*": "./*.ts"
  }
}

See also:

Vite's vite.config.js#resolve.alias only applies to files that are processed by Vite. (In other words: the +*.js files and their imports.)

Browser files are always processed by Vite, but this isn't always the case for Node.js server files, for example Express.js server code.

You can use Node.js's built-in support package.json#imports or, alternatively, you can use one of many npm packages such as module-alias. (Example of using module-alias: /examples/path-aliases (@c914dad).)

TypeScript

If you use TypeScript, then TypeScript needs to know about your path aliases.

// tsconfig.json
 
{
  "compilerOptions": {
    "paths": {
      "#root/*": ["./*"]
    }
  }
}

See also: