67

I'm struggling to get absolute path to work in a Vite react-ts project.

Here's how I created the project

npm init @vitejs/app
npx: installed 6 in 1.883s
√ Project name: ... test-vite
√ Select a framework: » react
√ Select a variant: » react-ts

Then I added baseUrl to tsconfig.json based on the TS official doc:

{
  "compilerOptions": {
    "baseUrl": "./src",
    ...

followed by adding a simple component (T:\test-vite\src\components\Test.tsx)

import React from "react";

const Test = () => <h1>This is a Test.</h1>;

export default Test;

Finally I import the Test component in App.tsx
but it won't let me use absolute path:

import Test from "components/Test";

I get this error enter image description here

whereas if I use relative path, the app works in dev & build mode without any error:

import Test from "./components/Test";

How can I make absolute path work in the project?

Alex Monkey
  • 1,427
  • 1
  • 14
  • 16

12 Answers12

139

There are two problems here:

  • Tell typescript how to resolve import path
  • Tell vite how to build import path

You only tell typescript how to resolve, but vite don't konw how to build. So refer to the official document resolve.alias, maybe this is what you want:

// vite.config.ts
{
  resolve: {
    alias: [
      { find: '@', replacement: path.resolve(__dirname, 'src') },
    ],
  },
  // ...
}

You can import path like this (or any module under ./src):

import Test from "@/components/Test";
import bar from "@/foo/bar"

Moreover, you can use vite plugin vite-tsconfig-paths directly, it makes you don't have to manually configure resolve.alias

Follow the instructions below:

  1. Install vite-tsconfig-paths as dev dependency

  2. Inject vite-tsconfig-paths using the vite.config.ts module

import { defineConfig } from 'vite'
import tsconfigPaths from 'vite-tsconfig-paths'

export default defineConfig({
  plugins: [tsconfigPaths()],
})
pensum
  • 980
  • 1
  • 11
  • 25
Yuns
  • 1,964
  • 1
  • 10
  • 13
  • 4
    Thank you @theprimone. The plugin is surely an easy way to make it work. I ended up with this simple vite.config.ts ``` import { defineConfig } from "vite"; import reactRefresh from "@vitejs/plugin-react-refresh"; import tsconfigPaths from "vite-tsconfig-paths"; // https://vitejs.dev/config/ export default defineConfig({ plugins: [reactRefresh(), tsconfigPaths()], }); ``` It means I can simply reference the component with relative path without the @ prefix. `import Test from "components/Test";` – Alex Monkey Jul 06 '21 at 11:12
  • 6
    +1 for using `vite-tsconfig-paths` over a manual alias. I had a similar situation but wasn't using @ imports, and the suggested plugin fixed it. – bildungsroman Mar 16 '22 at 21:16
  • 2
    I got "Cannot find name '__dirname'." when using this solution. Changed the file name's extension from .ts to .cjs and it worked. – Robin Wieruch Jul 07 '22 at 07:19
  • 4
    @RobinWieruch Try dev-installing `@types/node` and explicitly import `path` like `import path from "path";`. The latest vite+react+typescript project I initialized didn't have that package installed. – V. Rubinetti Sep 30 '22 at 15:59
  • 1
    An addition to @yuns, using the plugin (vite-tsconfig-paths) means that you set your paths in tsconfig.json without having to duplicate them in vite.config.ts (.i.e you don't have to manually configure resolve.alias) – Oladapo Ajala Nov 14 '22 at 11:21
21

I came here through search results, I was looking for something different, namely, how to do a simple absolute import like import { foo } from 'src/lib/foo.ts'

So if you have a /src directory that contains all code and want to use an absolute import path.

vite.config.ts

export default defineConfig({
  ...
  resolve: {
    alias: {
      src: path.resolve('src/'),
    },
  }
})

tsconfig.json

{
  "compilerOptions": {
    ...
    "baseUrl": "./"
  }
}

Note that this is a trick: src is an alias, so it appears like the path is absolute in Vite. If you have another directory in the root dir, adjacent to /src, you will need to add another alias for that directory.

Maciej Krawczyk
  • 14,825
  • 5
  • 55
  • 67
  • 6
    There's also an npm package 'vite-tsconfig-paths' written by one of Vite's maintainers, however, it's better to not add extra 14 dependencies if it's possible. – Maciej Krawczyk May 02 '22 at 10:04
  • 1
    Thanks! This helped me, but I wasn't able to get the usage of `path` working because `path` had no reference in the file. Not sure where it comes from, so I tweaked your approach and put together an [alternative answer here](https://stackoverflow.com/a/73666492/8954541) for anyone else who has the same problem. – Erdős-Bacon Sep 09 '22 at 19:01
  • Used a lot different configurations I found to try to make this work and this finally did the trick, when the others did not. Thanks very much! To the person above you should be good to just `import path from 'path'`. – lmurphud May 23 '23 at 23:35
19

@Yuns solutions works, but it shows error in vscode. And it was breaking auto-import in vs code.

To make it work in vscode and vite both, I added alias in both tsconfig and vite.config.

// tsconfig.json
{
  "paths": {
      "@/*": ["src/*"]
    }
  // ...
}


// vite.config.ts
{
  resolve: {
   alias: [{ find: '@', replacement: '/src' }],
  },
  // ...
}

Then, I could import like below (svelte app is in src directory)

import Header from '@/components/Header.svelte
Jashwant
  • 28,410
  • 16
  • 70
  • 105
10

Looking for import {...} from "src/foo/bar";?

I also came here through search results like user Maciej Krawczyk, but the @ part also wasn't what I was interested in. That user's answer helped me, but I had trouble with the path.resolve part (ReferenceError because path wasn't defined), so I used a slightly different approach:

vite.config.ts
export default defineConfig({
  ...
  resolve: {
    alias: {
      src: "/src",
    },
  },
  ...
})

Vite's resolver considers the absolute path /src to be from where the server is serving (see GH issue). So if you're running/building from the root of your project with src as a top level directory -- which is pretty common -- this alias points Vite in the right direction.

tsconfig.json
{
  "compilerOptions": {
    ...
    "baseUrl": "./",
    "paths": {
      "src/*": [
        "./src/*"
      ]
    }
  }
}

This is basically blindly following this StackOverflow answer. TypeScript needs to know that we have special resolving going on as well, otherwise TS will be freaked out about your non-existent src package and not know where it should go looking. (Note: After I changed my TS config, VSCode didn't immediately pick up the change, so I was still getting warnings. I quit, re-opened, and had to wait ~15sec for the warnings to go away.)

Erdős-Bacon
  • 748
  • 8
  • 16
2

1) You need to install these packages:


npm i path
yarn add path

npm i @types/node
yarn add @types/node

npm i vite-tsconfig-paths
yarn add vite-tsconfig-paths

2) Then in the vite.config file:

    import { defineConfig } from 'vite';
    import react from '@vitejs/plugin-react';
    import tsconfigPaths from 'vite-tsconfig-paths';
    import path from 'path';

    export default defineConfig({
      base: './',
      resolve: {
        alias: {
          Components: path.resolve(__dirname, './src/components'),
          Assets: path.resolve(__dirname, './src/assets'),
        },
      },
      plugins: [react(), tsconfigPaths()],
    });

3) And now we have to tell TS those same paths that we defined in the alias:


    {
      "compilerOptions": {
        ...,
        "baseUrl": "./",
        "paths": {
          "src/*": [ "./src/*" ],
          // We define this path for all files/folders inside 
          // components folder:
          "Components/*": [ "./src/components/*" ],
          // We define this path for the index.ts file inside the 
          // components folder:
          "Components": [ "./src/components" ],
          "Assets/*": [ "./src/assets/*" ],
          "Assets": [ "./src/assets" ]
        }
      },
      ...
    }

4) reload vscode: As the comment above said, press Fn1 and type "reload with extensions disabled", re-enabling extensions from the popup.


Now try to import

import Test from "components/Test";

it should work.

Lucia Aldana
  • 354
  • 2
  • 6
2

Step 1 - vite.config.ts

import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react(),tsconfigPaths()],
});

