第一步开始安装:
1
2
|
pnpm create vite vue3-ts-vite-pinia-element-plus-pnpm --template vue-ts
ERROR No package.json (or package.yaml, or package.json5) was found in "/home/xfhuang/workspace/node".
|
安装 pnpm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
pc wget -qO- https://get.pnpm.io/install.sh | pc sh -
==> Downloading pnpm binaries 8.1.1
WARN using --force I sure hope you know what you are doing
Copying pnpm CLI from /tmp/tmp.SJzIHrlcoP/pnpm to /home/xfhuang/.local/share/pnpm/pnpm
Appended new lines to /home/xfhuang/.zshrc
Next configuration changes were made:
export PNPM_HOME="/home/xfhuang/.local/share/pnpm"
case ":$PATH:" in
*":$PNPM_HOME:"*) ;;
*) export PATH="$PNPM_HOME:$PATH" ;;
esac
To start using pnpm, run:
source /home/xfhuang/.zshrc
[Tue Apr 04 2023 11:02AM (CST+0800)] [1 day, 57 min] :~/workspace/node via v16.15.0 took 35s
🌈 source /home/xfhuang/.zshrc
Seems robbyrussell/oh-my-zsh is already installed!
Seems zsh-users/zsh-syntax-highlighting is already installed!
Seems zsh-users/zsh-autosuggestions is already installed!
Seems zsh-users/zsh-completions is already installed!
Seems robbyrussell/oh-my-zsh is already installed!
Seems robbyrussell/oh-my-zsh is already installed!
Seems robbyrussell/oh-my-zsh is already installed!
Seems robbyrussell/oh-my-zsh is already installed!
Seems robbyrussell/oh-my-zsh is already installed!
Seems robbyrussell/oh-my-zsh is already installed!
Seems paulirish/git-open is already installed!
Seems robbyrussell/oh-my-zsh is already installed!
Seems robbyrussell/oh-my-zsh is already installed!
Seems zsh-users/zsh-syntax-highlighting is already installed!
Seems zsh-users/zsh-autosuggestions is already installed!
Seems zsh-users/zsh-completions is already installed!
Seems robbyrussell/oh-my-zsh is already installed!
λ ls -all
rwxr-xr-x 18 xfhuang xfhuang 4 KiB Tue Apr 4 10:54:23 2023 ./
rwxr-xr-x 11 xfhuang xfhuang 4 KiB Tue Mar 21 14:28:56 2023 ../
rwxr-xr-x 8 xfhuang xfhuang 4 KiB Wed Jul 6 17:34:29 2022 cloud-disk-ui/
rwxr-xr-x 8 xfhuang xfhuang 4 KiB Fri Aug 12 09:50:47 2022 education-cloud-web-admin/
rwxr-xr-x 17 xfhuang xfhuang 4 KiB Thu Jul 21 11:13:15 2022 education-cloud-web-ui/
rwxr-xr-x 6 xfhuang xfhuang 4 KiB Mon Apr 3 13:48:52 2023 icMedia/
rwxr-xr-x 3 xfhuang xfhuang 4 KiB Fri Oct 21 15:00:55 2022 kubegems-dashboard/
rwxr-xr-x 6 xfhuang xfhuang 4 KiB Wed Aug 31 14:48:52 2022 mini-gde-frontend/
rwxr-xr-x 6 xfhuang xfhuang 4 KiB Wed Aug 31 09:43:43 2022 mynode/
rwxr-xr-x 3 xfhuang xfhuang 4 KiB Tue Oct 11 13:19:46 2022 nestjs/
rwxr-xr-x 5 xfhuang xfhuang 4 KiB Mon Oct 17 13:24:09 2022 Node全栈项目开源/
rw-r--r-- 1 xfhuang xfhuang 3 B Tue Apr 4 10:54:23 2023 package.json
rw-r--r-- 1 xfhuang xfhuang 83 B Tue Apr 4 10:54:23 2023 package-lock.json
rw-r--r-- 1 xfhuang xfhuang 1 KiB Tue Apr 4 11:07:03 2023 .pnpm-debug.log
rwxr-xr-x 3 xfhuang xfhuang 4 KiB Thu Feb 2 12:29:52 2023 sample-app/
rwxr-xr-x 12 xfhuang xfhuang 4 KiB Tue Oct 11 10:28:16 2022 sf-midway-admin/
rwxr-xr-x 8 xfhuang xfhuang 4 KiB Tue Oct 11 13:35:15 2022 sf-vue-admin/
rwxr-xr-x 3 xfhuang xfhuang 4 KiB Tue Oct 11 11:29:41 2022 v2/
rwxr-xr-x 4 xfhuang xfhuang 4 KiB Tue Jan 17 09:02:07 2023 vue3/
rwxr-xr-x 8 xfhuang xfhuang 4 KiB Fri Feb 24 09:05:09 2023 vue3.0-template-admin/
rwxr-xr-x 6 xfhuang xfhuang 4 KiB Fri Feb 24 09:05:30 2023 vue3-element-admin/
[Tue Apr 04 2023 11:08AM (CST+0800)] [1 day, 1:03] :~/workspace/node via v16.15.0
🌈 rm -rf package.json
[Tue Apr 04 2023 11:08AM (CST+0800)] [1 day, 1:04] :~/workspace/node
🌈 rm -rf package-lock.json
[Tue Apr 04 2023 11:08AM (CST+0800)] [1 day, 1:04] :~/workspace/node
🌈 rm -rf .pnpm-debug.log
[Tue Apr 04 2023 11:14AM (CST+0800)] [1 day, 1:09] :~/workspace/node took 1s
🌈 pnpm create vite vue3-ts-vite-pinia-element-plus-pnpm --template vue-ts
.../share/pnpm/store/v3/tmp/dlx-310038 | +1 +
Packages are hard linked from the content-addressable store to the virtual store.
Content-addressable store is at: /home/xfhuang/.local/share/pnpm/store/v3
Virtual store is at: ../../.local/share/pnpm/store/v3/tmp/dlx-310038/node_modules/.pnpm
.../share/pnpm/store/v3/tmp/dlx-310038 | Progress: resolved 1, reused 0, downloaded 1, added 1, done
Scaffolding project in /home/xfhuang/workspace/node/vue3-ts-vite-pinia-element-plus-pnpm...
Done. Now run:
cd vue3-ts-vite-pinia-element-plus-pnpm
pnpm install
pnpm run dev
|
接下来操作运行看看
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
🌈 cd vue3-ts-vite-pinia-element-plus-pnpm
pnpm install
pnpm run dev
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
Packages: +50
++++++++++++++++++++++++++++++++++++++++++++++++++
Packages are copied from the content-addressable store to the virtual store.
Content-addressable store is at: /home/xfhuang/.local/share/pnpm/store/v3
Virtual store is at: node_modules/.pnpm
Downloading registry.npmmirror.com/typescript/4.9.3: 11.6 MB/11.6 MB, done
node_modules/.pnpm/registry.npmmirror.com+esbuild@0.17.15/node_modules/esbuild: Running postinstall script, done in 54ms
Progress: resolved 72, reused 0, downloaded 50, added 50, done
dependencies:
+ vue 3.2.47
devDependencies:
+ @vitejs/plugin-vue 4.1.0
+ typescript 4.9.3 (5.0.3 is available)
+ vite 4.2.0 (4.2.1 is available)
+ vue-tsc 1.2.0
Done in 4.4s
> vue3-ts-vite-pinia-element-plus-pnpm@0.0.0 dev /home/xfhuang/workspace/node/vue3-ts-vite-pinia-element-plus-pnpm
> vite
VITE v4.2.0 ready in 241 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h to show help
|
点开浏览器可以看到界面即可。
必要依赖安装
element-plus
命令: pnpm install element-plus
执行:
1
2
3
4
5
6
7
8
9
10
11
12
|
λ pnpm install element-plus
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
Packages: +21
+++++++++++++++++++++
Downloading registry.npmmirror.com/element-plus/2.3.2: 7.94 MB/7.94 MB, done
node_modules/.pnpm/registry.npmmirror.com+vue-demi@0.13.11_vue@3.2.47/node_modules/vue-demi: Running postinstall script, done in 83ms
Progress: resolved 93, reused 50, downloaded 21, added 21, done
dependencies:
+ element-plus 2.3.2
Done in 6.6s
|
@element-plus/icons-vue
命令: pnpm install @element-plus/icons-vue
执行:
1
2
3
4
5
6
7
8
9
|
pnpm install @element-plus/icons-vue
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
Already up to date
dependencies:
+ @element-plus/icons-vue 2.1.0
Progress: resolved 93, reused 71, downloaded 0, added 0, done
Done in 1.2s
|
axios
命令: pnpm install axios
执行:
1
2
3
4
5
6
7
8
9
10
|
pnpm install axios
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
Packages: +9
+++++++++
Progress: resolved 102, reused 71, downloaded 9, added 9, done
dependencies:
+ axios 1.3.4
Done in 1.7s
|
pinia
命令: pnpm install pinia
执行:
1
2
3
4
5
6
7
8
9
10
|
pnpm install pinia
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
Packages: +2
++
Progress: resolved 104, reused 80, downloaded 2, added 2, done
dependencies:
+ pinia 2.0.33
Done in 1.6s
|
vue-router
命令: pnpm install vue-router
执行:
1
2
3
4
5
6
7
8
9
10
|
pnpm install vue-router
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
Packages: +1
+
Progress: resolved 105, reused 82, downloaded 1, added 1, done
dependencies:
+ vue-router 4.1.6
Done in 1.5s
|
sass
命令: pnpm install -D sass
执行:
1
2
3
4
5
6
7
8
9
10
|
pnpm install -D sass
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
Packages: +17 -1
+++++++++++++++++-
Progress: resolved 121, reused 83, downloaded 16, added 17, done
devDependencies:
+ sass 1.60.0
Done in 2.3s
|
eslint
命令:pnpm install -D eslint
执行:
1
2
3
4
5
6
7
8
9
10
|
pnpm install -D eslint
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
Packages: +94
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 215, reused 99, downloaded 94, added 94, done
devDependencies:
+ eslint 8.37.0
Done in 3.8s
|
Next:
-
使用 eslint 自动进行配置
命令:./node_modules/.bin/eslint --init
执行:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
----------------------------------- Questions ----------------------------------------
$ ./node_modules/.bin/eslint --init
You can also run this command directly using 'npm init @eslint/config'.
npx: 40 安装成功,用时 3.22 秒
1.
? How would you like to use ESLint? ...
To check syntax only
To check syntax and find problems
> To check syntax, find problems, and enforce code style
2.
? What type of modules does your project use? ...
> JavaScript modules (import/export)
CommonJS (require/exports)
None of these
3.
? Which framework does your project use? ...
React
> Vue.js
None of these
4.
? Does your project use TypeScript? » No / >Yes
5.
? Where does your code run? ... (Press <space> to select, <a> to toggle all, <i> to invert selection)
> √ Browser
√ Node
6.
? How would you like to define a style for your project? ...
> Use a popular style guide
Answer questions about your style
7.
? Which style guide do you want to follow? ...
> Standard: https://github.com/standard/eslint-config-standard-with-typescript
XO: https://github.com/xojs/eslint-config-xo-typescript
8.
? What format do you want your config file to be in? ...
> JavaScript
YAML
JSON
Checking peerDependencies of eslint-config-standard-with-typescript@latest
The config that you've selected requires the following dependencies:
eslint-plugin-vue@latest eslint-config-standard-with-typescript@latest @typescript-eslint/eslint-plugin@^5.0.0 eslint@^8.0.1 eslint-plugin-import@^2.25.2 eslint-plugin-n@^15.0.0 eslint-plugin-promise@^6.0.0 typescript@*
9.
? Would you like to install them now? » No / > Yes
10.
? Which package manager do you want to use? ...
npm
yarn
> pnpm
----------------------------------- Result -------------------------------------
$ ./node_modules/.bin/eslint --init
You can also run this command directly using 'npm init @eslint/config'.
npx: 40 安装成功,用时 3.22 秒
√ How would you like to use ESLint? · style
√ What type of modules does your project use? · esm
√ Which framework does your project use? · vue
√ Does your project use TypeScript? · No / Yes
√ Where does your code run? · browser
√ How would you like to define a style for your project? · guide
√ Which style guide do you want to follow? · standard-with-typescript
√ What format do you want your config file to be in? · JavaScript
Checking peerDependencies of eslint-config-standard-with-typescript@latest
The config that you've selected requires the following dependencies:
eslint-plugin-vue@latest eslint-config-standard-with-typescript@latest @typescript-eslint/eslint-plugin@^5.0.0 eslint@^8.0.1 eslint-plugin-import@^2.25.2 eslint-plugin-n@^15.0.0 eslint-plugin-promise@^6.0.0 typescript@*
√ Would you like to install them now? · No / Yes
√ Which package manager do you want to use? · pnpm
Installing eslint-plugin-vue@latest, eslint-config-standard-with-typescript@latest, @typescript-eslint/eslint-plugin@^5.0.0, eslint@^8.0.1, eslint-plugin-import@^2.25.2, eslint-plugin-n@^15.0.0, eslint-plugin-promise@^6.0.0, typescript@*
Already up-to-date
Progress: resolved 298, reused 277, downloaded 0, added 0, done
Successfully created .eslintrc.cjs file in F:\Web\Vue\vue3-ts-vite-pinia-element-plus-pnpm
|
result:
-
检查项目目录出现 .eslintrc.cjs 文件
-
检查 package.json,出现一堆 eslint 相关依赖
-
1
2
3
4
5
|
"@typescript-eslint/eslint-plugin": "^5.57.1",
"@typescript-eslint/parser": "^5.57.1",
"@vitejs/plugin-vue": "^4.1.0",
"eslint": "^8.37.0",
"eslint-plugin-vue": "^9.10.0",
|
prettier
命令: pnpm install -D --save-exact prettier
执行:
1
2
3
4
5
6
7
8
9
10
|
pnpm install -D --save-exact prettier
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
Packages: +1
+
Progress: resolved 250, reused 227, downloaded 1, added 1, done
devDependencies:
+ prettier 2.8.7
Done in 2.2s
|
Next:
-
创建空的配置文件:echo {}> .prettierrc.json
-
创建 prettier 格式化忽略配置文件:.prettierignore
-
在 .prettierignore 文件中添加如下初始配置
-
1
2
3
|
# Ignore artifacts:
build
coverage
|
格式化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
🌈 npx prettier --write .
.eslintrc.cjs 44ms
.prettierrc.json 3ms
.vscode/extensions.json 2ms
index.html 37ms
package.json 3ms
pnpm-lock.yaml 379ms
README.md 41ms
src/App.vue 168ms
src/components/HelloWorld.vue 26ms
src/main.ts 6ms
src/style.css 13ms
src/vite-env.d.ts 5ms
tsconfig.json 4ms
tsconfig.node.json 1ms
vite.config.ts 5ms
|
安装 hook
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
λ pnpm install -D husky lint-staged
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
Packages: +55
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 305, reused 228, downloaded 55, added 55, done
devDependencies:
+ husky 8.0.3
+ lint-staged 13.2.0
Done in 4.1s
[Tue Apr 04 2023 12:46PM (CST+0800)] [1 day, 2:42] :~/workspace/node/vue3-ts-vite-pinia-element-plus-pnpm via v19.8.1 took 4s
🌈 npx husky install
fatal: not a git repository (or any of the parent directories): .git
husky - git command not found, skipping install
[Tue Apr 04 2023 12:46PM (CST+0800)] [1 day, 2:42] :~/workspace/node/vue3-ts-vite-pinia-element-plus-pnpm via v19.8.1
🌈 git init
Initialized empty Git repository in /home/xfhuang/workspace/node/vue3-ts-vite-pinia-element-plus-pnpm/.git/
[Tue Apr 04 2023 12:46PM (CST+0800)] [1 day, 2:42] :~/workspace/node/vue3-ts-vite-pinia-element-plus-pnpm 🍣 main 🛤️ ×14via v19.8.1
🌈 npx husky install
husky - Git hooks installed
[Tue Apr 04 2023 12:46PM (CST+0800)] [1 day, 2:42] :~/workspace/node/vue3-ts-vite-pinia-element-plus-pnpm 🍣 main 🛤️ ×14via v19.8.1
🌈 npm set-script prepare "husky install"
Unknown command: "set-script"
Did you mean this?
npm run-script # Run arbitrary package scripts
To see a list of supported npm commands, run:
npm help
[1 - ERROR] [Tue Apr 04 2023 12:47PM (CST+0800)] [1 day, 2:42] :~/workspace/node/vue3-ts-vite-pinia-element-plus-pnpm 🍣 main 🛤️ ×14via v19.8.1
λ pnpm set-script prepare "husky install"
Unknown command: "set-script"
Did you mean this?
npm run-script # Run arbitrary package scripts
To see a list of supported npm commands, run:
npm help
[1 - ERROR] [Tue Apr 04 2023 12:47PM (CST+0800)] [1 day, 2:43] :~/workspace/node/vue3-ts-vite-pinia-element-plus-pnpm 🍣 main 🛤️ ×14via v19.8.1
λ npm set-script prepare "husky install"
Unknown command: "set-script"
Did you mean this?
npm run-script # Run arbitrary package scripts
To see a list of supported npm commands, run:
npm help
[1 - ERROR] [Tue Apr 04 2023 12:51PM (CST+0800)] [1 day, 2:46] :~/workspace/node/vue3-ts-vite-pinia-element-plus-pnpm 🍣 main 🛤️ ×14via v19.8.1
λ code .
[Tue Apr 04 2023 12:51PM (CST+0800)] [1 day, 2:46] :~/workspace/node/vue3-ts-vite-pinia-element-plus-pnpm 🍣 main 🛤️ ×14via v19.8.1 took 1s
🌈 npm set-script prepare "husky install"
Unknown command: "set-script"
Did you mean this?
npm run-script # Run arbitrary package scripts
To see a list of supported npm commands, run:
npm help
[1 - ERROR] [Tue Apr 04 2023 12:54PM (CST+0800)] [1 day, 2:49] :~/workspace/node/vue3-ts-vite-pinia-element-plus-pnpm 🍣 main 🛤️ ×14via v19.8.1
λ npm pkg set scripts.prepare="husky install"
[Tue Apr 04 2023 12:56PM (CST+0800)] [1 day, 2:52] :~/workspace/node/vue3-ts-vite-pinia-element-plus-pnpm 🍣 main 🛤️ ×14via v19.8.1
🌈 npx husky add .husky/pre-commit "npx lint-staged"
husky - created .husky/pre-commit
|

