链接地址:
版本号:
- Node: v14.19.3
- pnpm: 7.1.9
- @vue/cli: 4.5.15
1. 项目基础环境搭建
命令:
pnpm create vite vue3-ts-vite-pinia-element-plus-pnpm --template vue-ts
执行:
$ pnpm create vite vue3-ts-vite-pinia-element-plus-pnpm --template vue-ts
../../.pnpm-store/v3/tmp/dlx-13012 | +6 +
Packages are hard linked from the content-addressable store to the virtual store.
Content-addressable store is at: F:\.pnpm-store\v3
Virtual store is at: ../../.pnpm-store/v3/tmp/dlx-13012/node_modules/.pnpm
../../.pnpm-store/v3/tmp/dlx-13012 | Progress: resolved 6, reused 6, downloaded 0, added 6, done
Scaffolding project in F:\Web\Vue\vue3-ts-vite-pinia-element-plus-pnpm...
Done. Now run:
cd vue3-ts-vite-pinia-element-plus-pnpm
pnpm install
pnpm run dev
命令:
cd vue3-ts-vite-pinia-element-plus-pnpm/
pnpm install
执行:
$ pnpm install
Packages: +47
+++++++++++++++++++++++++++++++++++++++++++++++
Packages are hard linked from the content-addressable store to the virtual store.
Content-addressable store is at: F:\.pnpm-store\v3
Virtual store is at: node_modules/.pnpm
Downloading registry.npmmirror.com/typescript/4.7.4: 11.7 MB/11.7 MB, done
node_modules/.pnpm/registry.npmmirror.com+esbuild@0.14.54/node_modules/esbuild: Running postinstall script, done in 398ms
Progress: resolved 68, reused 0, downloaded 47, added 47, done
dependencies:
+ vue 3.2.37
devDependencies:
+ @vitejs/plugin-vue 3.0.3
+ typescript 4.7.4
+ vite 3.0.8
+ vue-tsc 0.39.5 (0.40.1 is available)
命令:
pnpm run dev
执行:
$ pnpm run dev
> vue3-ts-vite-pinia-element-plus-pnpm@0.0.0 dev F:\Web\Vue\vue3-ts-vite-pinia-element-plus-pnpm
> vite
VITE v3.0.8 ready in 375 ms
➜ Local: http://127.0.0.1:5173/
➜ Network: use --host to expose
点击链接,跳转浏览器查看效果:
至此项目基础框架搭建完毕
2. 必要依赖安装
element-plus
命令:
pnpm install element-plus
执行:
$ pnpm install element-plus
Packages: +21
+++++++++++++++++++++
Downloading registry.npmmirror.com/element-plus/2.2.13: 7.85 MB/7.85 MB, done
node_modules/.pnpm/registry.npmmirror.com+vue-demi@0.13.8_vue@3.2.37/node_modules/vue-demi: Running postinstall script, done in 146ms
Progress: resolved 89, reused 47, downloaded 21, added 21, done
dependencies:
+ element-plus 2.2.13
@element-plus/icons-vue
命令:
pnpm install @element-plus/icons-vue
执行:
$ pnpm install @element-plus/icons-vue
Already up-to-date
Progress: resolved 116, reused 95, downloaded 0, added 0, done
dependencies:
+ @element-plus/icons-vue 2.0.9
备注:
axios
命令:
pnpm install axios
执行:
$ pnpm install axios
Packages: +8
++++++++
Progress: resolved 97, reused 68, downloaded 8, added 8, done
dependencies:
+ axios 0.27.2
pinia
命令:
pnpm install pinia
执行:
$ pnpm install pinia
Packages: +2
++
dependencies:
+ pinia 2.0.19
Progress: resolved 99, reused 76, downloaded 2, added 2, done
vue-router
命令:
pnpm install vue-router
执行:
$ pnpm install vue-router
Packages: +1
+
Progress: resolved 100, reused 79, downloaded 0, added 0, done
dependencies:
+ vue-router 4.1.3
sass
命令:
pnpm install -D sass
执行:
$ pnpm install -D sass
Packages: +17 -1
+++++++++++++++++-
Progress: resolved 116, reused 79, downloaded 16, added 17, done
devDependencies:
+ sass 1.54.4
- vite 3.0.8
+ vite 3.0.
备注:
eslint
命令:pnpm install -D eslint
执行:
$ pnpm install -D eslint
Packages: +103
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 219, reused 95, downloaded 103, added 103, done
devDependencies:
+ eslint 8.22.0
Next:
-
使用eslint自动进行配置
命令:
./node_modules/.bin/eslint --init
执行:
----------------------------------- 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相关依赖
"devDependencies": { "@typescript-eslint/eslint-plugin": "^5.0.0", ... "eslint": "^8.0.1", "eslint-config-standard-with-typescript": "^22.0.0", "eslint-plugin-import": "^2.25.2", "eslint-plugin-n": "^15.0.0", "eslint-plugin-promise": "^6.0.0", "eslint-plugin-vue": "^9.3.0", ...
prettier
命令:
pnpm install -D --save-exact prettier
执行:
$ pnpm install -D --save-exact prettier
Packages: +1
+
Progress: resolved 220, reused 199, downloaded 0, added 0, done
devDependencies:
+ prettier 2.7.1
Next:
- 创建空的配置文件:
echo {}> .prettierrc.json
- 创建prettier格式化忽略配置文件:.prettierignore
- 在 .prettierignore 文件中添加如下初始配置
# Ignore artifacts:
build
coverage
- 配置与 eslint 配合(参考下一步)
备注:
eslint-config-prettier
命令:
pnpm install -D eslint-config-prettier
执行:
$ pnpm install -D eslint-config-prettier
Packages: +1
+
Progress: resolved 299, reused 277, downloaded 1, added 1, done
devDependencies:
+ eslint-config-prettier 8.5.0
Next:
- 将 prettier 添加到 .eslintrc.cjs 配置文件的 eslint 扩展配置中,并且保证其在该配置项的最后一项
/** ./.eslintrc.cjs */
module.exports = {
env: {
browser: true,
es2021: true
},
extends: [
'plugin:vue/vue3-essential',
'standard-with-typescript',
'prettier' <--------(此箭头仅起提示作用,代码中需要删除)
],
...
备注:
@types/node
命令:
pnpm install -D @types/node
执行:
$ pnpm install -D @types/node
Packages: +1
+
Progress: resolved 300, reused 278, downloaded 1, added 1, done
devDependencies:
+ @types/node 18.7.6
备注:此依赖是node中的类型定义,在后面对于一些配置信息时需要使用node中的方法时,没有引入此依赖就会提示安装。
3. 基础配置
1. 添加环境变量配置文件
1. 根据 <开发版本> | <预发行版> | <生产版本> 创建单独的 .env 文件
- .env : 基本配置项
- .env.development : 开发环境配置项
- .env.staging : 预发布版本配置项
- .env.production : 生产环境配置项
# windows 批处理命令(在项目根目录cmd窗运行下面命令即可生成上述四个文件):
echo '# DEFAULT ENV'> .env;echo '# DEVELOPMENT ENV'> .env.development;echo '# STAGING DEV'> .env.staging;echo '# PRODUCTION ENV'> .env.production
2. 配置基本的配置项
修改 .env 文件
# DEFAULT ENV
# 项目标题
VITE_APP_TITLE = 'My App'
# 项目运行端口
VITE_PORT = '3000'
# 项目启动后自动打开默认浏览器
VITE_OPEN = 'true'
2. 修改 vite 配置文件 vite.config.js
- 设置模块引入路径别名 "@"
首先需要在 vite.config.js 添加别名和对应的路径信息
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 文件中添加别名的配置
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
+ "baseUrl": "./",
+ "paths": {
+ "@/*": ["src/*"]
+ }
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }] // 此处注意后面会提到
}
- 将env文件中定义的配置添加到vite配置信息中
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,所以直接在此文件下添加,如果没有该文件,手动创建。
/// <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
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无法自动识别并提示,同时手动添加导入信息会提示
按照提示的信息,找到项目根目录下的tsconfig.node.json文件,发现其与tsconfig.json是一样的,只不过里面的配置信息不相同,这个文件是为了typescript在node环境的配置信息
上文提到的tsconfig.json文件中的最后一行中的 references
其作用是可以将程序分割为更小的模块,然后统一进行管理和编译,因为我并不了解所以具体内容自行查阅, 而此处主要使用用于对node环境下,运行的vite.config.ts进行的配置,在文件中填写包含的文件即创建的getEnv.ts,就可以在vite.config.ts中正常的引入getEnv函数了,同时也可以自动导入函数。
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": [
"vite.config.ts",
+ "./src/utils/getEnv.ts"
]
}
修改后的vite.config.ts
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()]
}
})
此时再次再次运行 pnpm run dev 即可发现项目启动后自动打开默认浏览器并跳转到localhost:3000
4. 配置 element-plus
- 全局注册element-plus组件(因为我现在并不是很在乎打包大小)
- 将element-plus组件默认语言设置为中文简体
- 将element的icon组件全局注册
代码:
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');
5. 创建 项目目录
vue3-ts-vite-pinia-element-plus-pnpm
├── .env
├── .env.development
├── .env.production
├── .env.staging
├── .eslintrc.cjs
├── .gitignore
├── .prettierignore
├── .prettierrc.json
├── .vscode
│ └── extensions.json
├── README.md
├── dist
│ ├── assets
│ ├── index.html
│ └── vite.svg
├── index.html
├── node.md
├── package.json
├── pnpm-lock.yaml
├── public
│ └── vite.svg
├── src
│ ├── App.vue
│ ├── api
│ ├── assets
│ ├── components
│ ├── config
│ ├── hooks
│ ├── layout
│ ├── main.ts
│ ├── plugins
│ ├── routers
│ ├── style.css
│ ├── types
│ ├── utils
│ ├── views
│ └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
如何生成文件树
使用 tree-node-cli
1. 全局安装
npm install -g tree-node-cli
2. 运行命令,由于windows环境为了与默认tree冲突,需要使用treee的命令执行
treee -L 2 -I "node_modules" > node.md
- a. -L 2 : 指层级为两层
- b. -I "node_modules" : 忽略node_modules文件夹
- c. > node.md: 指将结果输出到node.md文件中
6. 配置 vue-router
1. 在 src/routers 创建index.ts
2. 在 src/views 添加两个用于跳转展示的页面 Home.vue, About.vue
<template>
<div>Home</div>
</template>
<script setup lang="ts"></script>
<style scoped></style>
About.vue与之相同
3. 在router/index.ts中添加路由内容
import AboutVue from "@/views/About.vue"
import HomeVue from "@/views/Home.vue"
import { createRouter, createWebHashHistory } from "vue-router"
// 每个路由都需要映射到一个组件。
const routes = [
{ path: '/', component: HomeVue },
{ path: '/about', component: AboutVue },
]
// 创建路由实例并传递 `routes` 配置
const router = createRouter({
// 使用 hash 模式。
history: createWebHashHistory(),
routes, // `routes: routes` 的缩写
})
export default router
4. 修改App.vue,用于展示跳转页面的内容
<template>
<div>
<RouterLink to="/">Home</RouterLink>
<br/>
<RouterLink to="/about">About</RouterLink>
</div>
<router-view/>
</template>
<script setup lang="ts"></script>
<style scoped></style>
5. 修改main.ts,注册router的信息
...
+ import router from '@/routers/index'
const app = createApp(App);
+ app.use(router);
...
6. 访问页面就可以体验简单的路由跳转功能
遇到的问题:
1. 创建的Home.vue会被eslint提示命名不符合规范
原因是vue在创建项目的时候使用了vue/cli-plugin-eslint插件,其在 eslint-plugin-vue v7.20.0后添加了除了根目录的app.vue和vue提供的组件以外,组件命名需要至少两个单词组成,即类似于HomeVue的形式,用来防止用户命名不规范的问题,但是我们这里不需要这种,所以需要将其验证条件关闭
关闭方式,打开根目录下的 .eslintrc.cjs 文件,在rules中添加关闭代码,然后问题解决
module.exports = {
env: {
browser: true,
es2021: true
},
extends: [
'plugin:vue/vue3-essential',
'standard-with-typescript',
'prettier'
],
overrides: [
],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module'
},
plugins: [
'vue'
],
rules: {
+ "vue/multi-word-component-names":"off",
}
}
7. 配置 pinia
1. 先将pinia注册到vue中
...
+ import { createPinia } from 'pinia'
app.use(router);
+ app.use(createPinia());
...
2. 在src/stores 创建index.ts
// stores/index.js
import { defineStore } from 'pinia'
export const useGlobalStore = defineStore('GlobalState', {
state: () => {
return { count: 0 }
},
actions: {
add() {
this.count++
},
sub(){
this.count--
}
},
getters: {
double(state){
return state.count * 2;
}
}
})
- state:存储数据
- actions:定义对数据进行操作的方法
- getters:定义对数据进行计算的方法
3. 在Home.vue中使用store
<template>
<div>Home</div>
<div>Count: {{count}}</div>
<div>Double: {{double}}</div>
<el-button @click="globalStore.add">+</el-button>
<el-button @click="globalStore.sub">-</el-button>
</template>
<script setup lang="ts">
import { useGlobalStore } from '@/stores';
import { storeToRefs } from 'pinia';
const globalStore = useGlobalStore()
const {count, double} = storeToRefs(globalStore) // !!!
</script>
<style scoped></style>
注意:
此处需要注意的是,从store中可以直接获取state中定义的数值,但是这个数据并不能成为响应式数据,具体表现为数值发生变化时,直接获取形式的数值并不会发生变化,所以需要使用pinia提供的storeToRefs函数,将数值转换为响应式的数值
4. 在About.vue中展示store中的值
<template>
<div>About</div>
<div>Count: {{count}}</div>
<div>Double: {{double}}</div>
</template>
<script setup lang="ts">
import { useGlobalStore } from '@/stores';
import { storeToRefs } from 'pinia';
const globalStore = useGlobalStore()
const {count, double} = storeToRefs(globalStore)
</script>
<style scoped></style>
5. 效果
8. scss
sass安装好后,就可以使用scss了
<template>
<div>Home</div>
<ul>
<li class="count">Count: {{count}}</li>
<li class="double">Double: {{double}}</li>
</ul>
<el-button @click="globalStore.add">+</el-button>
<el-button @click="globalStore.sub">-</el-button>
</template>
<script setup lang="ts">
import { useGlobalStore } from '@/stores';
import { storeToRefs } from 'pinia';
const globalStore = useGlobalStore()
const {count, double} = storeToRefs(globalStore)
</script>
<style scoped lang="scss">
$color: red;
ul{
color: $color;
}
</style>