vue3 项目框架搭建和配置
记录底层框架搭建,全局 TS 检测,自动导入,eslint 检测,vite 配置等一系列踩坑和解决办法
1.import 导入 .vue 文件和 tsx,TS 提示错误解决
1.在跟目录创建一个 types 文件夹,types 文件夹底下创建一个 shims-vue.d.ts 文件,文件代码如下:
// types/shims-vue.d.ts
declare module "*.vue" {
import { ComponentOptions } from "vue";
const componentOptions: ComponentOptions;
export default componentOptions;
}
2.修改 tsconfig.json 配置,include types 文件进去
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": ["types"], //包含types文件夹下的所有文件,会自动读取*.d.ts系统文件
"compilerOptions": {
"jsx": "preserve", //处理引入jsx文件报错
},
}
2.vue3 中使用 ref 语法糖 $ref,$toRef
使用 ref 总是需要处理.value 问题,所以引入了 ref 的语法糖$ref 他本身就是一个 xxx.value 所以无需处理.value 的问题 参考文件链接地址:https://www.jb51.net/article/263363.htm
const count = $ref(10)
const str = $ref('dddd')
第一步(必须),在 vite 配置里面启动语法糖
// 修改vite.config.ts
return {
plugins: [
vue({
reactivityTransform: true //启用响应式语法糖$ref $computed $toRef
})
]
}
第二步(可选),配置 tsconfig.json 在 compilerOptions 下添加 vue/ref-macros, 不然会报错 TS2304: Cannot find name '$ref'.虽然不影响使用,但是会影响开发体验
"compilerOptions":{
"types": ["vue/ref-macros"]
}
第三步(可选),配置 eslint 在 eslintrc.cjs 中加上 global,不然会提示 ESLint: '$ref' is not defined.(no-undef)
module.exports = {
globals: {
$: 'readonly',
$$: 'readonly',
$ref: 'readonly',
$computed: 'readonly',
$shallowRef: 'readonly',
$customRef: 'readonly',
$toRef: 'readonly'
}
}
3.types 文件夹下 .d.ts 文件定义全局声明引用的时候,eslint 报错 error 'PlRouteRaw' is not defined no-undef 处理
1、创建 eslintrc-global.json 配置如下
{
"globals":{
"PlRouteRaw":"readonly", //配置公共路由type PlRouteRaw
}
}
2、修改 eslintrc.cjs 文件,引入 eslintrc-global.json
module.exports = defineConfig({
extends: [
'./.eslintrc-global.json' //继承eslintrc-global.json文件的配置
]
})
4.setup 标签支持定义组件名称 name
当使用 setup 放到 scrip 标签的时候,组件需要通过 name 去注册的时候,可以通过以下方式去修改, 参考地址:https://blog.csdn.net/zy21131437/article/details/124523320
第一种:新增加一个 script 标签,在这个标签中写入 name 属性,代码如下
<template>
<button>demo</button>
</template>
<script lang="ts">
export default {
name: 'TButton'
}
</script>
<script lang="ts" setup></script>
<style scoped lang="less"></style>
第二种:使用一个叫做 “unplugin-vue-define-options” 的插件,这个插件本来确实不知道,有一次在看 Element Plus 的源码时发现了这个插件,发现在 Element Plus 中都是使用这个插件来对组件名进行注册的,因此学到了 具体方式如下:
第一步:安装,安装的方式很常规,就是 npm 的安装
npm install unplugin-vue-define-options -D
第二步:集成,找到 vite.config.ts 文件,加入插件 unplugin-vue-define-options(由于我是使用了 vite 作为配置工具,那么这里就演示 vite 中的用法)
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import DefineOptions from 'unplugin-vue-define-options/vite'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(), DefineOptions()]
})
第三步:集成完成之后,那么可以直接使用了,如果在 TypeScript 中报错了,那么调整一下就行了,比如在 d.ts 的配置文件中加入描述
<template>
<button></button>
</template>
<script lang="ts" setup>
defineOptions({
name: 'TButton'
})
</script>
<style scoped></style>
第三种:这种方式其实也是 vue3 中的,只是它的 setup 用法是 vue3 早期的,这种方式其实没有 name 这个顾虑,可以直接写,这里也列一下吧
<template>
<div></div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'TButton'
})
</script>
<style scoped lang="less"></style>
5.自动按需导入配置
通过插件 unplugin-auto-import/vite 实现自动按需导入。 使用参考地址:https://github.com/antfu/unplugin-auto-import 第一步:安装插件
npm i -D unplugin-auto-import
第二步:引入组件,vite 配置
//自动导入
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
plugins: [
AutoImport({
/* options */
})
]
})
6.环境变量自定义变量类型错误,都是字符串处理
参考地址:https://juejin.cn/post/7094940781726826526
问题一、自定义的环境变量没有提示,使用环境变量的时候 ts 报错 第一步:需要配置 ts 支持,根目录创建 env.d.ts 文件进行如下配置
// env.d.ts文件配置
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_XXX_XXXX: boolean;
readonly VITE_XXXX_XXX: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
第二步:配合 tsconfig.json 配置文件,读取 env.d.ts。
{
"include": ["env.d.ts"],
}
问题二:自定义的环境变量的类型不正确,拿到的都是字符串类型
第一步:在文件夹 build 下创建一个工具函数 useEnv.ts 将环境变量转换成正确的类型
//useEnv.ts
export const useEnv = (envs: Record<string, string>): Plugin => {
return {
name: "vite:debug-env",
config(config: UserConfig, env: ConfigEnv) {
if (env) {
const defineMap = {} as Record<string, any>;
const envPrefix = Array.isArray(config.envPrefix)
? config.envPrefix
: [config.envPrefix || "VITE_"];
const pattern = new RegExp(`^${envPrefix.join("|")}`, "i");
Object.keys(envs).forEach((key) => {
if (pattern.test(key)) {
const realName = (envs[key] as any).replace(/\\n/g, "\n");
if (["true", "false"].includes(realName.toLowerCase())) {
defineMap[`import.meta.env.${key}`] = JSON.parse(
realName.toLowerCase()
);
} else {
defineMap[`import.meta.env.${key}`] = JSON.stringify(realName);
}
}
});
return {
define: defineMap,
};
}
return;
},
};
};
第二步:vite.config.ts 引入工具函数 useEnv
//vite.config.ts
import { useEnv } from "./build/useEnv";
export default defineConfig(({ mode }: ConfigEnv) => {
const env = loadEnv(mode, process.cwd());
return {
plugins:{
useEnv(env),
},
};
});
7.elementUI 自定义样式修改支持
1.修复原始变量 var.scss 具体的语法参考 elementui 官网:https://element-plus.org/zh-CN/guide/theming.html#%E9%80%9A%E8%BF%87-scss-%E5%8F%98%E9%87%8F
2.vite 配置如下:
export default defineConfig(({ mode }: ConfigEnv) => {
const env = loadEnv(mode, process.cwd())
return {
css: {
preprocessorOptions: {
scss: {
additionalData: `
@use "@/plugins/elementPlus/var.scss" as *; // element ui原始变量修改
@use "@/styles/style_base.scss"; //项目样式文件
`
}
}
}
}
})
8.全局配置自动导入 ElMessage,并且配置 TS 全局使用和提示
1.vite 配置支持自动导入如下
//vite.config.ts
export default defineConfig(({ mode }: ConfigEnv) => {
return {
plugins:{
AutoImport({
imports: [
"vue",
{
"@/utils/storage": [["*", "$plStore"]],
"element-plus": [
["ElMessage", "$ElMessage"],
["ElMessageBox", "$ElMessageBox"],
["ElNotification", "$ElNotification"],
],
dayjs: [["*", "dayjs"]],
},
],
dts: "./types/auto-import.d.ts", //生成自动全局导入文件
eslintrc: {
enabled: true,
filepath: "./.eslintrc-auto-import.json", //生成全局eslint支持
},
}),
},
};
});
9.打包去掉 TS 报错校验
1.修改配置文件 package.json 文件
//打包校验ts
{
build:"run-p type-check build-only",
}
//打包不校验ts
{
build:"run-p build-only",
}
10.scss 不放在默认的 assets 目录下无法编译识别变量,并且报错
1.安装 postcss-scss
pnpm i postcss-scss
2.根目录创建 postcss.config.js
module.exports = {
parser: 'postcss-scss' //预处理器配置
}
3.vite 配置支持全局变量和引入全局基础样式
//vite.config.ts
export default defineConfig(({ mode }: ConfigEnv) => {
const env = loadEnv(mode, process.cwd())
return {
css: {
preprocessorOptions: {
scss: {
additionalData: `
@use "@/styles/var.scss"; //全局变量
@use "@/styles/style_base.scss"; //全局基础样式
`
}
}
}
}
})
vite3.x globEager 已弃用的解决方案
js import.meta.globEager
已弃用采用 import.meta.glob
替代
const modules = import.meta.glob('./*/index.ts', {
eager: true,
import: 'default'
})
vite 配置支持 eslint 检测
1.vite 配置文件修改
//vite.config.ts
import eslint from "vite-plugin-eslint";
export default defineConfig(({ mode }: ConfigEnv) => {
const env = loadEnv(mode, process.cwd());
return {
plugins: {
eslint({ fix: false }),
},
};
});
2.根目录创建.eslintrc.cjs 文件进行 eslint 语法配置
/* eslint-env node */
const { defineConfig } = require('eslint-define-config')
module.exports = defineConfig({
root: true,
env: {
browser: true,
es2021: true,
node: true
},
globals: {
$: 'readonly',
$$: 'readonly',
$ref: 'readonly',
$computed: 'readonly',
$shallowRef: 'readonly',
$customRef: 'readonly',
$toRef: 'readonly'
},
extends: [
'plugin:vue/vue3-essential',
// "eslint:recommended",
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier',
'./.eslintrc-auto-import.json',
'./.eslintrc-pl-global.json'
],
parserOptions: {
ecmaVersion: 'latest',
parser: '@typescript-eslint/parser',
sourceType: 'module',
ecmaFeatures: {
jsx: true
}
},
plugins: ['vue', '@typescript-eslint'],
rules: {
'no-var': 1, //不使用var
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', //生产环境不能用console.log()
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', //生产环境不能用debugger
'no-undef': 'error', // 变量未声明就使用
'no-empty': 'warn', // 块语句的内容不能为空,warn警告
'no-extra-semi': 2, // 禁止多余的冒号
'prefer-const': 1, // 授权const
'no-useless-escape': 'warn',
semi: [2, 'always'],
quotes: [
'error',
'double',
{ avoidEscape: true, allowTemplateLiterals: true }
], //单双引号
eqeqeq: 2, //必须使用全等
// "comma-dangle": [ // 关掉 拖尾逗号 校验
// "warn",
// {
// arrays: "always-multiline",
// objects: "always-multiline",
// exports: "never",
// functions: "never",
// },
// ],
indent: 'off',
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'warn',
{ argsIgnorePattern: '^_', args: 'after-used' }
],
'vue/html-selft-closing': 0,
'vue/multi-word-component-names': 0,
'vue/singleline-html-element-content-newline': 'off',
// "space-before-function-paren": [
// "error",
// { anonymous: "always", named: "never", asyncArrow: "always" },
// ],
'space-before-function-paren': 'off',
'vue/max-attributes-per-line': [
'error',
{
singleline: 4,
multiline: {
max: 4
}
}
],
'vue/v-on-event-hyphenation': [
'warn',
'always',
{
autofix: true,
ignore: []
}
],
'vue/html-indent': 'off',
// "vue/html-indent": [
// "warn",
// 2,
// {
// attribute: 1,
// baseIndent: 1,
// closeBracket: 0,
// alignAttributesVertically: true,
// ignores: ["VAttribute"],
// },
// ],
'vue/first-attribute-linebreak': [
'error',
{
singleline: 'ignore',
multiline: 'ignore'
}
]
}
})