技术栈
-
⚡️ Vite 3 - 构建工具(就是快!)
-
🖖 Vue 3 - 渐进式 JavaScript 框架
-
🚦 Vue Router - 官方路由管理器
-
📦 Pinia - 值得你喜欢的 Vue Store
-
💻 TDesign - TDesign 适配桌面端的组件库
-
🎨 Less - CSS 预处理器
-
🔗 Axios - 一个基于 promise 的网络请求库,可以用于浏览器和 node.js
-
🧰 Husky + Lint-Staged - Git Hook 工具
-
🛡️ EditorConfig + ESLint + Prettier + Stylelint - 代码规范
-
🔨 Commitizen + Commitlint - 提交规范
-
💡 GitHub Actions - 自动部署
基础搭建
构建项目雏形
在项目的命令行中运行以下命令:
//确保安装了最新版本的 node
node -v //v20.5.1
npm -v //9.8.1
//npm 7+, extra double-dash is needed:
npm create vite@latest vite-vue3-starter -- --template vue
这一指令将会安装并执行 create-vite,它是一个基本模板快速启动项目工具。
在项目被创建后,通过以下步骤安装依赖并启动开发服务器:
//进入项目
cd vite-vue3-starter
// 安装依赖
npm install
// 启动项目
npm run dev
Vite 基础配置
Vite 配置文件 vite.config.js 位于项目根目录下,项目启动时会自动读取。
修改配置:
- 公共基础路径
- 自定义路径别名
- 服务器选项
- 构建选项
- (关于 Vite 更多配置项及用法,请查看 Vite 官网 vitejs.dev/config/)
import { defineConfig } from 'vite'
import { resolve } from 'path';
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
base: './',
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, './src') ,
},
},
server: {
// 是否开启 https
https: false,
// 端口号
port: 3000,
// 监听所有地址
host: '0.0.0.0',
// 服务启动时是否自动打开浏览器
open: true,
// 允许跨域
cors: true,
// 自定义代理规则
proxy: {},
},
build: {
// 设置最终构建的浏览器兼容目标
target: 'es2015',
// 构建后是否生成 source map 文件
sourcemap: false,
// chunk 大小警告的限制(以 kbs 为单位)
chunkSizeWarningLimit: 2000,
// 启用/禁用 gzip 压缩大小报告
reportCompressedSize: false,
},
})
规范目录结构
├── dist/
└── src/
├── api/ // 接口请求目录
├── assets/ // 静态资源目录
├── common/ // 通用类库目录
├── components/ // 公共组件目录
├── router/ // 路由配置目录
├── store/ // 状态管理目录
├── style/ // 通用样式目录
├── utils/ // 工具函数目录
├── views/ // 页面组件目录
├── App.vue
├── main.js
├── tests/ // 单元测试目录
├── index.html
├── jsconfig.json // JavaScript 配置文件
├── vite.config.js // Vite 配置文件
└── package.json
集成 Vue Router 路由工具
安装依赖
npm i vue-router@4
创建路由配置文件
在 src/router 目录下新建 index.js 文件与 modules 文件夹
└── src/
├── router/
├── modules/ // 路由模块
├── index.js // 路由配置文件
关于路由表,建议根据功能的不同来拆分到 modules 文件夹中,好处是:
- 方便后期维护
- 减少 Git 合并代码冲突可能性
我们在modules文件夹下创建一个demo文件夹,用来存放基本的路由信息。同样也要在src下创建views目录,并且在该目录下创建HomeView.vue、PiniaView.vue。
export default [
{
path: '/',
name: 'home',
component: () => import('@/views/HomeView.vue'),
},
{
path: '/pinia',
name: 'pinia',
component: () => import('@/views/PiniaView.vue'),
},
];
//路由配置文件
import { createRouter, createWebHistory } from "vue-router";;
import baseRouters from './modules/base';
const routes = [...baseRouters];
const router = createRouter({
history: createWebHistory(import.meta.evn.BASE_URL),
routes,
scrollBehavior() {
return {
el: '#app',
top: 0,
behavior:'smooth',
};
},
});
export default router;
解释两个关键字
1、 createWebHistory
createWebHistory 是 Vue Router 提供的一种基于浏览器 history API 的路由模式,
它使用了 HTML5 中的 history.pushState 和 history.replaceState 方法来实现路由跳转。这种模式可以使得 URL 更加直观,而且不会在 URL 中添加任何特殊字符。
2、 scrollBehavior
scrollBehavior 是一种 “记录浏览器滚动条默认位置” 的解决方案。
考虑一种情景: 用户在一个商品列表中查看详情页以后,想要返回列表页刚刚浏览的位置,这种需求该如何实现?
在用户切换页面后,列表页组件已经被销毁,所以重新返回到列表页后页面会置顶,需要重新下拉查看列表,这样就做了很多没有必要的操作,也是不符合用户的预期。
大概有3种解决方案:
- 第一种:使用 vue-router 的方法
scrollBehavior(推荐)- 注意: 这个功能只在支持
history.pushState的浏览器中可用
const scrollBehavior = function scrollBehavior (to, from, savedPosition) { if (savedPosition) { return savedPosition; }else { return { x: 0, y: 0 } } }; const router = new Router({ routes, scrollBehavior, }); - 注意: 这个功能只在支持
- 第二种:使用路由守卫(组件内守卫)
- 原理:在beforRouterLeave的路由钩子记录当前页面滚动位置
//在页面离开时记录滚动位置 beforeRouteLeave (to, from, next) { this.scrollTop = document.documentElement.scrollTop || document.body.scrollTop next() }, //进入该页面时,用之前保存的滚动位置赋值 beforeRouteEnter (to, from, next) { next(vm => { document.body.scrollTop = vm.scrollTop }) }, - 第三种:使用 缓存
// App.vue <template> <div id="app"> <!-- <router-view/> --> <keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive" /> </div> </template>// router.js routes: [ { path: '/', name: 'List', component: () => import('./views/index/list.vue'), meta: { keepAlive: true // 需要缓存 } }, { path: '/content/:contentId', name: 'content', component: () => import('./views/index/content.vue'), meta: { keepAlive: false // 不需要缓存 } }, ]
创建路由配置文件
在 main.js 文件中挂载路由配置
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
集成 Pinia 全局状态管理工具
安装依赖
npm i pinia
创建仓库配置文件
在 src/store 目录下新建 index.js 文件与 modules 文件夹
开发中需要将不同功能所对应的状态,拆分到不同的 modules,好处如同路由模块一样。
└── src/
├── store/
├── modules/ // 仓库模块
├── index.js // 仓库配置文件
// src/store/modules/counter.js
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 1,
}),
actions: {
accumulate() {
this.count++;
},
},
});
// src/store/index.js
import { createPinia } from 'pinia';
const store = createPinia();
export default store;
export * from './modules/counter';
挂载 Pinia 配置
在 main.js 文件中挂载 Vuex 配
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import store from './store';
createApp(App).use(router).use(store).mount('#app')
Pinia 和 Vuex 区别
Pinia和Vuex都是Vue.js状态管理库,但它们在一些方面有所不同。
- Pinia是一个
轻量级的状态管理库,它专注于提供一个简单的API来管理应用程序的状态。相比之下,Vuex是一个更完整的状态管理库,它提供了更多的功能,比如模块化、插件和严格模式等; - Pinia是基于
Vue 3 的 Composition API构建的,这使得它更加灵活和可组合。而 Vuex 则是基于Vue 2 的 Options API构建的,因此在某些方面可能会受到限制。 - Pinia采用了
类似于React Hooks的方式来管理状态,这使得它更加直观和易于使用。Vuex则采用了一种基于 mutations 和 actions 的方式来管理状态,这可能需要更多的代码来实现相同的功能。
集成 TDesign Vue Next 组件库
安装依赖
npm i tdesign-vue-next
基础使用
全局使用
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import store from './store';
import TDesign from 'tdesign-vue-next';
import 'tdesign-vue-next/es/style/index.css'; // 引入组件库全局样式资源
createApp(App).use(router)
.use(store)
.use(TDesign)
.mount('#app')
通过插件按需引用使用
使用 unplugin-vue-components 和 unplugin-auto-import 来实现自动导入
npm install unplugin-vue-components unplugin-auto-import -D
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import store from './store';
import 'tdesign-vue-next/es/style/index.css'; // 引入组件库全局样式资源
createApp(App).use(router).use(store).mount('#app')
在 Vite 对应的配置文件 vite.config.js 添加上述插件:
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import { TDesignResolver } from 'unplugin-vue-components/resolvers';
export default {
plugins: [
AutoImport({
resolvers: [TDesignResolver({
library: 'vue-next'
})],
}),
Components({
resolvers: [TDesignResolver({
library: 'vue-next'
})],
}),
],
};
}
集成 Axios HTTP 工具
安装依赖
npm i axios
请求配置
在 utils 目录下创建 request.js 文件,配置好适合自己业务的请求拦截和响应拦截
└── src/
├── api // 接口
├── utils/
├── request.js // axios 请求库二次封装
// src/utils/request.js
import axios from 'axios';
// 创建请求实例
const instance = axios.create({
baseURL: '/api',
// 指定请求超时的毫秒数
timeout: 1000,
// 表示跨域请求时是否需要使用凭证
withCredentials: false,
});
// 前置拦截器(发起请求之前的拦截)
instance.interceptors.request.use(
(config) => {
/**
* 在这里一般会携带前台的参数发送给后台,比如下面这段代码:
* const token = getToken()
* if (token) {
* config.headers.token = token
* }
*/
return config;
},
(error) => {
return Promise.reject(error);
},
);
// 后置拦截器(获取到响应时的拦截)
instance.interceptors.response.use(
(response) => {
/**
* 根据你的项目实际情况来对 response 和 error 做处理
* 这里对 response 和 error 不做任何处理,直接返回
*/
return response;
},
(error) => {
const { response } = error;
if (response && response.data) {
return Promise.reject(error);
}
const { message } = error;
console.error(message);
return Promise.reject(error);
},
);
// 导出常用函数
/**
* @param {string} url
* @param {object} data
* @param {object} params
*/
export const post = (url, data = {}, params = {}) => {
return instance({
method: 'post',
url,
data,
params,
});
};
/**
* @param {string} url
* @param {object} params
*/
export const get = (url, params = {}) => {
return instance({
method: 'get',
url,
params,
});
};
/**
* @param {string} url
* @param {object} data
* @param {object} params
*/
export const put = (url, data = {}, params = {}) => {
return instance({
method: 'put',
url,
params,
data,
});
};
/**
* @param {string} url
* @param {object} params
*/
export const _delete = (url, params = {}) => {
return instance({
method: 'delete',
url,
params,
});
};
export default instance;
在 api 文件夹中以业务模型对接口进行拆分,比如将所有跟用户相关接口封装在 User 类中,此类称作用户模型。
在 User 类中比如有登录、注册、获取用户信息等方法,如果有业务逻辑变动,只需要修改相关方法即可。
import { post } from '@/utils/request';
export default class User {
/**
* 登录
* @param {String} username 用户名
* @param {String} password 密码
* @returns
*/
static async login(username, password) {
return post('/login', {
username,
password,
});
}
}
模拟演示
<script>
import User from '@/api/user';
export default {
data() {
return {
username: '',
password: '',
};
},
methods: {
async login() {
const res = await User.login(this.username, this.password);
console.log(res);
},
},
};
</script>
集成 CSS 预处理器 Less
本项目使用 CSS 预处理器 Less,直接安装为开发依赖即可。
Vite 内部已帮我们集成了相关的 loader,不需要额外配置。
npm i less -D
如何使用
在 <style></style> 样式标签中引用 lang="less" 即可。
<style lang="less"></style>
全局样式
在 src/style 目录下创建 variables.less 全局样式文件:
└── src/
├── style/
├── variables.less // 全局样式文件
在 vite.config.js 配置文件中新增CSS 预处理器相关配置即可实现 less 全局样式:
import { resolve } from 'path';
export default defineConfig({
css: {
preprocessorOptions: {
less: {
modifyVars: {
hack: `true; @import (reference) "${resolve('src/style/variables.less')}";`,
},
math: 'strict',
javascriptEnabled: true,
},
},
},
});
样式穿透
在 Vue3 中,改变了以往样式穿透的语法,如果继续使用 ::v-deep、/deep/、>>> 等语法的话,会出现一个警告,下面是新的语法:
/* 深度选择器 */
:deep(selector) {
/* ... */
}
/* 插槽选择器 */
:slotted(selector) {
/* ... */
}
/* 全局选择器 */
:global(selector) {
/* ... */
}
至此,一个基于 JavaScript + Vite3 + Vue3 + Vue Router + Pinia + Axios + Less 的前端项目开发环境搭建完毕。
代码规范
如何使用 EditorConfig + ESLint + Prettier + Stylelint 组合来实现代码规范化。
-
解决团队之间代码不规范导致的可读性差和可维护性差的问题。
-
解决团队成员不同编辑器导致的编码规范不统一问题。
-
提前发现代码风格问题,给出对应规范提示,及时修复。
-
减少代码审查过程中反反复复的修改过程,节约时间。
-
自动格式化,统一编码风格,从此和脏乱差的代码说再见。
集成 EditorConfig 配置
EditorConfig 主要用于统一不同 IDE 编辑器的编码风格。
在项目根目录下添加 .editorconfig 文件:
# 表示是最顶层的 EditorConfig 配置文件
root = true
# 表示所有文件适用
[*]
# 缩进风格(tab | space)
indent_style = space
# 控制换行类型(lf | cr | crlf)
end_of_line = lf
# 设置文件字符集为 utf-8
charset = utf-8
# 去除行首的任意空白字符
trim_trailing_whitespace = true
# 始终在文件末尾插入一个新行
insert_final_newline = true
# 表示仅 md 文件适用以下规则
[*.md]
max_line_length = off
trim_trailing_whitespace = false
# 表示仅 ts、js、vue、css 文件适用以下规则
[*.{ts,js,vue,css}]
indent_size = 2
很多 IDE 中会默认支持此配置,但是也有些不支持,如:VSCode、Atom、Sublime Text 等。 具体列表可以参考官网,如果在 VSCode 中使用需要安装
EditorConfig for VS Code插件。
集成 ESLint 配置
ESLint 是针对 EScript 的一款代码检测工具,它可以检测项目中编写不规范的代码,如果写出不符合规范的代码会被警告。
由此我们就可以借助于 ESLint 强大的功能来统一团队的编码规范。
安装依赖
-
ESLint- ESLint 本体 -
eslint-define-config- 改善 ESLint 规范编写体验 -
eslint-plugin-vue- 适用于 Vue 文件的 ESLint 插件 -
eslint-config-airbnb-base- Airbnb JavaScript 风格指南 -
eslint-plugin-import- 使用eslint-config-airbnb-base时必须安装的前置插件 -
vue-eslint-parser- 使用eslint-plugin-vue时必须安装的 ESLint 解析器
npm i eslint eslint-define-config eslint-config-airbnb-base eslint-plugin-import eslint-plugin-vue vue-eslint-parser -D
安装插件
Visual Studio Code 编辑器使用 ESLint 配置需要下载插件 ESLint 。
创建 ESLint 配置文件
在项目根目录创建 .eslintrc.js 文件,并填入以下内容:
const { defineConfig } = require('eslint-define-config');
module.exports = defineConfig({
root: true,
env: {
browser: true,
node: true,
jest: true,
es6: true,
},
plugins: ['vue'],
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
allowImportExportEverywhere: true,
ecmaFeatures: {
jsx: true,
},
},
extends: [
'eslint-config-airbnb-base',
'eslint:recommended',
'plugin:vue/vue3-essential',
'plugin:vue/vue3-recommended',
'plugin:prettier/recommended',
],
rules: {
// 禁止使用多余的包
'import/no-extraneous-dependencies': 0,
// 确保在导入路径内一致使用文件扩展名
'import/extensions': 0,
// 确保导入指向可以解析的文件/模块
'import/no-unresolved': 0,
// 首选默认导出导入/首选默认导出
'import/prefer-default-export': 0,
// 要求使用 let 或 const 而不是 var
'no-var': 'error',
// 禁止使用 new 以避免产生副作用
'no-new': 1,
// 禁止变量声明与外层作用域的变量同名
'no-shadow': 0,
// 禁用 console
'no-console': 0,
// 禁止标识符中有悬空下划线
'no-underscore-dangle': 0,
// 禁止在可能与比较操作符相混淆的地方使用箭头函数
'no-confusing-arrow': 0,
// 禁用一元操作符 ++ 和 --
'no-plusplus': 0,
// 禁止对 function 的参数进行重新赋值
'no-param-reassign': 0,
// 禁用特定的语法
'no-restricted-syntax': 0,
// 禁止在变量定义之前使用它们
'no-use-before-define': 0,
// 禁止直接调用 Object.prototypes 的内置属性
'no-prototype-builtins': 0,
// 禁止可以在有更简单的可替代的表达式时使用三元操作符
'no-unneeded-ternary': 'error',
// 禁止重复模块导入
'no-duplicate-imports': 'error',
// 禁止在对象中使用不必要的计算属性
'no-useless-computed-key': 'error',
// 禁止不必要的转义字符
'no-useless-escape': 0,
// 禁用 continue 语句
'no-continue': 0,
// 强制使用一致的缩进
indent: ['error', 2, { SwitchCase: 1 }],
// 强制使用骆驼拼写法命名约定
camelcase: 0,
// 强制类方法使用 this
'class-methods-use-this': 0,
// 要求构造函数首字母大写
'new-cap': 0,
// 强制一致地使用 function 声明或表达式
'func-style': 0,
// 强制一行的最大长度
'max-len': 0,
// 要求 return 语句要么总是指定返回的值,要么不指定
'consistent-return': 0,
// 强制switch要有default分支
'default-case': 2,
// 强制剩余和扩展运算符及其表达式之间有空格
'rest-spread-spacing': 'error',
// 要求使用 const 声明那些声明后不再被修改的变量
'prefer-const': 'error',
// 强制箭头函数的箭头前后使用一致的空格
'arrow-spacing': 'error',
// 只强制对象解构,不强制数组解构
'prefer-destructuring': ['error', { object: true, array: false }],
},
});
关于更多配置项信息,请前往 ESLint 官网查看 ESLint-Configuring
创建 ESLint 过滤规则
在项目根目录添加一个 .eslintignore 文件,内容如下:
dist
node_modules
!.prettierrc.js
components.d.ts
auto-imports.d.ts
集成 Prettier 配置
Prettier 是一款强大的代码格式化工具,支持 JavaScript、TypeScript、CSS、SCSS、Less、JSX、Angular、Vue、GraphQL、JSON、Markdown 等语言,基本上前端能用到的文件格式它都可以搞定,是当下最流行的代码格式化工具。
安装依赖
npm i prettier -D
安装插件
Visual Studio Code 编辑器使用 Prettier 配置需要下载插件 Prettier - Code formatter
创建 Prettier 配置文件
Prettier 支持多种格式的配置文件,比如 .json、.yml、.yaml、.js等。
在项目根目录创建 .prettierrc.js 文件,并填入以下内容:
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,
// jsx 标签的反尖括号需要换行
jsxBracketSameLine: false,
// 箭头函数,只有一个参数的时候,也需要括号
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',
// 格式化嵌入的内容
embeddedLanguageFormatting: 'auto',
// html, vue, jsx 中每个属性占一行
singleAttributePerLine: false,
};
关于更多配置项信息,请前往 Prettier 官网查看 Prettier-Options
创建 Prettier 过滤规则
在项目根目录添加一个 .prettierignore 文件,内容如下:
## OS
.DS_Store
.idea
.editorconfig
pnpm-lock.yaml
.npmrc
# Ignored suffix
*.log
*.md
*.svg
*.png
*.ico
*ignore
## Local
.husky
## Built-files
.cache
dist
解决 Prettier 和 ESLint 冲突
本项目中的 ESLint 配置使用了 Airbnb JavaScript 风格指南校验,其规则之一是代码结束后面要加分号,而在 Prettier 配置文件中加了代码结束后面不加分号配置项,从而冲突了。
解决两者冲突问题,需要用到 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
修改 ESLint 配置文件
修改 .eslintrc.js 文件,在 extends 中添加 plugin:prettier/recommended 规则(此规则一定要加在最后)
module.exports = {
extends: [
'airbnb-base',
'eslint:recommended',
'plugin:vue/vue3-essential',
'plugin:vue/vue3-recommended',
'plugin:prettier/recommended'
],
}
自动格式化代码
Visual Studio Code 在 settings.json 设置文件中,增加以下代码:
{
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.fixAll.eslint": true
}
}
集成 Stylelint 配置
Stylelint 是一个强大、先进的 CSS 代码检查器(linter),可以帮助你规避 CSS 代码中的错误并保持一致的编码风格。
安装依赖
-
Stylelint- Stylelint 本体 -
stylelint-less- Stylelint Less 规则 -
stylelint-config-prettier- 关闭 Stylelint 中与 Prettier 中会发生冲突的规则 -
stylelint-config-standard- Stylelint 官方推荐规则 -
stylelint-config-recess-order- 对 CSS 声明进行排序 -
stylelint-order- CSS 属性顺序规则插件
npm i stylelint stylelint-less stylelint-config-prettier stylelint-config-standard stylelint-config-recess-order stylelint-order -D
安装插件
创建 Stylelint 配置文件
module.exports = {
root: true,
defaultSeverity: 'error',
plugins: ['stylelint-order', 'stylelint-less'],
extends: [
'stylelint-config-standard', // the standard shareable config for Stylelint
'stylelint-config-html/html', // the shareable html config for Stylelint.
'stylelint-config-html/vue', // the shareable vue config for Stylelint.
'stylelint-config-recess-order', // use the clean order for properties
'stylelint-config-prettier', // turn off any rules that conflict with Prettier
],
rules: {
// 禁止在覆盖高特异性选择器之后出现低特异性选择器
'no-descending-specificity': null,
// 禁止空源码
'no-empty-source': null,
// 禁止字体族中缺少泛型族关键字
'font-family-no-missing-generic-family-keyword': null,
// 禁止未知的@规则
'at-rule-no-unknown': [
true,
{
ignoreAtRules: [
'tailwind',
'apply',
'variants',
'responsive',
'screen',
'function',
'if',
'each',
'include',
'mixin',
],
},
],
// 不允许未知函数
'function-no-unknown': null,
// 不允许未知单位
'unit-no-unknown': [true, { ignoreUnits: ['rpx'] }],
// 不允许选择器使用供应商前缀
'selector-no-vendor-prefix': null,
// 指定关键帧名称的模式
'keyframes-name-pattern': null,
// 指定类选择器的模式
'selector-class-pattern': null,
// 不允许值使用供应商前缀
'value-no-vendor-prefix': null,
// 要求或禁止在规则之前的空行
'rule-empty-line-before': ['always', { ignore: ['after-comment', 'first-nested'] }],
// 指定字符串使用单引号
'string-quotes': 'single',
// 指定@规则名的大小写
'at-rule-name-case': 'lower',
// 指定缩进
indentation: [2, { severity: 'warning' }],
},
ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.tsx', '**/*.ts'],
};
创建 Stylelint 过滤规则
# .stylelintignore
# 旧的不需打包的样式库
*.min.css
# 其他类型文件
*.js
*.jpg
*.woff
# 测试和打包目录
/test/
/dist/*
/public/*
public/*
/node_modules/
启用 Vue 文件支持
Stylelint v14 版本默认不支持 vue 文件中的 style 代码自动检测,详情查看官方迁移指南
安装依赖
stylelint-config-html- 解析 vue 文件postcss-html- 使用stylelint-config-html依赖的模块postcss-less- 对 less 文件进行解析
npm i stylelint-config-html postcss-html postcss-less -D
修改 Stylelint 配置文件
修改 .stylelintrc.js 文件,添加如下配置:
module.exports = {
overrides: [
{
files: ['*.vue', '**/*.vue', '*.html', '**/*.html'],
customSyntax: 'postcss-html',
rules: {
// 禁止未知的伪类选择器
'selector-pseudo-class-no-unknown': [true, { ignorePseudoClasses: ['deep', 'global'] }],
// 禁止未知的伪元素选择器
'selector-pseudo-element-no-unknown': [true, { ignorePseudoElements: ['v-deep', 'v-global', 'v-slotted'] }],
},
},
{
files: ['*.less', '**/*.less'],
customSyntax: 'postcss-less',
rules: {
'less/color-no-invalid-hex': true,
'less/no-duplicate-variables': true,
},
},
],
};
修改 Visual Studio Code 工作区配置
Visual Studio Code 在 settings.json 设置文件中,增加以下代码:
{
"stylelint.validate": ["css", "less", "postcss", "scss", "vue", "sass", "html"]
}
集成 husky 和 lint-staged
在项目中已集成 ESLint 和 Prettier,在编码时,这些工具可以对代码进行实时校验,在一定程度上能有效规范所写代码,但有些人可能觉得这些限制很麻烦,从而选择视“提示”而不见,依旧按自己编程风格来写代码,或者干脆禁用掉这些工具,开发完成就直接把代码提交到了仓库,日积月累,ESLint 也就形同虚设。
所以,还需要做一些限制,让没通过 ESLint 检测和修复的代码禁止提交,从而保证仓库代码都是符合规范的。
为了解决这个问题,需要用到 Git Hook,在本地执行 git commit 的时候,就对所提交的代码进行 ESLint 检测和修复(即执行 eslint --fix),如果这些代码没通过 ESLint 规则校验,则禁止提交。
实现这一功能,需要借助 husky + lint-staged 。
配置 husky
注意:本项目使用 husky 6.x 版本,6.x 版本配置方式跟之前版本有较大差异,当发现配置方法不一致时,一切以 husky 官网为准。 使用
husky-init命令快速在项目初始化husky配置:
# 初始化仓库
git init
# 初始化
npx husky-init
# 安装依赖
npm install
husky 包含很多 hook(钩子),常用有:pre-commit、commit-msg。
使用 pre-commit 来触发 ESLint 命令,修改 .husky/pre-commit 文件触发命令:
eslint --fix ./src --ext .vue,.js,.ts
pre-commit hook 文件作用是:当执行 git commit -m "xxx" 时,会先对 src 目录下所有的 .vue、.js、.ts 文件执行 eslint --fix 命令,如果 ESLint 通过,成功 commit,否则终止 commit。
但是又存在一个问题:有时候明明只改动了一两个文件,却要对所有的文件执行 `eslint --fix`。
假如这是一个历史项目,在中途配置了 ESLint 规则,那么在提交代码时,也会对其他未修改的“历史”文件都进行检查,可能会造成大量文件出现 ESLint 错误,显然这不是我们想要的结果。
所以只需要用 ESLint 修复此次写的代码,而不去影响其他的代码,此时需要借助 lint-staged 工具。
配置 lint-staged
lint-staged 一般结合 husky 来使用,它可以让 husky 的 hook 触发的命令只作用于 git 暂存区的文件,而不会影响到其他文件。
安装依赖
npm i lint-staged -D
新增配置
在 package.json 里增加 lint-staged 配置项:
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"prettier --write",
"eslint --fix"
],
"*.vue": [
"prettier --write",
"eslint --fix",
"stylelint --fix"
],
"*.{html,vue,vss,sass,less}": [
"prettier --write",
"stylelint --fix"
],
"package.json": [
"prettier --write"
],
"*.md": [
"prettier --write"
]
},
}
修改触发命令
npx lint-staged
经过以上配置之后,就可以在每次提交之前对所有代码进行格式化,保证线上代码的规范性。
提交规范
多人协作项目中,在提交代码环节,也存在一种情况:不能保证每个人对提交信息的准确描述,因此会出现提交信息紊乱、风格不一致的情况。
如果 git commit 的描述信息精准,在后期维护和 Bug 处理时会变得有据可查,项目开发周期内还可以根据规范的提交信息快速生成开发日志,从而方便我们追踪项目和把控进度。
集成 commitlint 验证规范提交
在“代码规范”章节中提到,尽管制定了规范,但在多人协作的项目中,总有些人依旧我行我素。
因此提交代码这个环节,也增加一个限制:只让符合 Angular 规范的 commit message 通过。
此功能需借助 @commitlint/config-conventional 和 @commitlint/cli 工具来实现。
安装
npm i @commitlint/cli @commitlint/config-conventional -D
配置
在项目根目录创建 commitlint.config.js 文件,并填入以下内容:
module.exports = {
extends: ['@commitlint/config-conventional']
}
使用 husky 命令在 .husky 目录下创建 commit-msg 文件,并在此执行验证命令:
npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"
自动部署
本章节将介绍如何使用 CI(Continuous Integration 持续集成)服务来完成项目部署工作。
本项目使用 GitHub Actions 来完成这一操作。
GitHub Actions 入门教程
创建 GitHub 仓库
因为 GitHub Actions 只对 GitHub 仓库有效,所以创建 GitHub 仓库来托管项目代码
master分支存储项目源代码gh-pages分支存储打包后的静态文件
创建 GitHub Token
创建一个有 repo 和 workflow 权限的 GitHub Token
添加 Actions secret
将上述创建的 Token 添加到 GitHub 仓库中的 Secrets 里,并将这个新增的 secret 命名为 VITE_VUE_DEPLOY 。
步骤:仓库 -> Settings -> Secrets -> Actions -> New repository secret。
修改 package.json
打开 package.json 文件,新增 homepage 字段,表示该应用发布后的根目录(参见官方文档)。
创建 Actions 配置文件
(1)在项目根目录下创建 .github 目录。
(2)在 .github 目录下创建 workflows 目录。
(3)在 workflows 目录下创建 deploy.yml 文件。
name: Vite Vue Deploy
on:
push:
# master 分支有 push 时触发
branches: [master]
jobs:
deploy:
# 指定虚拟机环境
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16.x]
steps:
- name: Checkout
# 拉取 GitHub 仓库代码
uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
# 设定 Node.js 环境
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Install
# 安装依赖
run: npm install
- name: Build
# 打包
run: npm run build
- name: Deploy
uses: JamesIves/github-pages-deploy-action@v4
with:
# 部署打包目录
folder: dist
# 密钥名
token: ${{ secrets.VITE_VUE_DEPLOY }}
# 分支
branch: gh-pages
参考出处
本文仅作为自己的学习笔记,文章出处以及源码看原作者:威廉王子