相信很多人设置了别名“@”后在编辑器内产生了大量的红色波浪线,警告无法读取相关模块。网上针对这个问题都没有好好分析原因,并且提供真正理解之下的解决方案。我在历经各种失败后,总结出这篇文章,希望对大家有所帮助。
当然我因为是匆忙上手vue项目,没有系统去学习nodejs
、vite
等,所以很可能这个问题产生的根本原因只是你我都没仔细看说明书~~~
各种出错情况
在这里罗列一下我曾出现的问题,大家如果有别的现象,但后来通过本文所提方法解决了,请写在留言里,我会补充进来。
- vscode编辑器中出现大量红色波浪线警告,这就是路径没配置好的最明显证据;
- 使用
typescript
就出错,使用javascript
就正常,把<script lang="ts"></script>
中的lang="ts"
删除后正常; .vue
组件页面中用import
引入时不出现警告,但在独立的.js
或.ts
文件中引用文件时出现波浪警告;npm run dev
时出现错误提示;- 编辑器有大量红色警告,但执行
npm run dev
命令正常启动服务; - 无论开发状态下有没有出现红色警告,但执行命令
npm run dev
和vite build
正常,执行npm run build
时却失败,出现类似提示Cannot find module '@/test/types' or its corresponding type declarations
(我就一直卡在这里); - 编译时提示模块找不到,出现类似
src/index.ts:4:31 - error TS7016: Could not find a declaration file for module '@/components/system/Register.vue'. 'E:/Projects/test/src/components/system/Register.vue' implicitly has an 'any' type.
的提示
vite和typescript调用分析
在 Vite 配置中设置路径别名时,.vue
文件和 .ts
文件的处理方式有所不同。
.vue
文件中的路径解析会被 Vite 的插件自动处理。
比如.vue
的非typerscript
代码中找不到@
别名,很可能是因为vite.config.ts
文件中没有正确配置路径别名。.ts
文件的别名解析可能依赖于tsconfig.json
的配置。
比如.ts
文件中找不到@
别名,很可能是因为tsconfig.json
文件中没有正确配置路径别名。
如果这两个没有配置正确,那自然就会出现之前提及的各种错误。
比如单独的ts或ts代码片段里出现错误,那就说明vite
配置好了,但typescript
没有配置好。
解决方案
不要跳,一步步看,看懂了以后遇到任何类似问题都能解决了。
- 主要配置
这是网上出现的最主要方案,但很可能配完以后还是失败。
- 确认 Vite 配置中的路径别名生效:
在vite.config.ts
中,确保别名配置正确,主要写法如下:
// vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': '/src'
}
}
});
- 在
tsconfig.json
中设置路径别名:
确保在tsconfig.json
文件中加入类似下面的配置,以便TypeScript
在编译时能正确解析@
,主要写法如下:
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
如果配置完成后还是失败,但情况与之前不同了,那么恭喜你,我们将进入下个必要手段:
- 开发时虽然路径有波浪线警告,但执行
npm run dev
命令正常,前端可运行【说明vite.config.ts配置正确】;- 运行
vite build
正常【说明vite.config.ts配置正确】;- 运行
npm run build
失败【说明tsconfig.json配置错误】。
- 次要及必要配置(往往是这一步导致的错)
你再仔细看看你的ts.config.json
真是写得一摸一样么?反正我不是。。。
用vite首次创建项目时,tsconfig.json
往往内容是这样的:
// tsconfig.json
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
你改完以后的代码往往是这样的:
// tsconfig.json
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
}
}
}
问题就出在这里了。
typescript在解析时,他根据配置引入了 ./tsconfig.app.json
这个配置文件,而这个配置文件可能是这样的;
// tsconfig.app.json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}
发现没,这里也有一个compilerOptions
项,现在你有那种茅塞顿开的感觉了么?
反正当我看到这个的时候恍然大悟了,原来是tm被覆盖了啊!
路径别名配置的生效文件: 由于 tsconfig.json 文件引用了 tsconfig.app.json 和 tsconfig.node.json,要确保这两个文件中没有覆盖 baseUrl 和 paths 配置。一般来说,主要的路径别名配置应位于 tsconfig.app.json 文件中,以便应用编译时可以正确使用别名。
事情到这里都应该知道怎么处理了吧?其实有很多种方式,这里列二种区别明显的:
方法一:覆盖
我让你覆盖,我让你覆盖。
你是不是要覆盖,行,我让你也有,你爱覆盖谁覆盖谁!
// tsconfig.json 原内容不变
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
],
// 写不写都可以
/*"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
}
}*/
}
// tsconfig.app.json
{
"compilerOptions": {
// 原配置
"noUncheckedSideEffectImports": true,
...
// 不管tsconfig.json写不写,我都给他写一下
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}
方法二:继承
用references
配置的模块就是子模块,那我让子模块继承extends
父模块的衣钵不就行了?
// tsconfig.json
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
],
// 新增配置
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
}
}
}
// tsconfig.app.json
{
// 加一句:继承,从你爸爸这里继承配置,看谁覆盖谁
"extends": "./tsconfig.json",
// 原生配置
"compilerOptions": {
"noUncheckedSideEffectImports": true,
...
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}
通过继承,可以在
tsconfig.json
中定义一些通用的配置项,然后在tsconfig.app.json
中只定义特定的或覆盖的配置项。这样可以减少重复配置,提高维护性。
了解了继承的概念后,以后你可以根据项目需要写不同的配置,然后把他们按需引进来就行了~~
哇哦,有用却用不上的概念又多了一点点。
其它情况
上面的操作基本上能解决99%的问题,现在我再提几个可能存在的情况。
- 安装依赖
在vue里使用typescript,请看一下node_modules/
里是不是已经安装了vue
和vue-tsc
,这个问题一般是不存在的,除非你中途从js转到了ts。。。
npm install vue vue-tsc --save-dev
- path在vite.config.ts的应用
有些人喜欢使用 path
模块的 resolve
方法,将 __dirname
和 src
组合成一个绝对路径,更保险一点。
- 跨平台兼容性:path 模块确保路径在不同操作系统上都能正确解析,避免了路径分隔符不一致的问题。
- 动态路径生成:path.resolve 可以根据当前文件的位置动态生成路径,适用于项目结构复杂或路径需要动态变化的场景。
- 可读性和维护性:使用 path 模块的代码更具可读性和维护性,尤其是在大型项目中,路径管理变得更加清晰。
- 先安装
path
模块
cnpm i path
- 在
vite.config.ts
里设置
...
import path from 'path'
export default defineConfig({
...
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
...
}
...
})
- 示例
// 1. path
const path = require('path');
const srcPath = path.resolve(__dirname, 'src');
console.log(srcPath); // 输出: C:\Users\user\project\src
//2. 原始
const srcPath = '/src';
console.log(srcPath); // 输出: /src
- __dirname 是当前文件 config.js 所在的目录路径,即 C:\Users\user\project。
- path.resolve(__dirname, ‘src’) 会将 C:\Users\user\project 和 src 组合成一个绝对路径 C:\Users\user\project\src。
这个路径是正确的,无论你在哪个操作系统上运行,都会生成正确的路径。
- 版本不同、模块冲突、完整安装等问题
这个情况就很复杂了,每个人当前系统都有差异,不太好分析。
比如你在vite.config.ts
中配置如下:
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
// 编译时的配置
build: {
outDir: 'dist',
assetsDir: 'static',
rollupOptions: {
input: 'src/main.ts',
},
},
// 配置生产环境的目录,注意process必须配置了 npm i @types/node
base: process.env.NODE_ENV === 'production' ? '/abc/' : '/',
})
此刻
如果你没有安装path
,那path.resolve(__dirname, 'src')
的path
就无法识别
如果你没有安装@types/node
,那base: process.env.NODE_ENV === 'production' ? '/abc/' : '/',
的process
就无法识别
只能先安装了
npm i path
npm i @types/node
其它情况你只能根据错误提示来安装了,如果实在不行我建议就删了重新部署一个干净的,再把项目代码放进去就行了。
- 书写错误
昨天为了写这篇文章,为了测试,在我现有代码上做了很多次改动,结果整个系统崩掉了,所以诸位兄弟姐妹一定要仔细看代码啊。
我的错误也是挺特殊的,正好与本文契合:
我的vite.config.ts
写成这样了,@
多了一个斜杠/
:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vite.dev/config/
export default defineConfig({
...
resolve: {
alias: {
'@/': path.resolve(__dirname, 'src')
}
},
...
})
然后死活整不出了。。。
这个问题解决也简单:
// 1. 方案一,删掉斜杠
...
export default defineConfig({
...
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
},
...
})
// 2. 方案二,为了斜杠而斜杠
...
export default defineConfig({
...
resolve: {
alias: {
'@/': `${path.resolve(__dirname, 'src')}/`
}
},
...
})
// 3. 方案三,之前已经写过了,这里重申一下:注意斜杠是在前面的
...
export default defineConfig({
...
resolve: {
alias: {
'@': '/src'
}
},
...
})
通过这里的知识点,其实你已经可以写很多自己的别名了,比如你常用目录是在a/b/c
,那就搞个别名叫abc
呗~~
- vue声明
vscode开发typescript在引用vue时会提示找不到模块,错误提示大概如下:
`src/index.ts:4:31 - error TS7016: Could not find a declaration file for module '@/components/system/Register.vue'. 'E:/Projects/test/src/components/system/Register.vue' implicitly has an 'any' type.`
这时需要在环境配置中加入声明,一般用方法一就够了。
// src/vite-env.d.ts
/// <reference types="vite/client" />
// 定义 .vue 文件的模块声明,使 TypeScript 能够正确识别和处理 Vue 组件
// 1. 方法1:更适合项目中有复杂的组件配置需求,或者需要更精确的类型检查
declare module "*.vue" {
import { ComponentOptions } from 'vue'
const componentOptions: ComponentOptions
export default componentOptions
}
// 2. 方法2
declare module "*.vue" {
import Vue from 'vue';
export default Vue;
}
// 注意,当自定义目录下有一些常规内容读不了,试试把这个目录也加进去,如下
// 定义路径别名的类型声明
declare module '@/xxxx/*' {
import type { ComponentOptions } from 'vue'
const componentOptions: ComponentOptions
export default componentOptions
}
- 清空缓存重启服务
有时 TypeScript 缓存可能会导致配置更改没有生效。尝试清理缓存(删除 node_modules
、 dist
、_vite
等文件夹),然后重新构建。
cnpm install
也可以重启vite服务
vite --force
也可以重启vscode
- 文件后缀或目录完整度
这条不是本文的主题,本文主题是
@
别名,但会有同学因为这个问题导致出错,所以这里提一下。
还记得原生代码中有这句么?
// tsconfig.app.json
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
目的很明确了,include
就相当于一个白名单,名单里有的文件类型才编译,那为什么有些人必须要写了这句才能解决@
的问题呢?
不是tsconfig.app.json
里配置了include
么?
我猜,我猜啊,他们这一类在tsconfig.json
的配置中没有里这个references
:
// tsconfig.json
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
],
因为他们的tsconfig.json
里既没有include
,又没有references
引入tsconfig.app.json
,所以出错了。
好了,现在知道为什么要加了不?参考下方代码。
"include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
我目前强迫症,喜欢把 src/**/*.d.ts
给加进去
- baseUrl基目录
compilerOptions
中一般要把baseUrl
加进去,"baseUrl": "."
的意思就是将项目的基目录为当前目录。
如果你的文件在D:/project/test/tsconfig.ts
,那么.
就意味着D:/project/test/
是基目录,一切从此出发。
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
}
}
你可以注意一下这个位置有没有配置错误。
- 小经验
编译的时候两个命令都用一下最好
vite build
npm run build
这两者产生的错误警告有所不同,编译有时候npm没通过,vite却通过了。
总结
- 文字
- 因为是
vite
和typescript
两条线走路,所以有两处需要配置。 - 不管你怎么改,万变不离其宗:主旨就是让
typescript调用的时候能看到你的完整路径!
- 完整路径由
根目录+目录名+文件名+文件后缀
组成,从这几点上去考虑,相信很快就能找到你自己代码的病症,开出准确的方子来解决。
- 代码
这里贴一下较为完整又精简够用的配置代码
// 1. vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vite.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
// 编译时的配置
build: {
outDir: 'dist',
assetsDir: 'static',
rollupOptions: {
input: 'src/main.ts',
},
},
// 配置生产环境的目录,注意process必须配置了 npm i @types/node
base: process.env.NODE_ENV === 'production' ? '/abc/' : '/',
})
// 2.tsconfig.json
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
// 3. tsconfig.app.json
{
"extends": "./tsconfig.json", // 继承自tsconfig.json
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}
如果对你有帮助,一键三连!
如果对你有帮助,一键三连!
如果对你有帮助,一键三连!
参考:
vue3+vite+typescript+setup组合式代码风格的模式开发的项目所需的一些必备内容,该安装安装,该创建创建
vue3+vite+ts 配置别名@报错找不到模块
【typescript - tsc 编译后路径问题/路径别名问题】
【解决90%】vue3+vite3+ts使用@alias路径别名爆红解决办法
Vue3解决“找不到模块“@/components/xxx.vue”或其相应的类型声明”