一. 文章结构
-
技术栈 -
搭建准备 -
架构搭建 -
代码规范 -
提交规范
二. 技术栈
-
编程语言:TypeScript 4.X + JavaScript -
构建工具:vite 3.X -
前端框架:Vue 3.X -
路由工具:Vue-router 4.X -
状态管理:pinia 2.X -
UI框架:Element plus -
CSS预处理:sass -
HTTP工具:Axios -
代码规范:Prettier + Eslint + EditorConfig -
提交规范:cz-git
三. 搭建前准备
前置条件
-
Vscode: 前端人必备写码神器 -
Chrome:对开发者非常友好的浏览器 -
Nodejs&npm:配置本地开发环境(建议安装node管理工具nvm方便切换node版本) -
Vue.js devtools:浏览器调试插件 -
Vue Language Features (Volar):Vscode 开发 vue3 必备插件,提供语法高亮提示,非常好用 -
Vue 3 Snippets:vue3 快捷输入
「Nvm常用命令」
-
查看已安装的版本:nvm ls -
安装指定的版本:nvm install version -
删除指定的版本:nvm uninstall version -
使用选定的版本:nvm use version
why vite
Vite 是一个现代化的前端开发构建工具,它在某些方面与传统的构建工具(如Webpack)相比具有一些优点和缺点。「优点:」
-
「快速的开发启动」:Vite 以极快的速度启动开发服务器,因为它使用了 ES 模块的原生浏览器支持,无需预先构建或打包。这意味着你可以更快地开始编写和测试代码。 -
「热模块替换(HMR)」:Vite 提供了强大的热模块替换功能,可以在不刷新整个页面的情况下实时更新应用程序的部分。这可以显著提高开发效率。 -
「按需加载」:Vite 支持按需加载,只会在需要的时候加载模块,而不是将整个应用打包成一个巨大的文件。这有助于减小最终构建的文件大小,提高加载性能。 -
「简单的配置」:Vite 的配置相对简单,因为它采用了约定大于配置的理念。许多默认配置都可以满足大多数项目的需求,不需要复杂的配置。 -
「Vue.js 生态系统的首选工具」:Vite 最初是为 Vue.js 开发的,因此在 Vue.js 生态系统中得到广泛支持和推广。Vue 3 与 Vite 配合使用效果最佳。
「缺点:」
-
「生态系统相对不成熟」:虽然 Vite 在 Vue.js 生态系统中表现出色,但在其他框架和库中的支持相对不足。如果你的项目不使用 Vue.js,可能需要面临一些挑战。 -
「相对较新」:Vite 是相对较新的工具,可能会有一些不稳定性或不兼容性问题,尤其是在生产环境中使用时。这需要更多时间来成熟和稳定。 -
「较少的插件和扩展」:与一些成熟的构建工具相比,Vite 的插件生态系统相对较小。这意味着你可能需要编写自定义插件来满足特定需求。 -
「可能不适用于复杂项目」:对于非常复杂的前端项目,Vite 的简化可能会导致一些不足。一些大型项目可能更喜欢使用更强大的构建工具,如Webpack。
why Vue3
Vue3由于完全由TS进行重写,在应用中对类型判断的定义和使用有很强的表现。Vue2 的双向数据绑定是利用 ES5 的一个 API Object.definePropert()对数据进行劫持结合 发布订阅模式的方式来实现的。Vue3 中使用了 es6 的 ProxyAPI 对数据代理。Vue3支持碎片(Fragments)。Vue3引入传送门(Teleport)。Vue2 与 Vue3 最大的区别: Vue2 使用Options API而 Vue3 使用的Composition API
why pinia
「Pinia 优点:」
-
「类型安全」:Pinia 是基于 TypeScript 构建的,提供了强大的类型支持。 -
「Composition API 集成」:Pinia 是为 Composition API 设计的,与 Vue 3 更紧密集成,使代码更具可读性和可维护性。 -
「模块化和可组合性」:Pinia 使用了模块化的状态管理,可以轻松地将状态拆分为模块,并在多个组件之间共享和组合模块。 -
「更好的性能」:Pinia 在性能方面进行了优化,使用了 Vue 3 的响应式系统,提供了更好的性能表现,特别适用于大型应用。 -
「自动化的热重载」:Pinia 提供了自动的热重载支持,使开发过程更加顺畅。
「Pinia 缺点:」
-
「相对较新」:生态系统、文档和社区支持方面不如 Vuex 成熟。 -
「学习曲线」:不熟悉 TypeScript 的开发者学习困难。
「Vuex 优点:」
-
「成熟的生态系统」:Vuex 是 Vue.js 生态系统的一部分,因此具有大量的文档、教程和社区支持,适用于各种规模的项目。 -
「简单易用」:Vuex 的 API 相对简单,容易上手,特别是对于初学者来说。 -
「大型社区支持」:由于其流行度,Vuex 有一个庞大的社区,可以找到许多第三方插件和工具,用于扩展其功能。
「Vuex 缺点:」
-
「冗余的模板代码」:在 Vuex 中,一些常见操作需要编写大量的模板代码,可能导致代码冗余。 -
「缺乏类型支持」:虽然可以使用 TypeScript 与 Vuex 结合使用,但 Vuex 本身没有内置的类型支持,需要额外的工作来实现类型安全。 -
「较大的包大小」:Vuex 的核心库相对较大,这可能会增加应用程序的总体文件大小。
wyh CSS预处理
-
「变量和计算」:CSS 预处理器允许你定义变量,可以在整个样式表中重复使用。这使得更容易维护一致性的设计,因为你只需更新变量的值,而不必逐个修改每个使用该值的地方。此外,你还可以进行数学运算,使样式更具动态性。 -
「嵌套规则」:CSS 预处理器允许你使用嵌套规则,使样式更具可读性。这特别有用,因为你可以将相关的样式组织在一起,而不必编写冗长的选择器。 -
「混合(Mixins)」:混合是可重用的代码块,可以在不同的规则中重复使用。这有助于减少代码重复,提高样式表的可维护性。 -
「继承(Inheritance)」:继承允许一个选择器继承另一个选择器的样式。这使得创建和维护样式更加高效,因为你可以利用现有样式。 -
「模块化开发」:CSS 预处理器有助于将样式表分解为多个模块或组件,每个模块都可以独立开发和维护。这有助于提高团队协作和项目的可扩展性。 -
「自动前缀」:一些 CSS 预处理器和构建工具可以自动为你添加浏览器前缀,以确保样式在不同浏览器中正确显示,从而减少了跨浏览器兼容性问题。 -
「代码压缩和优化」:许多 CSS 预处理器具有优化选项,可以在构建过程中自动压缩和优化生成的 CSS,从而减小文件大小,提高加载性能。 -
「插件和生态系统」:CSS 预处理器通常有丰富的插件和工具生态系统,可以进一步扩展其功能,满足特定项目需求。
四. 架构搭建
Vite初始化项目
-
使用npm
npm create vite@latest
-
使用yarn
yarn create vite
-
使用pnpm
pnpm create vite
-
项目创建
还可以通过附加的命令行选项直接指定项目名和模板,本项目要构建 Vite + Vue3 + TypeScript 项目
# npm 6.x
npm create vite@latest my-vue-app --template vue
# npm 7+, extra double-dash is needed:
npm create vite@latest my-vue-app -- --template vue
# yarn
yarn create vite my-vue-app --template vue
# pnpm
pnpm create vite my-vue-app --template vue
-
安装依赖
cd test
npm install
-
运行项目
npm run dev
修改Vite配置
Vite 配置文件 vite.config.ts 位于根目录下,项目启动时会自动读取。本项目先做一些简单配置,例如:设置@指向 src目录、服务器启动端口、打包路径、代理等。
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 如果编辑器提示 path 模块找不到,则可以安装一下 @types/node -> npm i @types/node -D
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/', '/')
// }
// }
}
})
修改 tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": {
"@/*":["src/*"] // 未设置 "baseUrl" 时,不允许使用非相对路径。是否忘记了前导 "./",所以添加一个baseUrl
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}
规范目录
├── publish/
└── src/
├── api/ // api接口目录
├── assets/ // 静态资源目录
├── common/ // 通用类库目录
├── components/ // 公共组件目录
├── router/ // 路由配置目录
├── store/ // 状态管理目录
├── style/ // 通用 CSS 目录
├── plugins/ // 插件目录
├── utils/ // 工具函数目录
├── server/ // 请求封装目录
├── views/ // 页面组件目录
├── App.vue
├── main.ts
├── shims-vue.d.ts
├── tests/ // 单元测试目录
├── index.html
├── tsconfig.json // TypeScript 配置文件
├── vite.config.ts // Vite 配置文件
└── package.json
集成路由 router
-
安装支持 Vue3 的路由工具 vue-router@4
npm i vue-router@4
-
创建 src/router/index.ts 文件
在 src 下创建 router 目录,然后在 router 目录里新建 index.ts 文件:
└── src/
├── router/
├── index.ts // 路由配置文件
import {
createRouter,
createWebHashHistory,
RouteRecordRaw
} from 'vue-router'
import Home from '@/views/home.vue'
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import('@/views/about.vue') // 懒加载组件
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
根据本项目路由配置的实际情况,你需要在 src 下创建 views 目录,用来存储页面组件。我们在 views 目录下创建 home.vue 、about.vue 。
-
在main.ts挂载路由配置
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
const app = createApp(App)
app.use(router)
app.mount('#app')
状态管理 pinia
-
安装:
yarn add pinia
-
src下的main.ts添加:
# 引入
import { createPinia } from "pinia"
# 创建根存储库并将其传递给应用程序
app.use(createPinia())
在 src 文件夹下新增 store 文件夹,接在在 store 中新增 main.ts
-
在store下创建main.ts:
import { defineStore } from 'pinia'
export const useMainStore = defineStore({
id: 'mian',
state: () =>({
name: '超级管理员'
})
})
-
组件中获取:
<template>
<div>{{mainStore.name}}</div>
</template>
<script setup lang="ts">
import { useMainStore } from "@/store/mian"
const mainStore = useMainStore()
</script>
集成UI框架 Element plus
-
安装:
# NPM
$ npm install element-plus --save
# Yarn
$ yarn add element-plus
# pnpm
$ pnpm install element-plus
-
main.ts挂载:
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from "pinia"
import router from './router/index'
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(router)
app.use(createPinia())
app.use(ElementPlus)
app.mount('#app')
-
组件中使用:
<template>
<div>
{{ mainStore.name }}
<el-button>点击</el-button>
</div>
</template>
<script setup lang="ts">
import { useMainStore } from './store/main';
const mainStore = useMainStore()
</script>
<style scoped>
</style>
集成HTTP工具Axios
-
安装:
# NPM
$ npm install axios
# Yarn
$ yarn add axios
# pnpm
$ pnpm install axios
-
配置:
为了使项目的目录结构合理且规范,我们在 src 下创建 server 目录来存储我们常用的工具函数。Axios 作为 HTTP 工具,我们在 server 目录下创建 server.ts 作为 Axios 配置文件:
└── src/
├── server/
├── server.ts // Axios 配置文件
├── tools.ts // Axios 工具
├── errorCode.ts // 错误处理文件
server.ts:
import axios from 'axios'
import { ElNotification, ElMessage } from 'element-plus'
import { tansParams } from './tools.ts'
import errorCode from './errorCode.ts'
const service = axios.create({
baseURL: '',
timeout: 10000,
})
/**
* @description: 请求拦截
*/
service.interceptors.request.use(
(config) => {
// get请求映射params参数
if (config.method === 'get' && config.params) {
let url = config.url + '?' + tansParams(config.params)
url = url.slice(0, -1)
config.params = {}
config.url = url
}
return config
},
(error) => {
Promise.reject(error)
},
)
/**
* @description: 响应拦截
*/
service.interceptors.response.use(
(res) => {
// 未设置状态码则默认成功状态
const code = res.data.code || 200
// 获取错误信息
const msg = errorCode[code] || res.data.msg || errorCode.default
if (code === 401) {
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
} else if (code === 500) {
ElMessage({ message: msg, type: 'error' })
return Promise.reject(new Error(msg))
} else if (code === 601) {
ElMessage({ message: msg, type: 'warning' })
return Promise.reject(new Error(msg))
} else if (code !== 200) {
ElNotification.error({ title: '系统错误请联系管理员' })
return Promise.reject('error')
}
return Promise.resolve(res.data)
},
(error) => {
let { message } = error
if (message === 'Network Error') {
message = '后端接口连接异常'
} else if (message.includes('timeout')) {
message = '系统接口请求超时'
} else if (message.includes('Request failed with status code')) {
message = '系统接口' + message.substr(message.length - 3) + '异常'
}
ElMessage({ message: message, type: 'error', duration: 3 * 1000 })
return Promise.reject(error)
},
)
export default service
tools.ts:
/**
* 参数处理
* @param {*} params 参数
*/
export function tansParams(params: any) {
let result = ''
for (const propName of Object.keys(params)) {
const value = params[propName]
const part = encodeURIComponent(propName) + '='
if (value !== null && value !== '' && typeof value !== 'undefined') {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
// eslint-disable-next-line max-depth
if (value[key] !== null && value[key] !== '' && typeof value[key] !== 'undefined') {
const params = propName + '[' + key + ']'
const subPart = encodeURIComponent(params) + '='
result += subPart + encodeURIComponent(value[key]) + '&'
}
}
} else {
result += part + encodeURIComponent(value) + '&'
}
}
}
return result
}
errorCode.ts:
export default {
'401': '认证失败,无法访问系统资源',
'403': '当前操作没有权限',
'404': '访问资源不存在',
default: '系统未知错误,请反馈给管理员',
} as any
-
使用:
在src添加api文件夹并在添加login文件夹,在login文件夹里添加login.ts以及types.ts:
└── src/
├── api/
├── login/
├── login.ts // 登录接口文件
├── types.ts // 类型判断
login.ts:
import service from '@/server/server.ts'
import * as T from './types.ts'
export function login(data: T.ILoginParams){
return service({
url: '/login',
headers: {
isToken: false
},
method: 'post',
data: data
})
}
types.ts:
export interface ILoginParams {
userName: string
passWord: string | number
}
集成CSS 预编译器 Stylus/Sass
虽然 vite 原生支持 less/sass/scss/stylus,但是你必须手动安装他们的预处理器依赖
-
安装:
yarn add dart-sass --dev
yarn add sass --dev
-
使用:
配置全局 scss 样式文件,在src/style 文件夹,新建 main.scss, 设置一个用于测试的颜色变量 :
$test-color: red;
如何将这个全局样式文件全局注入到项目中呢?配置 Vite 即可:
css:{
preprocessorOptions:{
scss:{
additionalData:'@import "@/style/main.scss";'
}
}
},
-
组件中使用:
<template>
<div class="div">
{{ mainStore.name }}
<el-button>点击</el-button>
</div>
</template>
<script setup lang="ts">
import { useMainStore } from './store/main';
const mainStore = useMainStore()
</script>
<style scoped lang="scss">
.div{
color: $test-color;
}
</style>
(未完 – 下一节集成代码规范+提交规范)
原文始发于微信公众号(前端大大大):Vue3+TS+Vite脚手架搭建全过程(一)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/174146.html