从 0 开始搭建Vue3.x 项目工程环境
作为一名前端工程师,只会写业务代码是不行了,项目搭建是我们成长路上必备得一课.今天我以vue3+vite+pinia+ts为基础搭建一个完整的vue框架,下面进入正题
架构搭建
请确保你的电脑上成功安装 Node.js,本项目使用 Vite 构建工具,需要 Node.js 版本 >= 12.0.0。
查看 Node.js 版本:
node -v
建议将 Node.js 升级到最新的稳定版本:
# 使用 nvm 安装最新稳定版 Node.js
nvm install stable
使用 Vite 快速初始化项目雏形
-
使用 NPM:
npm init vite
-
使用 Yarn:
yarn create vite
然后按照终端提示完成以下操作:
-
输入项目名称
例如:本项目名称 vite-vue3
-
选择模板
本项目需要使用 Vue3 + TypeScript,所以我们选择
vue-ts
,会自动安装 Vue3 和 TypeScript。
你还可以通过附加的命令行选项直接指定项目名和模板,本项目要构建 Vite + Vue3 + TypeScript 项目,则运行:
```
# npm 6.x
npm init @vitejs/app vite-vue3 --template vue-ts
# npm 7+(需要额外的双横线)
npm init @vitejs/app vite-vue3 -- --template vue-ts
# yarn
yarn create @vitejs/app vite-vue3 --template vue-ts
```
-
安装依赖
npm install
-
启动项目
npm run dev
如上图,表示 Vite + Vue3 + TypeScript 简单的项目骨架搭建完毕,下面我们来为这个项目集成 Vue Router、pinia、Element Plus、Axios、Stylus/Sass/Less。
修改 Vite 配置文件
Vite 配置文件 vite.config.ts
位于根目录下,项目启动时会自动读取。
本项目先做一些简单配置,例如:设置 @
指向 src
目录、 服务启动端口、打包路径、代理等。
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import {resolve} from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve:{
alias:{
'@':resolve(__dirname,'src')//设置 `@` 指向 `src` 目录
}
},
base: './', // 设置打包路径
server: {
port: 4000, // 设置服务启动端口号
open: true, // 设置服务启动时是否自动打开浏览器
cors: true // 允许跨域
// 设置代理,根据我们项目实际情况配置
// proxy: {
// '/api': {
// target: 'http://xxx.xxx.xxx.xxx:8000',
// changeOrigin: true,
// secure: false,
// rewrite: (path) => path.replace('/api/', '/')
// }
// }
}
})
当前文件目录如下:
现在我们开始配置路由
集成路由工具 Vue Router
-
安装支持 Vue3 的路由工具 vue-router
npm i vue-router
-
创建
src/router/index.ts
文件在
src
下创建router
目录,然后在router
目录里新建index.ts
文件:scss └── src/ ├── router/ ├── index.ts // 路由配置文件
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
import Home from '@/views/home.vue'
const routers: RouteRecordRaw[] = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/pageOne',
name: 'pageOne',
component: () => import('@/views/PageOne.vue') // 懒加载组件
},
]
const router = createRouter({
history: createWebHashHistory(),
routes: routers
})
export default router
根据本项目路由配置的实际情况,你需要在 src
下创建 views
目录,用来存储页面组件。
在 main.ts
文件中挂载路由配置
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
createApp(App).use(router).mount('#app')
集成状态管理工具 pinia
-
pinia相较于vuex的优点(详情可查询pinia官网
-
-
Devtools 支持
-
追踪 actions、mutations 的时间线
-
在组件中展示它们所用到的 Store
-
让调试更容易的 Time travel
-
-
热更新
- 不必重载页面即可修改 Store
- 开发时可保持当前的 State
-
插件:可通过插件扩展 Pinia 功能
-
为 JS 开发者提供适当的 TypeScript 支持以及自动补全功能。
-
支持服务端渲染
npm install pinia
创建一个 pinia 实例 (根 store) 并将其传递给应用:
import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' const pinia = createPinia() const app = createApp(App) app.use(pinia) app.mount('#app')
-
创建
src/store/index.ts
文件在
src
下创建store
目录,然后在store
目录里新建index.ts
文件:scss 复制代码 └── src/ ├── store/ ├── index.ts // store 配置文件
在深入研究核心概念之前,我们得知道 Store 是用 defineStore()
定义的,它的第一个参数要求是一个独一无二的名字:
import { defineStore } from 'pinia'
// 你可以任意命名 `defineStore()` 的返回值,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。
// (比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一个参数是你的应用中 Store 的唯一 ID。
export const useAlertsStore = defineStore('alerts', {
// 其他配置...
})
这个名字 ,也被用作 id ,是必须传入的, Pinia 将用它来连接 store 和 devtools。为了养成习惯性的用法,将返回的函数命名为 use... 是一个符合组合式函数风格的约定。
defineStore()
的第二个参数可接受两类值:Setup 函数或 Option 对象。
Option Store
与 Vue 的选项式 API 类似,我们也可以传入一个带有 state
、actions
与 getters
属性的 Option 对象
js
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters: {
double: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
},
},
})
你可以认为 state
是 store 的数据 (data
),getters
是 store 的计算属性 (computed
),而 actions
则是方法 (methods
)。
为方便上手使用,Option Store 应尽可能直观简单。
Setup Store
也存在另一种定义 store 的可用语法。与 Vue 组合式 API 的 setup 函数 相似,我们可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。
js
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})
在 Setup Store 中:
ref()
就是state
属性computed()
就是getters
function()
就是actions
集成 UI 框架 Element Plus
-
安装支持 Vue3 的 UI 框架 Element Plus
npm i element-plus
-
在
main.ts
文件中挂载 Element Plusts 复制代码 import { createApp } from 'vue' import App from './App.vue' import ElementPlus from 'element-plus' import 'element-plus/lib/theme-chalk/index.css' createApp(App).use(ElementPlus).mount('#app')
集成 HTTP 工具 Axios
-
安装 Axios
npm i axios
-
配置 Axios
为了使项目的目录结构合理且规范,我们在
src
下创建utils
目录来存储我们常用的工具函数。Axios 作为 HTTP 工具,我们在
utils
目录下创建axios.ts
作为 Axios 配置文件:scss 复制代码 └── src/ ├── utils/ ├── axios.ts // Axios 配置文件
-
import Axios from 'axios' import { ElMessage } from 'element-plus' const baseURL = 'https://api.github.com' const axios = Axios.create({ baseURL, timeout: 20000 // 请求超时 20s }) // 前置拦截器(发起请求之前的拦截) axios.interceptors.request.use( (response) => { /** * 根据你的项目实际情况来对 config 做处理 * 这里对 config 不做任何处理,直接返回 */ return response }, (error) => { return Promise.reject(error) } ) // 后置拦截器(获取到响应时的拦截) axios.interceptors.response.use( (response) => { /** * 根据你的项目实际情况来对 response 和 error 做处理 * 这里对 response 和 error 不做任何处理,直接返回 */ return response }, (error) => { if (error.response && error.response.data) { const code = error.response.status const msg = error.response.data.message ElMessage.error(`Code: ${code}, Message: ${msg}`) console.error(`[Axios Error]`, error.response) } else { ElMessage.error(`${error}`) } return Promise.reject(error) } ) export default axios
-
使用 Axios 在需要使用 Axios 文件里,引入 Axios 配置文件,参考如下:
html 复制代码 <template></template> <script lang="ts"> import { defineComponent } from 'vue' import axios from '../utils/axios' export default defineComponent({ setup() { axios .get('/users/XPoet') .then((res) => { console.log('res: ', res) }) .catch((err) => { console.log('err: ', err) }) } }) </script>
集成 CSS 预编译器 Stylus/Sass/Less
本项目使用 CSS 预编译器 Sass,直接安装为开发依赖即可。Vite 内部已帮我们集成了相关的 loader,不需要额外配置。同理,你也可以使用 Stylus 或 Less 等。
-
安装
npm i less -D # or npm i sass -D npm i stylus -D
-
使用
html 复制代码 <style lang="Sass"> ... </style>
至此,一个基于 TypeScript + Vite + Vue3 + Vue Router + Vuex + Element Plus + Axios + Stylus/Sass/Less 的前端项目开发环境搭建完毕,项目 Demo 托管在,需要的同学可以去下载下来,参考学习。
代码规范
代码规范的重要性不言而喻,特别是在多人合作的项目中尤其重要
本文讲解如何使用 EditorConfig + Prettier + ESLint 组合来实现代码规范化。
这样做带来好处:
- 解决团队之间代码不规范导致的可读性差和可维护性差的问题。
- 解决团队成员不同编辑器导致的编码规范不统一问题。
- 提前发现代码风格问题,给出对应规范提示,及时修复。
- 减少代码审查过程中反反复复的修改过程,节约时间。
- 自动格式化,统一编码风格,从此和脏乱差的代码说再见。
集成 EditorConfig 配置
EditorConfig 有助于为不同 IDE 编辑器上处理同一项目的多个开发人员维护一致的编码风格。
在项目根目录下增加 .editorconfig
文件:
# Editor configuration, see http://editorconfig.org
# 表示是最顶层的 EditorConfig 配置文件
root = true
[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
indent_style = space # 缩进风格(tab | space)
indent_size = 2 # 缩进大小
end_of_line = lf # 控制换行类型(lf | cr | crlf)
trim_trailing_whitespace = true # 去除行首的任意空白字符
insert_final_newline = true # 始终在文件末尾插入一个新行
[*.md] # 表示仅 md 文件适用以下规则
max_line_length = off
trim_trailing_whitespace = false
注意:
-
VSCode 使用 EditorConfig 需要去插件市场下载插件 EditorConfig for VS Code 。
-
JetBrains 系列(WebStorm、IntelliJ IDEA 等)则不用额外安装插件,可直接使用 EditorConfig 配置。
集成 Prettier 配置
Prettier 是一款强大的代码格式化工具,支持 JavaScript、TypeScript、CSS、SCSS、Less、JSX、Angular、Vue、GraphQL、JSON、Markdown 等语言,基本上前端能用到的文件格式它都可以搞定,是当下最流行的代码格式化工具。
};
```
-
Prettier 安装且配置好之后,就能使用命令来格式化代码
# 格式化所有文件(. 表示所有文件) npx prettier --write .
注意:
-
VSCode 编辑器使用 Prettier 配置需要下载插件 Prettier - Code formatter 。
Prettier 配置好以后,在使用 VSCode 或 WebStorm 等编辑器的格式化功能时,编辑器就会按照 Prettier 配置文件的规则来进行格式化,避免了因为大家编辑器配置不一样而导致格式化后的代码风格不统一的问题。
集成 ESLint 配置
正如前面我们提到的因团队成员之间编程能力和编码习惯不同所造成的代码质量问题,我们使用 ESLint 来解决,一边写代码一边查找问题,如果发现错误,就给出规则提示,并且自动修复,长期下去,可以促使团队成员往同一种编码风格靠拢。
-
安装 ESLint
可以全局或者本地安装,作者推荐本地安装(只在当前项目中安装)。
npm i eslint -D
-
配置 ESLint
ESLint 安装成功后,执行
npx eslint --init
,然后按照终端操作提示完成一系列设置来创建配置文件。-
How would you like to use ESLint? (你想如何使用 ESLint?)
我们这里选择 To check syntax, find problems, and enforce code style(检查语法、发现问题并强制执行代码风格)
-
What type of modules does your project use?(你的项目使用哪种类型的模块?)
我们这里选择 JavaScript modules (import/export)
-
Which framework does your project use? (你的项目使用哪种框架?)
我们这里选择 Vue.js
-
Does your project use TypeScript?(你的项目是否使用 TypeScript?)
我们这里选择 Yes
-
Where does your code run?(你的代码在哪里运行?)
我们这里选择 Browser 和 Node(按空格键进行选择,选完按回车键确定)
-
How would you like to define a style for your project?(你想怎样为你的项目定义风格?)
我们这里选择 Use a popular style guide(使用一种流行的风格指南)
-
Which style guide do you want to follow?(你想遵循哪一种风格指南?)
我们这里选择 standard
此时,我们在 ESLint 配置了 Airbnb JavaScript 规则,在编码时,所有不符合 standard 风格的代码,编辑器都会给出提示,并且可以自动修复。
-
What format do you want your config file to be in?(你希望你的配置文件是什么格式?)
我们这里选择 JavaScript
- Would you like to install them now with npm?(你想现在就用 NPM 安装它们吗?)
根据上面的选择,ESLint 会自动去查找缺失的依赖,我们这里选择 Yes,使用 NPM 下载安装这些依赖包。
-
-
ESLint 配置文件
.eslintrc.js
在上一步操作完成后,会在项目根目录下自动生成
.eslintrc.js
配置文件:js 复制代码 module.exports = { env: { browser: true, es2021: true, node: true }, extends: ['plugin:vue/essential', 'airbnb-base'], parserOptions: { ecmaVersion: 12, parser: '@typescript-eslint/parser', sourceType: 'module' }, plugins: ['vue', '@typescript-eslint'], rules: {} }
根据项目实际情况,如果我们有额外的 ESLint 规则,也在此文件中追加。
注意:
-
VSCode 使用 ESLint 配置文件需要去插件市场下载插件 ESLint 。
虽然,现在编辑器已经给出错误提示和修复方案,但需要我们一个一个去点击修复,还是挺麻烦的。很简单,我们只需设置编辑器保存文件时自动执行 eslint --fix
命令进行代码风格修复。
-
VSCode 在
settings.json
设置文件中,增加以下代码:js 复制代码 "editor.codeActionsOnSave": { "source.fixAll.eslint": true }
解决 Prettier 和 ESLint 的冲突
通常大家会在项目中根据实际情况添加一些额外的 ESLint 和 Prettier 配置规则,难免会存在规则冲突情况。
本项目中的 ESLint 配置中使用了 Airbnb JavaScript 风格指南校验,其规则之一是代码结束后面要加分号,而我们在 Prettier 配置文件中加了代码结束后面不加分号的配置项,这样就有冲突了,会出现用 Prettier 格式化后的代码,ESLint 检测到格式有问题的,从而抛出错误提示。
解决两者冲突问题,需要用到 eslint-plugin-prettier 和 eslint-config-prettier。
eslint-plugin-prettier
将 Prettier 的规则设置到 ESLint 的规则中。eslint-config-prettier
关闭 ESLint 中与 Prettier 中会发生冲突的规则。
最后形成优先级:Prettier 配置规则
> ESLint 配置规则
。
-
安装插件
npm i eslint-plugin-prettier eslint-config-prettier -D
-
在
.eslintrc.js
添加 prettier 插件module.exports = { ... extends: [ 'plugin:vue/essential', 'airbnb-base', 'plugin:prettier/recommended' // 添加 prettier 插件 ], ... }
这样,我们在执行 eslint --fix
命令时,ESLint 就会按照 Prettier 的配置规则来格式化代码,轻松解决二者冲突问题。
集成 husky 和 lint-staged
我们在项目中已集成 ESLint 和 Prettier,在编码时,这些工具可以对我们写的代码进行实时校验,在一定程度上能有效规范我们写的代码,但团队可能会有些人觉得这些条条框框的限制很麻烦,选择视“提示”而不见,依旧按自己的一套风格来写代码,或者干脆禁用掉这些工具,开发完成就直接把代码提交到了仓库,日积月累,ESLint 也就形同虚设。
所以,我们还需要做一些限制,让没通过 ESLint 检测和修复的代码禁止提交,从而保证仓库代码都是符合规范的。
为了解决这个问题,我们需要用到 Git Hook,在本地执行 git commit
的时候,就对所提交的代码进行 ESLint 检测和修复(即执行 eslint --fix
),如果这些代码没通过 ESLint 规则校验,则禁止提交。
配置 husky
-
自动配置(推荐)
使用
husky-init
命令快速在项目初始化一个 husky 配置。npx husky-init && npm install
这行命令做了四件事:
-
安装 husky 到开发依赖
-
在项目根目录下创建
.husky
目录 -
在
.husky
目录创建pre-commit
hook,并初始化pre-commit
命令为npm test
-
修改
package.json
的scripts
,增加"prepare": "husky install"
到这里,husky 配置完毕,现在我们来使用它:
husky 包含很多
hook
(钩子),常用有:pre-commit
、commit-msg
、pre-push
。这里,我们使用pre-commit
来触发 ESLint 命令。修改
.husky/pre-commit
hook 文件的触发命令:eslint --fix ./src --ext .vue,.js,.ts
-
但是又存在一个问题:有时候我们明明只改动了一两个文件,却要对所有的文件执行 eslint --fix
。假如这是一个历史项目,我们在中途配置了 ESLint 规则,那么在提交代码时,也会对其他未修改的“历史”文件都进行检查,可能会造成大量文件出现 ESLint 错误,显然不是我们想要的结果。
我们要做到只用 ESLint 修复自己此次写的代码,而不去影响其他的代码。所以我们还需借助一个神奇的工具 lint-staged 。
配置 lint-staged
lint-staged 这个工具一般结合 husky 来使用,它可以让 husky 的 hook
触发的命令只作用于 git add
那些文件(即 git 暂存区的文件),而不会影响到其他文件。
接下来,我们使用 lint-staged 继续优化项目。
-
安装 lint-staged
npm i lint-staged -D
-
在
package.json
里增加 lint-staged 配置项"lint-staged": { "*.{vue,js,ts}": "eslint --fix" },
这行命令表示:只对 git 暂存区的
.vue
、.js
、.ts
文件执行eslint --fix
。 -
修改
.husky/pre-commit
hook 的触发命令为:npx lint-staged
至此,husky 和 lint-staged 组合配置完成。
规范目录结构
最终文件结构如图所示
├── publish/
└── src/
├── assets/ // 静态资源目录
├── common/ // 通用类库目录
├── components/ // 公共组件目录
├── router/ // 路由配置目录
├── store/ // 状态管理目录
├── style/ // 通用 CSS 目录
├── utils/ // 工具函数目录
├── views/ // 页面组件目录
├── App.vue
├── main.ts
├── shims-vue.d.ts
├── index.html
├── tsconfig.json // TypeScript 配置文件
├── vite.config.ts // Vite 配置文件
└── package.json
本项目完整的代码托管在 GitHub 仓库,有需要的同学可以去下载下来,参考学习。喜欢的同学们可以一键三联,后续我也会不定期更新,去逐步完善这个框架.有好的建议或者想法可以一起交流,本文也是采众家之所长为己用,如有错误请指摘,共同进步
转载自:https://juejin.cn/post/7349002962867912704