Step 2 - tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "useDefineForClassFields": true,
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "baseUrl": "./src",
    "paths": {
      "@assets/*": ["./assets/*"],
      "@components/*": ["./components/*"],
      "@config/*": ["./config/*"],
      "@hooks/*": ["./hooks/*"],
      "@ioc/*": ["./ioc/*"],
      "@pages/*": ["./pages/*"],
      "@utils/*": ["./utils/*"]
    },
    "typeRoots": ["node_modules/@types", "./types"]
  },
  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.js", "src/**/*.jsx", "tests/**/*.ts", "tests/**/*.tsx"],
  "exclude": ["node_modules", "dist"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

Step 3 - index.tsx

import React from 'react';
import HeaderCustom from '@components/header';

interface Props {
   children?: React.ReactNode;
}

const Component: React.FC<Props> = ({ children, ...props }) => {
   return (
      <>
         <HeaderCustom></HeaderCustom>
      </>
   )
}

export default Component;
jonathasborges1
  • 2,351
  • 2
  • 10
  • 17
1

For anyone who stucks after all required changes, you need to reload vscode. My config files:

tsconfig.json

"baseUrl": "./",
        "paths": {
            "@/*": ["src/*"]
        }

vite.config.ts

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

// https://vitejs.dev/config/
export default defineConfig({
    resolve: {
        alias: { '@': path.resolve(__dirname, './src') },
    },
    plugins: [react()],
});

In above code you need to have 2 libraries installed:

  • 'path': npm i path
  • '@types/node': npm i @types/node

After configure your project files you need to reload vscode. To do that press ctrl + P and type ">reload with extensions disabled", after that you will get popUp to activate extensions again click it, and your absoulte path should work

If someone installed vite-tsconfig-paths library, you also need to reload the vscode, remember to import given library to vite.config.ts

export default defineConfig({ plugins: [react(), tsconfigPaths()] });

With package you get default 'components/File' import instead of '@components/File' import.

ImIGI
  • 53
  • 7
1

Try updating vite.config.ts file!

  1. install vite-tsconfig-paths as dev dependency

  2. import tsconfigPaths

  3. add tsconfigPaths() to plugins

vite.config.ts

import tsconfigPaths from "vite-tsconfig-paths"

defineConfig({ ..., plugins: [..., tsconfigPaths()] })

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 24 '23 at 20:49
0

For anyone looking specifically to add the nice import "@/something-in-src" syntax like Vue has with the latest (as of posting this answer) version of Vite + React + TypeScript, here's how I did it:

Make sure @types/node is installed as a dev dependency. This didn't come with the latest version of Vite for me, and it will make "path" and __dirname throw an undefined error.

vite.config.ts

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import path from "path";

// https://vitejs.dev/config/
export default defineConfig({
  resolve: {
    alias: [{ find: "@", replacement: path.resolve(__dirname, "src") }],
  },
  plugins: [react()],
});

tsconfig.json

Add:

{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
V. Rubinetti
  • 1,324
  • 13
  • 21
0

For anyone not using TypeScript that wants to do the same, you can achieve this by installing a Rollup plugin.

npm install --save-dev rollup-plugin-includepaths

vite.config.js

import includePaths from "rollup-plugin-includepaths";

export default defineConfig({
  plugins: [
    react(),
    includePaths({ paths: ["./"] })
  ]
})

Now you can import modules with a path like this…

import MyModule from "src/components/MyModule";

I prefer to use includePaths({ paths: ["./src"] }) to allow a simpler import, like import MyModule from "components/MyModule".

matharden
  • 757
  • 6
  • 15
0

this is just the an update from prev answers. I just merge the @Yuns and @Jashwant solution to make it work for me.

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "paths": {
      "@/*": ["./src/*"] // ==> dot before '/' is important 
    },

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

and vite.config.ts

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";
import path from "path";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react(), tsconfigPaths()],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
});

Amir Rezvani
  • 1,262
  • 11
  • 34
0

here is what i write on codenanshu

To configure your app to use absolute import, you need to make some changes to the vite.config.js file, which is found at the root of your project directory.

Add the code below to the vite.config.js file

resolve: {
    alias: {
      src: "/src",
    },
  },

like

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      // here add the absolute paths that you wanna add
      src: "/src",
    },
  },
});

after changing this file you can able to import absolute paths in TypeScript files here is an example

import Button from "src/components/Button/Button"

but to get intelligence from your code editor like VS code you have to change tsconfig.json file

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "src/*": ["./src/*"],
    }
  }
}

in this way you can able to use absolute paths without any third party packages.

Anshu Meena
  • 169
  • 1
  • 6