🎉 init:底层初始化

This commit is contained in:
sundongyu 2024-05-30 19:07:35 +08:00
commit b0441ed8de
30 changed files with 5591 additions and 0 deletions

199
.eslintrc.js Normal file
View File

@ -0,0 +1,199 @@
{
"extends": [
// 这一行告诉ESLint去使用@typescript-eslint/recommended规则集。这个规则集包含了TypeScript团队推荐的一系列规则有助于识别TypeScript代码中的常见问题比如语法错误、潜在的类型问题等。
"plugin:@typescript-eslint/recommended",
// 这行配置引入了Vue 3的官方ESLint插件推荐的规则集。它包含了对于Vue 3单文件组件SFCs的最佳实践建议帮助开发者遵循Vue的编码规范包括模板、脚本和样式部分的检查
"plugin:vue/vue3-recommended",
// 此行配置启用了Prettier的ESLint插件并使用其推荐的规则。Prettier是一个流行的代码格式化工具能够自动格式化代码以保持一致的风格。通过此配置你的代码风格将与Prettier的标准保持一致减少因格式差异导致的代码审查冲突。
"plugin:prettier/recommended"
],
"env": {
// 告诉ESLint你的代码将在浏览器环境中运行。因此ESLint会启用或强化那些与浏览器环境相关的规则比如禁止使用Node.js特有的全局变量如require
"browser": true,
// 表明你的代码设计为在Node.js环境中执行。启用这个选项后ESLint会认识Node.js的全局变量和Node.js特有的API调用避免这些被误报为错误。
"node": true,
// 指出你的项目使用Jest作为测试框架。这会配置ESLint以理解Jest的全局变量和函数确保在编写测试代码时不会因为使用了Jest的特性而触发不必要的警告或错误。
"jest": true,
// 指示你的代码基于ECMAScript 6ES6也称作ES2015或更高版本的标准。启用此选项后ESLint会支持ES6的语法特性并根据这些新标准调整相关规则比如允许使用箭头函数、解构赋值等ES6特性。
"es6": true
},
"plugins": [
// 这个插件使得ESLint能够理解并检查Vue.js单文件组件SFCs中的代码。它提供了对Vue模板语法、script部分以及style部分的 linting 规则帮助开发者遵循Vue的最佳实践提升代码质量和可维护性
"vue",
// 插件是专门为TypeScript设计的它允许ESLint理解和 lint TypeScript 代码。这个插件集成了许多有用的规则用以识别TypeScript特有的一些潜在问题比如类型错误提示、不必要的类型断言等从而提高TypeScript代码的质量和类型安全性。
"@typescript-eslint"
],
"globals": {
// 这两个全局变量通常与Cypress测试框架相关cy是Cypress提供的命令链方法的主入口点用于编写测试代码Cypress则是该框架的全局对象包含配置和其他功能。标记为readonly表示这些变量不应在代码中被重新赋值仅用于读取和调用。
"cy": "readonly",
"Cypress": "readonly",
// 表示clipboardData是一个预期存在的全局变量可能与浏览器的剪贴板操作有关标记为只读意味着它不应该被修改
"clipboardData": "readonly",
// 定义了一个名为PKG_VERSION的全局变量这里的true表示这是一个可写的全局变量没有特别限制其使用方式。这种变量可能用于存储项目版本信息等。
"PKG_VERSION": true,
// 这两个全局变量与Vue 3的Composition API紧密相关。defineProps用于定义组件接收的props而defineEmits用于定义组件可以发出的事件。它们都被标记为只读意味着这些函数不应该被赋予新的值仅用于组件内部的属性和事件声明
"defineProps": "readonly",
"defineEmits": "readonly"
},
"parserOptions": {
// 指定了ESLint应该使用@typescript-eslint/parser作为代码解析器。这个解析器是专门为TypeScript设计的能够理解TypeScript的语法特性使得ESLint能够正确地解析和 lint TypeScript 代码。
"parser": "@typescript-eslint/parser",
// 告诉ESLint你的代码使用的是ES模块import/export语法而不是传统的CommonJS模块如require。这会影响如何解析模块导入导出语句
"sourceType": "module",
// 允许在代码的任何位置使用import和export语句而不局限于模块顶层。这在某些特定的项目配置或使用场景下可能有用但通常建议仅在模块顶层使用导入导出以遵循最佳实践。
"allowImportExportEverywhere": true,
// 启用对JSX的支持。这意味着ESLint会正确解析包含JSX元素一种HTML-like语法常用于React和其他库中编写用户界面的代码不会将其视为错误。当你的项目中包含前端组件并使用JSX编写时这一设置是必要的。
"ecmaFeatures": {
"jsx": true
}
},
"settings": {
// 这个设置指定了ESLint在检查导入语句时应考虑的文件扩展名列表。列表中的每一个扩展名都代表了一种ESLint会认为是有效导入目标的文件类型。
"import/extensions": [
".js",
".jsx",
".ts",
".tsx"
]
},
// 这段配置详细地定义了ESLint的规则设置覆盖了代码风格、导入管理、以及TypeScript和Vue特定的规则。以下是一些关键规则及其含义的简要说明
// 通用代码风格规则
// "no-console": ["error", { "allow": ["info", "warn", "error"] }]: 错误级别地禁止使用console.log等方法但允许console.info、console.warn和console.error。
// "no-continue": "off", "no-restricted-syntax": "off", "no-plusplus": "off" 等: 这些规则被关闭意味着允许使用continue语句、不限制特定语法结构如for循环、允许自增自减操作符等。
// "no-param-reassign": "off", "no-shadow": "off": 关闭参数重赋值和变量阴影的检查。
// "no-underscore-dangle": ["error"]: 错误级别地禁止在标识符中使用前导或尾随下划线(某些例外可能通过其他配置允许)。
// 未使用变量和表达式
// "no-unused-vars": "off", "no-unused-expressions": "off": 关闭未使用变量和未使用的表达式的检查。
// 函数和循环
// "func-names": "off", "guard-for-in": "off", "consistent-return": "off": 不强制函数命名规则、不检查for...in循环的安全性、不强制函数返回一致性。
// 导入规则
// "import/extensions": "off", "import/no-unresolved": "off", "import/no-extraneous-dependencies": "off": 关闭导入文件扩展名检查、未解决的导入路径检查、以及禁止导入非直接依赖。
// "import/prefer-default-export": "off": 不强制模块使用默认导出。
// TypeScript规则
// @typescript-eslint: 大多数TypeScript相关的规则被关闭或放宽如允许any类型、不强制模块边界类型、允许require导入、允许空函数、允许特定类型注释等。但也有配置如"@typescript-eslint/no-unused-vars"设置为警告级别并指定了忽略模式以忽略以_开头的变量。
// Vue规则
// "vue/require-default-prop", "vue/multi-word-component-names", "vue/no-deprecated-slot-attribute": 这些Vue规则被关闭意味着组件不必提供默认prop、组件名称不必多词、允许使用已废弃的slot属性。
// 整体来看,这些规则配置放松了很多常见的代码风格和最佳实践检查,可能旨在提高开发速度或适应特定团队的编码习惯。然而,过度放宽规则可能牺牲代码质量和可维护性,因此建议根据项目实际需要仔细权衡。
"rules": {
"no-console": [
"error",
{
"allow": ["info", "warn", "error"]
}
],
// code style config
"no-continue": "off",
"no-restricted-syntax": "off",
"no-plusplus": "off",
"no-param-reassign": "off",
"no-shadow": "off",
"no-underscore-dangle": ["error"],
"no-unused-vars": "off",
"no-unused-expressions": "off",
"no-return-assign": "off",
"no-use-before-define": "off",
"func-names": "off",
"guard-for-in": "off",
"consistent-return": "off",
"no-restricted-globals": "off",
"default-param-last": "off",
"default-case": "off",
"prefer-spread": "off",
// import config
"import/extensions": "off",
"import/no-unresolved": "off",
"import/no-extraneous-dependencies": "off",
"import/prefer-default-export": "off",
"import/no-relative-packages": "off",
// typescript config
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-require-imports": 0,
"@typescript-eslint/no-var-requires": 0,
"@typescript-eslint/prefer-for-of": 0,
"@typescript-eslint/ban-types": 0,
"@typescript-eslint/no-unused-vars": [
1,
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_"
}
],
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/ban-ts-comment": 0,
"vue/require-default-prop": 0,
"vue/multi-word-component-names": 0,
"vue/no-deprecated-slot-attribute": 0
},
"overrides": [
{
// "files": ["*.vue"]: 指定此override应用于所有扩展名为.vue的文件即Vue单文件组件SFCs。 在rules部分针对Vue组件设置了特定的规则
"files": ["*.vue"],
// 此规则强制组件名称在模板中必须遵循“kebab-case”短横线连接的小写单词例如<my-component>。数字2表示如果违反此规则ESLint将以错误级别报告最严格的级别通常会导致构建失败或警告
"rules": {
"vue/component-name-in-template-casing": [2, "kebab-case"],
// 这个规则被设置为0意味着完全关闭了对组件默认属性props的要求。Vue通常推荐为组件的props提供默认值以增强组件的可复用性但此处决定不强制执行此最佳实践。
"vue/require-default-prop": 0
}
},
{
// "files": 列出了覆盖规则将应用的文件路径模式。
"files": [
// **/_example/*: 匹配任何层级下以_example为目录名的文件。
"**/_example/*",
// **/_example - ts/*: 类似地匹配任何层级下以_example - ts为目录名的
"**/_example - ts/*",
// script/**/* 和script/*: 匹配script目录下的所有文件无论深度如何。
"script/**/* ",
"script/*",
// *.js: 匹配任何直接位于根目录下的.js文件。
"*.js",
// site/**/*和site/*: 匹配site目录下的所有文件不论层级。
"site/**/*",
//
"site/*"
],
// "rules": 定义了在上述指定的文件范围内生效的特定规则。
"rules": {
// "no-var-requires": 0: 禁止使用require语句中的变量声明var关键字但在这些文件中该规则被关闭。
"no-var-requires": 0,
// "no-console": 0: 允许使用console.log等console方法不报错。
"no-console": 0,
// "no-unused-expressions": 0: 不检查未使用的表达式,如未赋值的函数调用。
"no-unused-expressions": 0,
// "no-alert": 0: 允许使用alert函数不报错。
"no-alert": 0
}
},
{
// "files": 指定了覆盖规则适用的文件类型这里是所有的TypeScript (*.ts) 和 TypeScript with JSX (*.tsx) 文件。
"files": [
"*.ts",
"*.tsx"
],
// "rules": 针对这些文件类型配置了一个特定的TypeScript ESLint规则
"rules": {
// "@typescript-eslint/explicit-function-return-type": 0: 禁用了
"@typescript-eslint/explicit-function-return-type": 0
}
},
{
// "files": 指定了覆盖规则适用的文件模式,这里是所有以.test.js结尾的文件即测试脚本文件。
"files": [
"*.test.js"
],
"rules": {
// "import/no-dynamic-require": "off": 关闭了import/no-dynamic-require规则。这条规则通常禁止在运行时动态地使用require()来导入模块,以鼓励静态分析和提前发现潜在的模块加载错误。但在测试环境中,动态加载模块可能是为了模拟或测试特定条件下的行为,因此在这个上下文中关闭该规则是有道理的
"import/no-dynamic-require": "off",
// "global-require": "off": 同样关闭了global-require规则。这条规则通常建议避免在全局作用域使用require()鼓励模块化的代码结构。然而在测试文件中有时直接在全局作用域使用require()来引入测试工具、模拟模块或设置测试环境是常见的做法,因此在此场景下关闭该规则可以减少不必要的警告。
"global-require": "off"
}
},
// 单独的"files": "*"}配置段在ESLint的overrides部分表示一个非常宽泛的覆盖规则理论上意在应用于所有文件
{
"files": "*"
}
]
}