eslint-config-prettier
命令: pnpm install -D eslint-config-prettier
执行:
1
2
3
4
5
6
7
8
9
10
|
pnpm install -D eslint-config-prettier
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
Packages: +1
+
Progress: resolved 306, reused 283, downloaded 1, added 1, done
devDependencies:
+ eslint-config-prettier 8.8.0
Done in 3.1s
|
添加 prettier

@types/node
命令: pnpm install -D @types/node
执行:
1
2
3
4
5
6
7
8
9
10
|
pnpm install -D @types/node
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
Packages: +2 -1
++-
Progress: resolved 307, reused 284, downloaded 1, added 2, done
devDependencies:
+ @types/node 18.15.11
Done in 2.5s
|
备注:此依赖是 node 中的类型定义,在后面对于一些配置信息时需要使用 node 中的方法时,没有引入此依赖就会提示安装。
3. 基础配置
1. 添加环境变量配置文件
1. 根据 <开发版本> | <预发行版> | <生产版本> 创建单独的 .env 文件
- .env : 基本配置项
- .env.development : 开发环境配置项
- .env.staging : 预发布版本配置项
- .env.production : 生产环境配置项
1
2
|
# windows 批处理命令(在项目根目录cmd窗运行下面命令即可生成上述四个文件):
echo '# DEFAULT ENV'> .env;echo '# DEVELOPMENT ENV'> .env.development;echo '# STAGING DEV'> .env.staging;echo '# PRODUCTION ENV'> .env.production
|
修改.env 文件
1
2
3
4
5
6
7
8
9
10
|
# DEFAULT ENV
# 项目标题
VITE_APP_TITLE = 'My App'
# 项目运行端口
VITE_PORT = '3000'
# 项目启动后自动打开默认浏览器
VITE_OPEN = 'true'
|
2. 修改 vite 配置文件 vite.config.js
- 设置模块引入路径别名 "@"
首先需要在 vite.config.js 添加别名和对应的路径信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path';
// https://vitejs.dev/config/
export default defineConfig(({command, mode}) => {
return {
resolve:{
alias: {
"@": resolve(__dirname, "./src")
}
},
plugins: [vue()]
}
})
|
然后在 tsconfig.json 文件中添加别名的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"noEmit": true,
//add
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}
|
- 将 env 文件中定义的配置添加到 vite 配置信息中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
export default defineConfig(({command, mode}) => {
const env = loadEnv(mode, process.cwd(), '');
return {
resolve:{
alias: {
"@": resolve(__dirname, "./src")
}
},
server:{
port: env.VITE_PORT, // 注意此时ts会提示VITE_PORT类型不符合
open: env.VITE_OPEN
},
plugins: [vue()]
}
})
|
由于 ts 无法识别.env 中的配置信息的类型,默认都是 string 类型,所以需要添加类型声明文件
按照文档中提示,在项目的 src 目录下创建 env.d.ts 文件,由于创建项目的时候,已经自动在目录下生成了 vite-env.d.ts,所以直接在此文件下添加,如果没有该文件,手动创建。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/// <reference types="vite/client" />
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
// +++
// * Vite Env 返回数据类型
declare type Recordable<T = any> = Record<string, T>;
interface ViteEnv {
readonly VITE_APP_TITLE: string;
readonly VITE_PORT: number;
readonly VITE_OPEN: boolean;
// 更多环境变量...
}
interface ImportMeta {
readonly env: ViteEnv
}
// +++
|
添加了上面的信息后,回到 vite.config.ts 中,依然提示上面类型问题,所以此处写一个转换函数,将结果输出为我们定义的类型
在 src 目录下创建 utils 目录,然后创建 getEnv.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import fs from "fs";
import path from "path";
// 在 .env 文件中读取配置信息,并转换为 vite-env.d.ts 文件中声明类型的值
export function wrapperEnv(env: Recordable): ViteEnv {
const ret: any = {};
for (const envName of Object.keys(env)) {
let envValue = env[envName].replace(/\\n/g, "\n");
envValue = envValue === "true" ? true : envValue === "false" ? false : envValue;
if (envName === "VITE_PORT") {
envValue = Number(envValue);
}
ret[envName] = envValue;
process.env[envName] = envValue;
}
return ret;
}
|
添加了上面内容后,发现在 vite.config.ts 中无法引入此 wrapperEnv 函数,ts 无法自动识别并提示,同时手动添加导入信息会提示
其作用是可以将程序分割为更小的模块,然后统一进行管理和编译,因为我并不了解所以具体内容自行查阅, 而此处主要使用用于对 node 环境下,运行的 vite.config.ts 进行的配置,在文件中填写包含的文件即创建的 getEnv.ts,就可以在 vite.config.ts 中正常的引入 getEnv 函数了,同时也可以自动导入函数。例如在 tsonfig.node.json 中添加 src/utils/getEnv.ts
1
2
3
4
5
6
7
8
9
|
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts","src/utils/getEnv.ts"]
}
|
修改后的 vite.config.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path';
import { wrapperEnv } from './src/utils/getEnv';
// https://vitejs.dev/config/
export default defineConfig(({command, mode}) => {
const env = loadEnv(mode, process.cwd(), '');
const viteEnv = wrapperEnv(env);
return {
resolve:{
alias: {
"@": resolve(__dirname, "./src")
}
},
server:{
port: viteEnv.VITE_PORT,
open: viteEnv.VITE_OPEN
},
plugins: [vue()]
}
})
|
运行 npm run dev 既可以看到 localhost:3000
4. 配置 element-plus
-
全局注册 element-plus 组件(因为我现在并不是很在乎打包大小) 

- 将 element-plus 组件默认语言设置为中文简体

- 将 element 的 icon 组件全局注册

代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import 'element-plus/dist/index.css'
import './style.css'
import App from './App.vue'
const app = createApp(App)
// 注册 Element-Plus
app.use(ElementPlus, {
locale: zhCn
})
// 注册 Element-Plus Icon 组件
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.mount('#app')
|
按需引入(本项目使用此方式)
自动导入要使用的组件,首先需求安装 unplugin-vue-components 和 unplugin-auto-import 这两个插件
1
2
3
4
5
6
7
8
9
10
11
|
🌈 pnpm install -D unplugin-vue-components unplugin-auto-import
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
Packages: +21
+++++++++++++++++++++
Progress: resolved 328, reused 285, downloaded 21, added 21, done
devDependencies:
+ unplugin-auto-import 0.15.2
+ unplugin-vue-components 0.24.1
Done in 3.1s
|
再 vite.config.ts 中配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path';
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { wrapperEnv } from './src/utils/getEnv';
// https://vitejs.dev/config/
export default defineConfig(({command, mode}) => {
const env = loadEnv(mode, process.cwd(), '');
const viteEnv = wrapperEnv(env);
return {
resolve:{
alias: {
"@": resolve(__dirname, "./src")
}
},
server:{
port: viteEnv.VITE_PORT,
open: viteEnv.VITE_OPEN
},
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
]
}
})
|
使用 svg 图标
Element Plus 图标库有时满足不了实际开发需求,可以引用和使用第三方图标库,例如 iconfont,这里介绍下通过 vite-plugin-svg-icons 插件如何使用第三方图标库。
安装 vite-plugin-svg-icons
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
pnpm install vite-plugin-svg-icons -D
WARN deprecated stable@0.1.8: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility
WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated
WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
Packages: +147
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 475, reused 306, downloaded 147, added 147, done
devDependencies:
+ vite-plugin-svg-icons 2.0.1
Done in 4.8s
|
vite.config.ts 中配置插件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path';
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import { wrapperEnv } from './src/utils/getEnv';
// https://vitejs.dev/config/
export default defineConfig(({command, mode}) => {
const env = loadEnv(mode, process.cwd(), '');
const viteEnv = wrapperEnv(env);
const root = process.cwd()
return {
resolve:{
alias: {
"@": resolve(__dirname, "./src")
}
},
server:{
port: viteEnv.VITE_PORT,
open: viteEnv.VITE_OPEN
},
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [resolve(root, 'src/assets/icons')],
// 指定symbolId格式
symbolId: 'icon-[dir]-[name]',
})
]
}
})
|
在 main.ts 中引入注册脚本
1
2
|
// src/main.ts
import 'virtual:svg-icons-register'
|
新建图标文件夹
创建 src/assets/icons 文件夹,存放 svg 图标