30
.gitignore vendored Normal file
View File

@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo

37
.prettierrc.js Normal file
View File

@ -0,0 +1,37 @@
module.exports = {
// 一行最多 120 字符
printWidth: 120,
// 使用 2 个空格缩进
tabWidth: 2,
// 不使用缩进符,而使用空格
useTabs: false,
// 行尾需要有分号
semi: true,
// 使用单引号
singleQuote: true,
// 对象的 key 仅在必要时用引号
quoteProps: 'as-needed',
// jsx 不使用单引号,而使用双引号
jsxSingleQuote: false,
// 末尾需要有逗号
trailingComma: 'all',
// 大括号内的首尾需要空格
bracketSpacing: true,
// 箭头函数,只有一个参数的时候,也需要括号
arrowParens: 'always',
// 每个文件格式化的范围是文件的全部内容
rangeStart: 0,
rangeEnd: Infinity,
// 不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准
proseWrap: 'preserve',
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: 'css',
// vue 文件中的 script 和 style 内不用缩进
vueIndentScriptAndStyle: false,
// 换行符使用 lf
endOfLine: 'lf',
};

7
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"recommendations": [
"Vue.volar",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}

2
README.md Normal file
View File

@ -0,0 +1,2 @@
```

3
env.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
// 是一个TypeScript引用指令通常出现在使用Vite作为开发服务器的项目中。这条注释有着特殊的意义它告知TypeScript编译器去包含来自@types/vite__client的类型声明文件。Vite客户端类型包含了用于Vite提供的客户端实用类型声明比如在浏览器环境中可用的全局变量或API。这样可以确保在项目中使用Vite的特性时编辑器和TypeScript能够提供正确的代码补全和类型检查提高开发体验。
/// <reference types="vite/client" />

13
index.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

4408
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

58
package.json Normal file
View File

@ -0,0 +1,58 @@
{
"name": "dykj",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build --force",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/",
"ts:check": "vue-tsc --noEmit"
},
"dependencies": {
"axios": "^1.7.2",
"echarts": "^5.5.0",
"element-plus": "^2.7.3",
"pinia": "^2.1.7",
"vue": "^3.4.21",
"vue-router": "^4.3.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.10",
"highlight.js": "^11.9.0"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.8.0",
"@tsconfig/node20": "^20.1.4",
"@types/node": "^20.12.5",
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^13.0.0",
"@vue/tsconfig": "^0.5.1",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.23.0",
"npm-run-all2": "^6.1.2",
"prettier": "^3.2.5",
"prettier-eslint": "^16.3.0",
"typescript": "~5.4.0",
"vite": "^5.2.8",
"vue-tsc": "^2.0.11",
"sass": "^1.69.5",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^7.1.0",
"@vitejs/plugin-legacy": "^5.3.1",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-ejs": "^1.7.0",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-progress": "^0.0.7",
"vite-plugin-purge-icons": "^0.10.0",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-top-level-await": "^1.3.1"
}
}

180
package.md Normal file
View File

@ -0,0 +1,180 @@
{
<!-- 项目名称 -->
"name": "dykj",
<!-- 项目的版本号 -->
"version": "0.0.0",
<!-- 表示这是一个私有项目不会被发布到公共npm仓库。 -->
"private": true,
<!-- 表示这是一个私有项目不会被发布到公共npm仓库。 -->
"type": "module",
"scripts": {
<!-- 运行开发服务器使用Vite作为开发环境。 -->
"dev": "vite",
<!-- 构建项目先执行类型检查然后执行构建命令。这里使用run - p可能是npm - run - all的一个别名来并行运行多个脚本。 -->
"build": "run-p type-check \"build-only {@}\" --",
<!-- 在本地预览生产构建的应用 -->
"preview": "vite preview",
<!-- 单独执行构建操作 -->
"build-only": "vite build",
<!-- 使用vue - tsc强制进行类型检查。 -->
"type-check": "vue-tsc --build --force",
<!-- lint": "eslint . --ext ...": 运行ESLint对项目进行代码规范检查并自动修复问题支持多种文件扩展名。 -->
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
<!-- 使用Prettier格式化src/目录下的所有文件。 -->
"format": "prettier --write src/"
<!--TypeScript项目提供的类型检查器。 -->
"ts:check": "vue-tsc --noEmit",
},
"dependencies": {
<!-- 状态管理库Vue中的轻量级状态管理解决方案。 -->
"pinia": "^2.1.7",
<!-- Vue框架的核心库。 -->
"vue": "^3.4.21",
<!-- Vue的路由管理库。 -->
"vue-router": "^4.3.0"
<!-- ui框架 -->
"element-plus": "^2.7.3",
<!--图表 -->
"echarts": "^5.5.0",
<!--@wangeditor/editor 及 @wangeditor/editor-for-vue: 分别是WangEditor的核心库和针对Vue的适配组件WangEditor是一个轻量级的Web富文本编辑器适用于构建需要文本编辑功能的应用。 -->
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.10"
<!-- cropperjs: 一个易用的图片裁剪JavaScript库可以在Web应用中提供图片裁剪功能。 -->
"cropperjs": "^1.6.1",
<!--代码高亮库,支持多种编程语言的语法高亮显示。 -->
"highlight.js": "^11.9.0",
},
"devDependencies": {
<!-- 一个用于修补ESLint与某些 TypeScript 工具集成时可能遇到的问题的库,版本"^1.8.0"表示兼容1.8.0及以上的版本。 -->
"@rushstack/eslint-patch": "^1.8.0",
<!-- 提供了一个针对Node.js 20版本的TS配置文件简化了TypeScript配置"^20.1.4"指定了使用的版本范围。 -->
"@tsconfig/node20": "^20.1.4",
<!-- Node.js的TypeScript类型声明文件让TypeScript能更好地理解和验证Node.js的API调用"^20.12.5"指定了版本兼容范围。 -->
"@types/node": "^20.12.5",
<!-- Vue官方提供的ESLint配置帮助遵循Vue和TypeScript的最佳实践"^9.0.0"和"^13.0.0"是各自的版本要求。 -->
"@vue/tsconfig": "^0.5.1",
<!-- 一个强大的JavaScript和TypeScript代码质量工具"^8.57.0"指定了版本。 -->
"eslint": "^8.57.0",
<!-- 为ESLint提供Vue.js相关的规则和解析器"^9.23.0"指定了版本。 -->
"eslint-plugin-vue": "^9.23.0",
<!-- 一个npm脚本任务的运行工具允许你并行或顺序执行多个脚本"^6.1.2"指定了版本。注意正式的包名为npm-run-all这里的“2”可能是笔误。 -->
"npm-run-all2": "^6.1.2",
<!-- 一个代码格式化工具,确保团队代码风格的一致性,"^3.2.5"指定了版本。 -->
"prettier": "^3.2.5",
<!-- 编程语言TypeScript的编译器提供了对JavaScript的强大类型检查和更现代的语法支持"~5.4.0"意味着使用5.4.0版本或其补丁更新版 -->
"typescript": "~5.4.0",
<!-- 一个由Vue.js作者尤雨溪开发的现代化的前端构建工具用于快速开发和优化Web应用"^5.2.8"指定了版本。 -->
"vite": "^5.2.8",
<!-- 一个专为Vue项目的TypeScript类型检查和错误报告工具"^2.0.11"指定了版本。 -->
"vue-tsc": "^2.0.11"
<!--@typescript-eslint/eslint-plugin, @typescript-eslint/parser: ESLint的插件和解析器专为TypeScript项目设计提供更准确的代码质量检查。 -->
"@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^7.1.0",
<!--@vitejs/plugin-legacy, @vitejs/plugin-vue, @vitejs/plugin-vue-jsx: Vite的官方插件分别用于支持老旧浏览器兼容、Vue和Vue JSX的编译和优化。 -->
"@vitejs/plugin-legacy": "^5.3.1",
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0",
<!--eslint, eslint-config-prettier, eslint-plugin-prettier, eslint-plugin-vue: ESLint相关依赖用于JavaScript和Vue项目的代码风格检查和格式化。 -->
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-vue": "^9.22.0",
<!--prettier, prettier-eslint: 代码格式化工具,确保代码风格统一。 -->
"prettier": "^3.2.5",
"prettier-eslint": "^16.3.0",
<!-- sass: CSS预处理器增加了变量、嵌套规则、混合、继承等特性。 -->
"sass": "^1.69.5"
<!-- vite-plugin-compression, vite-plugin-ejs, vite-plugin-eslint, vite-plugin-progress, vite-plugin-purge-icons, vite-plugin-svg-icons, vite-plugin-top-level-await: Vite的各种插件分别用于资源压缩、EJS模板支持、ESLint集成、构建进度显示、图标自动清理、SVG图标集成、顶级await支持等。 -->
"vite-plugin-compression": "^0.5.1",
"vite-plugin-ejs": "^1.7.0",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-progress": "^0.0.7",
"vite-plugin-purge-icons": "^0.10.0",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-top-level-await": "^1.3.1",
}
<!-- 行在你的项目package.json文件中表示该项目所采用的许可证类型。MIT许可是一种广泛使用的开源软件许可证它允许用户自由地使用、修改及分发软件既可用于商业目的也可以是非商业目的。该许可证对软件使用者的限制极少基本上只要求保留学术署名和免责声明即可。这意味着采纳MIT许可的项目具有很高的开放性和灵活性对于促进软件共享和协作是非常友好的。 -->
"license": "MIT",
<!-- node版本号 -->
"engines": {
"node": ">= 16.0.0",
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

85
src/App.vue Normal file
View File

@ -0,0 +1,85 @@
<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from './components/HelloWorld.vue'
</script>
<template>
<header>
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
<div class="wrapper">
<HelloWorld msg="You did it!" />
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about">About</RouterLink>
</nav>
</div>
</header>
<RouterView />
</template>
<style scoped>
header {
line-height: 1.5;
max-height: 100vh;
}
.logo {
display: block;
margin: 0 auto 2rem;
}
nav {
width: 100%;
font-size: 12px;
text-align: center;
margin-top: 2rem;
}
nav a.router-link-exact-active {
color: var(--color-text);
}
nav a.router-link-exact-active:hover {
background-color: transparent;
}
nav a {
display: inline-block;
padding: 0 1rem;
border-left: 1px solid var(--color-border);
}
nav a:first-of-type {
border: 0;
}
@media (min-width: 1024px) {
header {
display: flex;
place-items: center;
padding-right: calc(var(--section-gap) / 2);
}
.logo {
margin: 0 2rem 0 0;
}
header .wrapper {
display: flex;
place-items: flex-start;
flex-wrap: wrap;
}
nav {
text-align: left;
margin-left: -1rem;
font-size: 1rem;
padding: 1rem 0;
margin-top: 1rem;
}
}
</style>

86
src/assets/base.css Normal file
View File

@ -0,0 +1,86 @@
/* color palette from <https://github.com/vuejs/theme> */
:root {
--vt-c-white: #ffffff;
--vt-c-white-soft: #f8f8f8;
--vt-c-white-mute: #f2f2f2;
--vt-c-black: #181818;
--vt-c-black-soft: #222222;
--vt-c-black-mute: #282828;
--vt-c-indigo: #2c3e50;
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
--vt-c-text-light-1: var(--vt-c-indigo);
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
--vt-c-text-dark-1: var(--vt-c-white);
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
}
/* semantic color variables for this project */
:root {
--color-background: var(--vt-c-white);
--color-background-soft: var(--vt-c-white-soft);
--color-background-mute: var(--vt-c-white-mute);
--color-border: var(--vt-c-divider-light-2);
--color-border-hover: var(--vt-c-divider-light-1);
--color-heading: var(--vt-c-text-light-1);
--color-text: var(--vt-c-text-light-1);
--section-gap: 160px;
}
@media (prefers-color-scheme: dark) {
:root {
--color-background: var(--vt-c-black);
--color-background-soft: var(--vt-c-black-soft);
--color-background-mute: var(--vt-c-black-mute);
--color-border: var(--vt-c-divider-dark-2);
--color-border-hover: var(--vt-c-divider-dark-1);
--color-heading: var(--vt-c-text-dark-1);
--color-text: var(--vt-c-text-dark-2);
}
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
font-weight: normal;
}
body {
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
transition:
color 0.5s,
background-color 0.5s;
line-height: 1.6;
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
'Fira Sans',
'Droid Sans',
'Helvetica Neue',
sans-serif;
font-size: 15px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

1
src/assets/logo.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>

After

Width:  |  Height:  |  Size: 276 B

35
src/assets/main.css Normal file
View File

@ -0,0 +1,35 @@
@import './base.css';
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
font-weight: normal;
}
a,
.green {
text-decoration: none;
color: hsla(160, 100%, 37%, 1);
transition: 0.4s;
padding: 3px;
}
@media (hover: hover) {
a:hover {
background-color: hsla(160, 100%, 37%, 0.2);
}
}
@media (min-width: 1024px) {
body {
display: flex;
place-items: center;
}
#app {
display: grid;
grid-template-columns: 1fr 1fr;
padding: 0 2rem;
}
}

View File

@ -0,0 +1,41 @@
<script setup lang="ts">
defineProps<{
msg: string
}>()
</script>
<template>
<div class="greetings">
<h1 class="green">{{ msg }}</h1>
<h3>
Youve successfully created a project with
<a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a> +
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>. What's next?
</h3>
</div>
</template>
<style scoped>
h1 {
font-weight: 500;
font-size: 2.6rem;
position: relative;
top: -10px;
}
h3 {
font-size: 1.2rem;
}
.greetings h1,
.greetings h3 {
text-align: center;
}
@media (min-width: 1024px) {
.greetings h1,
.greetings h3 {
text-align: left;
}
}
</style>

View File

@ -0,0 +1,88 @@
<script setup lang="ts">
import WelcomeItem from './WelcomeItem.vue'
import DocumentationIcon from './icons/IconDocumentation.vue'
import ToolingIcon from './icons/IconTooling.vue'
import EcosystemIcon from './icons/IconEcosystem.vue'
import CommunityIcon from './icons/IconCommunity.vue'
import SupportIcon from './icons/IconSupport.vue'
</script>
<template>
<WelcomeItem>
<template #icon>
<DocumentationIcon />
</template>
<template #heading>Documentation</template>
Vues
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
provides you with all information you need to get started.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<ToolingIcon />
</template>
<template #heading>Tooling</template>
This project is served and bundled with
<a href="https://vitejs.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
recommended IDE setup is
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a> +
<a href="https://github.com/johnsoncodehk/volar" target="_blank" rel="noopener">Volar</a>. If
you need to test your components and web pages, check out
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a> and
<a href="https://on.cypress.io/component" target="_blank" rel="noopener"
>Cypress Component Testing</a
>.
<br />
More instructions are available in <code>README.md</code>.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<EcosystemIcon />
</template>
<template #heading>Ecosystem</template>
Get official tools and libraries for your project:
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
you need more resources, we suggest paying
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
a visit.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<CommunityIcon />
</template>
<template #heading>Community</template>
Got stuck? Ask your question on
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>, our official
Discord server, or
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
>StackOverflow</a
>. You should also subscribe to
<a href="https://news.vuejs.org" target="_blank" rel="noopener">our mailing list</a> and follow
the official
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
twitter account for latest news in the Vue world.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<SupportIcon />
</template>
<template #heading>Support Vue</template>
As an independent project, Vue relies on community backing for its sustainability. You can help
us by
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
</WelcomeItem>
</template>

View File

@ -0,0 +1,87 @@
<template>
<div class="item">
<i>
<slot name="icon"></slot>
</i>
<div class="details">
<h3>
<slot name="heading"></slot>
</h3>
<slot></slot>
</div>
</div>
</template>
<style scoped>
.item {
margin-top: 2rem;
display: flex;
position: relative;
}
.details {
flex: 1;
margin-left: 1rem;
}
i {
display: flex;
place-items: center;
place-content: center;
width: 32px;
height: 32px;
color: var(--color-text);
}
h3 {
font-size: 1.2rem;
font-weight: 500;
margin-bottom: 0.4rem;
color: var(--color-heading);
}
@media (min-width: 1024px) {
.item {
margin-top: 0;
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
}
i {
top: calc(50% - 25px);
left: -26px;
position: absolute;
border: 1px solid var(--color-border);
background: var(--color-background);
border-radius: 8px;
width: 50px;
height: 50px;
}
.item:before {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
bottom: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:after {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
top: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:first-of-type:before {
display: none;
}
.item:last-of-type:after {
display: none;
}
}
</style>

View File

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
/>
</svg>
</template>

View File

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
<path
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
/>
</svg>
</template>

View File

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
<path
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
/>
</svg>
</template>

View File

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
/>
</svg>
</template>

View File

@ -0,0 +1,19 @@
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
aria-hidden="true"
role="img"
class="iconify iconify--mdi"
width="24"
height="24"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 24 24"
>
<path
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
fill="currentColor"
></path>
</svg>
</template>

14
src/main.ts Normal file
View File

@ -0,0 +1,14 @@
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')

23
src/router/index.ts Normal file
View File

@ -0,0 +1,23 @@
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('../views/AboutView.vue')
}
]
})
export default router

12
src/stores/counter.ts Normal file
View File

@ -0,0 +1,12 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})

15
src/views/AboutView.vue Normal file
View File

@ -0,0 +1,15 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<style>
@media (min-width: 1024px) {
.about {
min-height: 100vh;
display: flex;
align-items: center;
}
}
</style>

9
src/views/HomeView.vue Normal file
View File

@ -0,0 +1,9 @@
<script setup lang="ts">
import TheWelcome from '../components/TheWelcome.vue'
</script>
<template>
<main>
<TheWelcome />
</main>
</template>

89
tsconfig.json Normal file
View File

@ -0,0 +1,89 @@
{
// TypeScript
"compilerOptions": {
// ECMAScriptDOM APIDOMscripthost API
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
],
// ECMAScript
"target": "esnext",
// libJavaScript
"outDir": "lib",
// .d.ts
"declaration": true,
// 使ES
"module": "esnext",
// 使Node.js
"moduleResolution": "node",
//
"isolatedModules": false,
//
"experimentalDecorators": true,
//CommonJSES
"esModuleInterop": true,
//strictNullChecksnullundefined
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": false,
//
"removeComments": true,
//any?
"suppressImplicitAnyIndexErrors": false,
//
"allowSyntheticDefaultImports": true,
//JSON
"resolveJsonModule": true,
//JavaScript
"allowJs": true,
//JSXReact
"jsx": "preserve",
//
"baseUrl": "./",
//便@src/*src/*
"paths": {
//
"@src/*": [
"src/*"
],
//
"tdesign-vue-next": [
"src"
],
//
"tdesign-vue-next/es/locale/*": [
"src/locale/*"
],
//
"@common/*": [
"src/_common/*"
],
//
"@test/utils": [
"test/utils"
]
}
},
//
"include": [
"./**/*.ts",
"./**/*.tsx",
"src/**/*.vue",
"scripts/rollup.config.js"
],
//node_modules
"exclude": [
"node_modules",
"src/_common",
"dist",
"lib",
"cjs",
"esm",
"es",
"global.d.ts"
],
//
"compileOnSave": false
}

22
vite.config.ts Normal file
View File

@ -0,0 +1,22 @@
// 这部分从Node.js的内置模块导入了两个函数fileURLToPath 和 URL。它们主要用于处理文件路径和URL之间的转换这对于Vite配置中的别名功能特别有用。
import { fileURLToPath, URL } from 'node:url'
// 这里导入了Vite的defineConfig函数以及Vue和Vue JSX的插件。
import { defineConfig } from 'vite'
//
import vue from '@vitejs/plugin-vue'
//
import vueJsx from '@vitejs/plugin-vue-jsx'
// 通过defineConfig函数定义配置对象并在其plugins属性中添加了之前导入的Vue和Vue JSX插件。这两个插件会在Vite启动时自动应用到项目中使得Vue和Vue JSX的功能得以实现
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
vueJsx(),
],
resolve: {
// 通过alias属性设置了一个路径别名。在这里@符号被映射到了项目源码目录src的绝对路径。这样做可以让开发者在导入模块时使用更简短的路径
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})