TypeScript 支持
1
2
3
4
5
6
|
// tsconfig.json
{
"compilerOptions": {
"types": ["vite-plugin-svg-icons/client"]
}
}
|
封装组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
<!-- src\components\SvgIcon.vue -->
<template>
<svg aria-hidden="true" class="svg-icon">
<use :xlink:href="symbolId" :fill="color" />
</svg>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
const props = defineProps({
prefix: {
type: String,
default: 'icon'
},
iconClass: {
type: String,
required: true
},
color: {
type: String,
default: ''
}
})
const symbolId = computed(() => `#${props.prefix}-${props.iconClass}`)
</script>
<style lang="scss" scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
overflow: hidden;
fill: currentColor;
}
</style>
|
展示效果如下:

集成 Vue Router
安装 vue-router
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
pnpm install vue-router@next
WARN deprecated stable@0.1.8: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated
WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
Packages: +1 -1
+-
Progress: resolved 475, reused 452, downloaded 1, added 1, done
dependencies:
- vue-router 4.1.6
+ vue-router 4.0.13 (4.1.6 is available)
Done in 2.9s
|
新建 src/router/index.ts 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// src/router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import Index from "@/views/Index.vue"
import HomeVue from "@/views/User.vue"
const routes: Array<RouteRecordRaw> = [
// {
// path: '/',
// name: 'home',
// component: () => import('@/views/layout/index.vue')
// }
{ path: '/', component: HomeVue },
{ path: '/about', component: Index },
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
|
在 main.ts 文件中挂载路由配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import 'element-plus/dist/index.css'
import './style.css'
import App from './App.vue'
import 'virtual:svg-icons-register'
import router from '@/router/index'
const app = createApp(App);
app.use(router)
// 注册 Element-Plus
app.use(ElementPlus, {
locale: zhCn,
});
// 注册 Element-Plus Icon 组件
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.mount('#app');
|
使用 router-view 修改 App.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
<script setup lang="ts">
import HelloWorld from "./components/HelloWorld.vue";
</script>
<template>
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo" />
</a>
<a href="https://vuejs.org/" target="_blank">
<img src="./assets/icons/vue.svg" class="logo vue" alt="Vue logo" />
</a>
</div>
<!-- <HelloWorld msg="Vite + Vue" />
<Index />
<User /> -->
<RouterLink to="/">Home</RouterLink>
<br/>
<RouterLink to="/about">About</RouterLink>
<router-view/>
</template>
<style scoped>
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}
</style>
|
这样才能使用 router
集成 Pinia
Pinia 是 Vue.js 的轻量级状态管理库,Vuex 的替代方案。
1
2
3
4
5
6
7
8
9
10
|
// src/main.ts
// 安装后导入
import { createPinia } from 'pinia'
// 创建 pinia 实例
const pinia = createPinia()
// 挂载
app.use(pinia)
|
pinia 模块封装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// src/store/modules/user.ts
import { defineStore } from 'pinia'
const useUserStore = defineStore({
id: 'user',
state: () => ({
count: 0,
}),
getters: {
double: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
},
},
})
export default useUserStore
|
view 创建 User
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<script setup lang="ts">
import useStore from '@/store'
const { user } = useStore()
</script>
<template>
<div>count: {{ user.count }}</div>
<div>double: {{ user.double }}</div>
<el-button @click="user.increment">add+</el-button>
</template>
<style scoped></style>
|
显示效果

八、集成 Axios
①、安装 axios
1
2
3
4
5
6
7
8
9
10
|
pnpm install axios
WARN deprecated stable@0.1.8: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility
WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated
WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
Already up to date
Progress: resolved 475, reused 453, downloaded 0, added 0, done
Done in 2.4s
|
axios 封装
在 src 目录下创建 utils 目录存储日常工具函数等,axios 作为 HTTP 工具,我们创建 http.ts 作为 axios 配置文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
// src/utils/http.ts
import { useRouter } from 'vue-router'
import Axios, { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
import { ResponseData } from '@/types/ResponseData'
import { ElMessage } from 'element-plus'
const router = useRouter()
// 创建 axios 实例
const axios = Axios.create({
// API 请求的默认前缀
baseURL: import.meta.env.VITE_API_BASE_URL,
// 请求超时时间
timeout: 20000,
headers: { 'Content-Type': 'application/json;charset=utf-8' }
})
// 前置拦截器 发起请求之前的拦截
axios.interceptors.request.use(
async (config: AxiosRequestConfig) => {
return config
},
(error) => {
return Promise.reject(error)
}
)
/**
* 异常拦截处理器
* @param {*} error
*/
const errorHandler = (error: AxiosError) => {
// 判断是否是响应错误信息
if (error.response) {
if (error.response.status == 401) {
ElMessage.error('登录已过期,请您重新登录!')
localStorage.clear()
router.push('/login')
} else if (error.response.status == 405) {
ElMessage.error('您没有此功能的操作权限!')
}
}
return Promise.reject(error)
}
// 后置拦截器 获取到响应时的拦截
axios.interceptors.response.use((response: AxiosResponse<ResponseData>) => {
return response.data
}, errorHandler)
export default axios
/**
* GET 请求
* @param url
* @param config
* @returns
*/
export const get = <T = any, R = ResponseData<T>>(
url: string,
config?: AxiosRequestConfig
): Promise<R> => {
return axios.get(url, config)
}
/**
* POST 请求
* @param url
* @param data
* @param config
* @returns
*/
export const post = <T = any, R = ResponseData<T>>(
url: string,
data?: any,
config?: AxiosRequestConfig
): Promise<R> => {
return axios.post(url, data, config)
}
/**
* delete 删除
* @param url
* @param config
* @returns
*/
export const deleteHttp = <T = any, R = ResponseData<T>>(
url: string,
config?: AxiosRequestConfig
): Promise<R> => {
return axios.delete(url, config)
}
/**
* put
* @param url
* @param data
* @param config
* @returns
*/
export const put = <T = any, R = ResponseData<T>>(
url: string,
data?: any,
config?: AxiosRequestConfig
): Promise<R> => {
return axios.put(url, data, config)
}
|
创建 ts 文件,传入泛型 T 声明返回数据类型
1
2
3
4
5
6
|
// src/types/ResponseData.ts
export interface ResponseData<T = any> {
code: number
message: string
data: T
}
|
API 封装
1
2
3
4
5
6
7
8
|
// src/api/auth/login.ts
import { post } from '@/utils/http'
import { TokenData, LoginParams } from '@/types/Auth'
// 登录服务接口
export const ServeLogin = (data: LoginParams) => {
return post<TokenData>('/api/v1/auth/login', data)
}
|
新建文件 src/types/Auth.ts,定义登录接口入参类型及返回数据类型。
1
2
3
4
5
6
7
8
9
10
11
|
// src/types/Auth.ts
export interface TokenData {
access_token: string
expires_in: number
type: string
}
export interface LoginParams {
username: string
password: string
}
|
API 调用
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<script setup lang="ts">
import { ServeLogin } from '@/api/auth/login';
const login = async () => {
const res = await ServeLogin({
username: 'Jenny',
password: '******'
})
console.log(res)
}
login()
</script>
|
集成 sass
新建 src/assets/styles/reset.scss 文件,将最新版本的 reset css 复制过来。
最新版本地址:The New CSS Reset | the-new-css-reset
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
/***
The new CSS reset - version 1.8.4 (last updated 14.2.2023)
GitHub page: https://github.com/elad2412/the-new-css-reset
***/
/*
Remove all the styles of the "User-Agent-Stylesheet", except for the 'display' property
- The "symbol *" part is to solve Firefox SVG sprite bug
*/
*:where(:not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)) {
all: unset;
display: revert;
}
/* Preferred box-sizing value */
*,
*::before,
*::after {
box-sizing: border-box;
}
/* Reapply the pointer cursor for anchor tags */
a, button {
cursor: revert;
}
/* Remove list styles (bullets/numbers) */
ol, ul, menu {
list-style: none;
}
/* For images to not be able to exceed their container */
img {
max-inline-size: 100%;
max-block-size: 100%;
}
/* removes spacing between cells in tables */
table {
border-collapse: collapse;
}
/* Safari - solving issue when using user-select:none on the <body> text input doesn't working */
input, textarea {
-webkit-user-select: auto;
}
/* revert the 'white-space' property for textarea elements on Safari */
textarea {
white-space: revert;
}
/* minimum style to allow to style meter element */
meter {
-webkit-appearance: revert;
appearance: revert;
}
/* preformatted text - use only for this feature */
:where(pre) {
all: revert;
}
/* reset default text opacity of input placeholder */
::placeholder {
color: unset;
}
/* remove default dot (•) sign */
::marker {
content: initial;
}
/* fix the feature of 'hidden' attribute.
display:revert; revert to element instead of attribute */
:where([hidden]) {
display: none;
}
/* revert for bug in Chromium browsers
- fix for the content editable attribute will work properly.
- webkit-user-select: auto; added for Safari in case of using user-select:none on wrapper element*/
:where([contenteditable]:not([contenteditable="false"])) {
-moz-user-modify: read-write;
-webkit-user-modify: read-write;
overflow-wrap: break-word;
-webkit-line-break: after-white-space;
-webkit-user-select: auto;
}
/* apply back the draggable feature - exist only in Chromium and Safari */
:where([draggable="true"]) {
-webkit-user-drag: element;
}
/* Revert Modal native behavior */
:where(dialog:modal) {
all: revert;
}
|
在 main.ts 文件中引入
1
|
import '@/assets/styles/reset.scss'
|
设置 scss 全局变量
新建文件 /src/assets/styles/variables.scss
1
2
3
4
5
|
$whiteColor: #fff;
$blackColor: #000;
$redColor: red;
$borderColor: #f5f5f5;
$backgroundColor: #eff0f1;
|
————————————————
配置 vite.config.ts 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// vite.config.ts
export default ({ command, mode }: ConfigEnv): UserConfig => {
return {
css: {
// 使用 scss 全局变量
preprocessorOptions: {
scss: {
additionalData: '@import "src/assets/styles/variables.scss";'
}
}
},
plugins: [
...
],
}
}
|
使用全局变量
1
2
3
4
5
6
7
8
9
|
<template>
<h1 class="title">首页</h1>
</template>
<style scoped lang="scss">
.title {
color: $redColor;
}
</style>
|
参考文档:
链接:https://juejin.cn/post/7135249540227006501
https://blog.csdn.net/lhz_333/article/details/125367315
https://juejin.cn/post/7174332521306390535