1 背景
经常会遇到时间紧迫的新项目需求
这时候,一个开箱即用的初始化工程是非常有必要的
2 初始化vite项目
Node.js 版本为 v14.19.3
npm 版本为 v6.14.17
// 安装 vite 构建工具
npm init vite@latest
// 使用 vue-ts 模板,vite提供多种模板,react、react-ts 等。
npm init vite@latest vue3-ts-template -- --template vue-ts
// 安装依赖
npm i
// 运行
npm run dev
定义目录结构
├─ .husky
│ ├─ pre-commit # husky commit 钩子配置文件
│ ├─ commit-msg # husky commit 钩子配置文件
├─ .vscode
│ ├─ settings.json # vscode 项目配置文件
├─ mock # mock 模拟数据配置
├─ public
│ ├─ favicon.ico
├─ src
│ ├─ @types # ts 接口定义
│ ├─ api # api 接口
│ ├─ assets # 静态资源
│ ├─ components # 全局组件
│ ├─ layout # 布局
│ ├─ plugins # 插件
│ ├─ router # 路由
│ ├─ store # vuex store
│ ├─ styles # 全局样式
│ ├─ utils # 全局公共方法
│ └─ views # 所有页面
│ ├─ App.vue # 入口页面
│ ├─ main.ts # 入口文件
│ └─ shims-vue.d.ts # ts 适配定义文件
│ └─ auto-import.d.ts # unplugin-auto-import 插件生成全局类型定义文件
│ └─ components.d.ts # unplugin-vue-components 插件生成全局组件定义文件
├─ .env.development # 开发环境
├─ .env.production # 生产环境
├─ .env.test # 测试环境
├─ .eslintignore # eslint 忽略配置文件
├─ .eslintrc-auto-import.json # unplugin-auto-import/vite 插件解决eslint报错问题的配置项文件
├─ .eslintrc.js # eslintrc 配置
├─ .gitignore # git 忽略配置文件
├─ .prettierignore # prettier 忽略配置文件
├─ .prettierrc.json # prettierrc 配置文件
├─ .stylelintignore # stylelint 忽略配置文件
├─ .stylelintrc.js # stylelintrc 配置文件
├─ tsconfig.json # ts 编译配置
└─ vite.config.js # vite 配置
└─ package.json
└─ README.md
└─ index.html
3 vite.config.ts配置
3.1 配置别名
如果require('path') ts报红提示 npm i @types/node
执行 npm i -D @vue/cli-plugin-typescript(ts相关的工具集成起来的插件)
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
const { resolve } = require('path')
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
}
})
3.2 配置代理
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
server: {
open: true,
proxy: {
'/api': {
// 后端服务器地址
target: 'http://xxx.xx.x.xx:8099/',
// 代理完成后需要去掉api前缀
rewrite: (path) => path.replace(/^\/api/, ''),
// 将主机报头来源更改为目标地址
changeOrigin: true
}
}
}
})
3.3 配置全局sass文件
- 安装 sass
npm i -D sass node-sass sass-loader
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
css: {
// 配置全局 sass 文件
preprocessorOptions: {
scss: {
additionalData: '@use "src/styles/var.scss" as *;'
}
}
}
})
3.4 自动按需引入 element-plus 组件和自定义 compontent 组件
- 简介
自动引入后,再也不用引入和注册组件,和全局引用一样,可以直接在模板中使用,再也不用手动注册组件了,nice!- 安装UI库 element-plus
npm i element-plus- 安装按需引入样式插件
npm i -D vite-plugin-style-import- 自动按需导入组件、vue3等插件 hooks,省去大量的import操作
npm i -D unplugin-vue-components unplugin-auto-import- 如果运行报错提示 Cannot find module 'consola'
npm i -D consola
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// vue3等插件 hooks 自动引入
import AutoImport from 'unplugin-auto-import/vite'
// 按需引入element-plus样式
import { createStyleImportPlugin, ElementPlusResolve } from 'vite-plugin-style-import'
// 自动按需导入elementPlus组件
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
plugins: [
vue(),
// 引入 element-plus 样式
createStyleImportPlugin({
resolves: [ElementPlusResolve()],
libs: [
{
libraryName: 'element-plus',
esModule: true,
resolveStyle: (name) => {
return `element-plus/theme-chalk/${name}.css`
}
}
]
}),
AutoImport({
// 自动按需导入elementPlus组件
resolvers: [ElementPlusResolver()]
}),
Components({
// 要搜索组件的目录的相对路径,components下的组件会被自动注册引入
dirs: ['src/components'],
// 搜索子目录
deep: true,
// 组件的有效文件扩展名
extensions: ['vue'],
// 允许子目录作为组件的命名空间前缀。
directoryAsNamespace: false,
// 配置文件生成位置
dts: 'src/components.d.ts',
// 自动按需导入element-plus组件、修改主题色添加importStyle,使用预处理样式
resolvers: [ElementPlusResolver({ importStyle: 'sass' })]
})
]
})
3.5 配置 element-icon
- 安装依赖
npm i @element-plus/icons-vue
// 1、main.ts
import { createApp } from 'vue'
import App from './App.vue'
// 插件配置
import { loadAllPlugins } from './plugins'
const app = createApp(App)
// 加载所有插件
loadAllPlugins(app)
app.use(store).use(router).mount('#app')
// 2、plugins/index.ts 在 plugins 文件夹中配置各种插件,在 plugins 中新建elementIcon.ts 文件
import { createApp } from 'vue'
/** 加载插件文件 */
export function loadAllPlugins(app: ReturnType<typeof createApp>) {
const files = import.meta.globEager('./*.ts')
for (const path in files) {
if (typeof files[path].default === 'function') {
files[path].default(app)
}
}
}
// 3、elementIcon.ts
import * as ElIconModules from '@element-plus/icons-vue'
export default function loadElementIcon(app: any) {
for (const iconName in ElIconModules) {
if (Reflect.has(ElIconModules, iconName)) {
app.component(iconName, ElIconModules[iconName])
}
}
}
3.6 配置 vue3 hook自动引入
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// vue3等插件 hooks 自动引入
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
plugins: [
vue(),
AutoImport({
// 自动导入vue3的hook
imports: ['vue', 'vue-router', 'vue-i18n', '@vueuse/head','@vueuse/core'],
// auto-import.d.ts生成的位置
dts: 'src/auto-import.d.ts',
// 解决eslint报错问题的配置项
eslintrc: {
enabled: true, // 默认 'false'
filepath: './.eslintrc-auto-import.json',
globalsPropValue: true // 默认 'true'
}
})
]
})
3.7 自动导入生成 svg 雪碧图组件
- svg-icon 在日常项目中经常会用到 ,如何在vite中使用?
1、安装svg雪碧图插件
2、配置vite.config文件
3、注册雪碧图
4、新建SvgIcon.vue组件- 安装依赖
npm i path-browserify vite-plugin-svg-icons
// 1、vite.config.ts 配置svg
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path-browserify'
// 生成 svg 雪碧图
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
export default defineConfig({
plugins: [
vue(),
// 自动导入svg图片
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [path.resolve(process.cwd(), 'src/assets/svg')],
// 指定symbolId格式
symbolId: 'icon-[dir]-[name]',
inject: 'body-last',
customDomId: '__svg__icons__dom__'
})
]
})
// 2、mian.ts 注册雪碧图
import { createApp } from 'vue'
import App from './App.vue'
// 注册脚本(生成svg雪碧图)
import 'virtual:svg-icons-register'
createApp(App).mount('#app')
// 3、在 compontent 中新建 SvgIcon.vue 组件(由于配置了按需导入,此组件无需import导入)
<template>
<div class="svg-box">
<svg :class="svgClass" aria-hidden="true" :style="style">
<use :xlink:href="iconName" :fill="color" />
</svg>
</div>
</template>
<script lang="ts" setup>
defineOptions({
name: 'SvgIcon'
})
interface Style {
width?: string
height?: string
[index: string]: any
}
const props = defineProps({
name: {
type: String,
required: true
},
width: {
type: String,
default: ''
},
height: {
type: String,
default: ''
},
className: {
type: String,
default: ''
},
color: {
type: String,
default: 'red'
}
})
const style: Style = computed(() => {
const style: Style = {}
if (props.width) {
style.width = props.width + 'px'
style.height = (props.height || props.width) + 'px'
}
return style
})
const iconName = computed(() => `#icon-${props.name}`)
const svgClass = computed(() => {
if (props.className) {
return `svg-icon ${props.className}`
}
return 'svg-icon'
})
</script>
<style lang="scss" scoped>
.svg-box {
display: inline-block;
.svg-icon {
position: relative;
width: 14px;
min-width: 1em;
height: 14px;
vertical-align: -2px;
}
}
</style>
// 4、使用 name 为 svg 图片名称
<SvgIcon width="444" height="342" name="errorPage404" />
3.8 开启gzip、压缩代码
- 安装依赖
npm i -D vite-plugin-compression rollup-plugin-terser
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 开启gzip、br压缩
import compressPlugin from 'vite-plugin-compression'
// rollup 压缩代码
import { terser } from 'rollup-plugin-terser'
export default defineConfig({
plugins: [
vue(),
terser(),
compressPlugin({
ext: '.gz',
algorithm: 'gzip',
// 是否删除原文件
deleteOriginFile: false
})
]
})
3.9 rollupOptions 打包优化
// 1、配置vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
sourcemap: false,
outDir: 'dist',
minify: 'terser', // 混淆器,terser构建后文件体积更小默认 esbuild
terserOptions: {
compress: {
// 生产环境时移除console
drop_console: true,
drop_debugger: true
}
},
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
const arr = id.toString().split('node_modules/')[1].split('/')
switch (arr[0]) {
case '@vue':
case 'axios':
case 'element-plus':
case '@element-plus':
return '_' + arr[0]
default:
return '__vendor'
}
}
},
chunkFileNames: 'static/js1/[name]-[hash].js',
entryFileNames: 'static/js2/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]'
}
}
},
})
3.10 配置 mock 模拟数据
- 安装依赖
npm i -D vite-plugin-mock
// 1、配置vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// mock模拟接口插件
import { viteMockServe } from 'vite-plugin-mock'
export default defineConfig({
plugins: [
vue(),
viteMockServe({
// 配置mock位置
mockPath: '/mock'
})
]
})
//2、在根目录下、新建 mock/index.ts 文件
export default [
{
url: '/mock/user/sysUser/login',
method: 'post',
timeout: 500,
statusCode: 200,
response: {
code: 0,
data: {
orgName: 'xxx',
mobile: 'xxx',
userId: 'xxx',
token: 'xxx',
password: '',
id: 'xxx',
username: 'xxx'
}
}
}
]
//3、使用时在 serveice.ts 中动态配置baseUrl
const baseURL = import.meta.env.DEV === 'development' ? 'mock' : import.meta.env.VITE_APP_BASEURL
如果ts报红提示,可在 .d.ts 声明文件中加入
interface ImportMeta {
env: Record<string, unknown>
}
3.11 配置实时检测typescript插件
- 安装依赖
npm i -D vite-plugin-checker
// 1、配置vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 实时检测typescript插件,可在运行时检测
import checker from 'vite-plugin-checker'
export default defineConfig({
plugins: [
vue(),
checker({ vueTsc: true })
]
})
vite.config.ts
import vue from '@vitejs/plugin-vue'
// 生成 svg 雪碧图
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
// vue3等插件 hooks 自动引入
import AutoImport from 'unplugin-auto-import/vite'
// 自动按需导入组件插件,省去大量的import操作
import Components from 'unplugin-vue-components/vite'
// 开启gzip、br压缩
import compressPlugin from 'vite-plugin-compression'
// rollup 压缩代码
import { terser } from 'rollup-plugin-terser'
// 按需引入element-plus样式
import { createStyleImportPlugin, ElementPlusResolve } from 'vite-plugin-style-import'
// 自动按需导入elementPlus组件
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// mock模拟接口插件
import { viteMockServe } from 'vite-plugin-mock'
// 实时检测typescript插件,可在运行时检测
import checker from 'vite-plugin-checker'
// 注册组件name
import DefineOptions from 'unplugin-vue-define-options/vite'
import path from 'path-browserify'
import { defineConfig } from 'vite'
const { resolve } = require('path')
export default defineConfig({
build: {
sourcemap: false,
outDir: 'dist',
minify: 'terser', // 混淆器,terser构建后文件体积更小默认 esbuild
terserOptions: {
compress: {
// 生产环境时移除console
drop_console: true,
drop_debugger: true
}
},
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
const arr = id.toString().split('node_modules/')[1].split('/')
switch (arr[0]) {
case '@vue':
case 'axios':
case 'element-plus':
case '@element-plus':
return '_' + arr[0]
default:
return '__vendor'
}
}
},
chunkFileNames: 'static/js1/[name]-[hash].js',
entryFileNames: 'static/js2/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]'
}
}
},
plugins: [
DefineOptions(),
checker({ vueTsc: true }),
terser(),
compressPlugin({
ext: '.gz',
algorithm: 'gzip',
// 是否删除原文件
deleteOriginFile: false
}),
viteMockServe({
// 配置mock位置
mockPath: '/mock'
}),
// 引入 element-plus 样式
createStyleImportPlugin({
resolves: [ElementPlusResolve()],
libs: [
{
libraryName: 'element-plus',
esModule: true,
resolveStyle: (name) => {
return `element-plus/theme-chalk/${name}.css`
}
}
]
}),
// 自动导入svg图片
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [path.resolve(process.cwd(), 'src/assets/svg')],
// 指定symbolId格式
symbolId: 'icon-[dir]-[name]',
inject: 'body-last',
customDomId: '__svg__icons__dom__'
}),
vue(),
AutoImport({
// 自动导入vue3的hook
imports: ['vue', 'vue-router', 'vue-i18n', '@vueuse/head', '@vueuse/core'],
// 自动导入elementPlus组件
resolvers: [ElementPlusResolver()],
// auto-import.d.ts生成的位置
dts: 'src/auto-import.d.ts',
// 解决eslint报错问题的配置项
eslintrc: {
enabled: true, // 默认 'false'
filepath: './.eslintrc-auto-import.json',
globalsPropValue: true // 默认 'true'
}
}),
// 自动按需导入组件
Components({
// 要搜索组件的目录的相对路径
dirs: ['src/components'],
// 搜索子目录
deep: true,
// 组件的有效文件扩展名
extensions: ['vue'],
// 允许子目录作为组件的命名空间前缀。
directoryAsNamespace: false,
// 配置文件生成位置
dts: 'src/components.d.ts',
// 自动按需导入element-plus组件、importStyle: 'sass': 修改主题色添加这一行,使用预处理样式
resolvers: [ElementPlusResolver({ importStyle: 'sass' })]
})
],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
css: {
// elementPlus组件库,css编译,警告 @charset 规则放在第一位
postcss: {
plugins: [
{
postcssPlugin: 'internal:charset-removal',
AtRule: {
charset: (atRule) => {
// 去除elementPlus内部charset警告
if (atRule.name === 'charset') {
atRule.remove()
}
}
}
}
]
},
preprocessorOptions: {
scss: {
// 公共样式文件 自定义的主题色
additionalData: '@use "src/styles/var.scss" as *;'
}
}
},
server: {
open: true,
proxy: {
'/api': {
target: 'http://xxx/',
rewrite: (path) => path.replace(/^\/api/, ''),
changeOrigin: true
}
}
}
})
4 集成 eslint
- 简介
ESLint 是一个插件化并且可配置的 JavaScript 语法规则和代码风格的检查工具,配置 typescript-eslint 代码规范- 相关依赖介绍
@typescript-eslint/eslint-plugin ( eslint 插件,包含了各类定义好的检测 TS 代码的规范 ) @typescript-eslint/parser ( eslint 的解析器,用于解析 TS, 从而检查和规范 TS ) @vue/eslint-config-standard ( vue 标准的esLint规则集 )
@vue/eslint-config-typescript ( ts 校验工具 )
eslint ( eslint 核心代码库, js代码检测工具 )
eslint-import-resolver-typescript ( 解决eslint-plugin-import不能识别目录别名问题 )
eslint-plugin-import ( eslint检测import/export语法插件 )
eslint-plugin-node ( 添加对node的eslint支持,也就是 npm run lint )
eslint-plugin-promise ( eslint检测promise语法 )
eslint-plugin-vue ( 解析 Vue 的 eslint 插件 )- 安装依赖
npm i -D @typescript-eslint/eslint-plugin @typescript-eslint/parser @vue/eslint-config-standard @vue/eslint-config-typescript eslint eslint-import-resolver-typescript eslint-plugin-import eslint-plugin-node eslint-plugin-promise eslint-plugin-vue
.eslintrc.js 配置
module.exports = {
root: true,
env: {
browser: true,
node: true,
es6: true
},
globals: {
defineProps: 'readonly',
defineEmits: 'readonly',
defineExpose: 'readonly'
},
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2020
},
settings: {
// 解决路径引用ts文件报错的问题
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.ts', '.tsx']
},
// 解决tsconfig下的path别名导致eslint插件无法解决的bug
typescript: {
alwaysTryTypes: true
}
},
// 忽略模块
'import/core-modules': ['virtual:svg-icons-register', 'unplugin-auto-import/vite', 'unplugin-vue-components/vite', 'unplugin-vue-components/resolvers'],
// 忽略导入
'import/ignore': ['vue-router', 'vue']
},
extends: [
'plugin:vue/vue3-recommended',
'plugin:vue/vue3-strongly-recommended',
'plugin:@typescript-eslint/recommended',
'@vue/standard',
'@vue/typescript/recommended',
'./.eslintrc-auto-import.json'
],
rules: {
'vue/comment-directive': 'off',
'no-console': 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/member-delimiter-style': [
'error',
{
multiline: {
delimiter: 'none'
},
singleline: {
delimiter: 'comma'
}
}
],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-var-requires': 'off',
'prefer-regex-literals': 'off',
'space-before-function-paren': 0,
'vue/array-bracket-spacing': 'error',
'vue/arrow-spacing': 'error',
'vue/block-spacing': 'error',
'vue/brace-style': 'error',
'vue/camelcase': 'error',
'vue/comma-dangle': 'error',
'vue/component-name-in-template-casing': 'error',
'vue/eqeqeq': 'error',
'vue/key-spacing': 'error',
'vue/match-component-file-name': 'error',
'vue/object-curly-spacing': 'off',
'vue/max-attributes-per-line': 'off',
'vue/html-closing-bracket-newline': 'off',
'no-useless-escape': 'off',
'@typescript-eslint/no-this-alias': [
'error',
{
allowDestructuring: true,
allowedNames: ['self']
}
],
'vue/attribute-hyphenation': 'off',
'vue/custom-event-name-casing': 'off',
'dot-notation': 'off',
'vue/html-self-closing': [
'error',
{
html: {
void: 'always',
normal: 'always',
component: 'always'
},
svg: 'always',
math: 'always'
}
],
'vue/singleline-html-element-content-newline': 'off',
'import/no-unresolved': [2, { commonjs: true, amd: true }],
'import/named': 2,
'import/namespace': 2,
'import/default': 2,
'import/export': 2,
'promise/always-return': 'error',
'promise/no-return-wrap': 'error',
'promise/param-names': 'error',
'promise/catch-or-return': 'off',
'promise/no-native': 'off',
'promise/no-nesting': 'warn',
'promise/no-promise-in-callback': 'warn',
'promise/no-callback-in-promise': 'warn',
'promise/avoid-new': 'warn',
'promise/no-return-in-finally': 'warn'
}
}
5 集成 prettier 格式化代码规范
- 简介
prettier是一个固定的代码格式化程序,通过解析项目代码库,强制使用统一的风格的代码- 相关依赖介绍
eslint-config-prettier (禁用与prettier样式规范有冲突的esLint规则)
eslint-plugin-prettier (将prettier作为esLint的规则来运行)- 安装依赖
npm i -D eslint-config-prettier eslint-plugin-prettier
对比于 eslint而言,prettier 没有太多的配置项,在根目录上新建配置文件 .prettierrc.json
{
"tabWidth": 2,
"jsxSingleQuote": true,
"jsxBracketSameLine": true,
"printWidth": 180,
"singleQuote": true,
"semi": false,
"bracketSpacing": true,
"trailingComma": "none",
"arrowParens": "always"
}
有些目录或者文件不需配置prettier,在根目录上新建忽略文件.prettierignore
/dist/*
.local
.output.js
/node_modules/**
**/*.svg
**/*.sh
/public/*
在 package.json 中添加脚本
{
"scripts":{
"prettier": "prettier --write .",
}
}
配合 vscode 代码格式化插件使用,完成自动保存格式化,vscode 编辑器 安装 Prettier - Code formatter,vscode编辑器配置文件 settings.json 增加以下配置
// 默认使用prettier格式化支持的文件
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
/** -------------------- 编辑器的默认格式化工具 -------------------- **/
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
/** -------------------- Prettier插件配置 -------------------- **/
"prettier.enable": true, // 设置是否开启prettier插件,默认为true,即开启
"prettier.semi": false, // 设置是否在每行末尾添加分号,默认为 true
"prettier.singleQuote": true, // 设置格式化时,保持单引号,如果设置为true,则单引号会自动变成双引号
"prettier.tabWidth": 2, // 设置每个tab占用多少个空格
"prettier.printWidth": 160, // 设置每行可容纳字符数
"prettier.useTabs": false, // 设置是否使用tab键缩进行,默认为false,即不使用
"prettier.bracketSpacing": true, // 对象大括号直接是否有空格,默认为true,效果:{ foo: bar }
"prettier.jsxBracketSameLine": true, // 多行使用拖尾逗号(默认none)
"prettier.arrowParens": "always", // 设置在jsx中,是否把'>' 单独放一行,默认为false,即单独放一行
"prettier.trailingComma": "none"
}
prettierrc 配置参数介绍
// 每个tab相当于多少个空格(默认2)
"tabWidth": 2,
// 是否使用tab进行缩进(默认false)
"useTabs": false,
// 在jsx中使用单引号代替双引号(默认false)
"jsxSingleQuote": true,
// 给对象里的属性名是否要加上引号,默认为 as-needed,即根据需要决定,如果不加引号会报错则加,否则不加
"quoteProps": "as-needed",
// 单行代码超出100个字符自动换行(默认80)
"printWidth": 800,
// 使用单引号(默认false)(在jsx中配置无效, 默认都是双引号)
"singleQuote": true,
// 句末禁止使用分号(默认true)
"semi": false,
// 多行使用拖尾逗号(默认none)
"trailingComma": "none",
// 箭头函数只有一个参数的时候可以忽略括号(默认always)
"arrowParens": "always",
// 对象字面量的大括号间使用空格(默认true)
"bracketSpacing": true,
// 多行HTML元素放在最后一行的末尾(默认false)
"bracketSameLine": false,
// 不格式化vue文件,vue文件的格式化单独设置
"prettier.disableLanguages": ["vue"],
// 结尾是 \n \r \n\r auto
"prettier.endOfLine": "auto",
// 不让prettier使用tslint的代码格式进行校验
"prettier.tslintIntegration": false,
// 不让prettier使用stylelint的代码格式进行校验
"prettier.stylelintIntegration": false,
// 不让prettier使用eslint的代码格式进行校验
"prettier.eslintIntegration": false,
// 不使用prettier格式化的文件填写在项目的.prettierignore文件中
"prettier.ignorePath": ".prettierignore"
需要注意,vue项目往往会配合 Vetur插件使用,主要是vue的语法高亮,其次是代码格式化,支持 prettier 等格式化器。
虽然有各种内置的格式化器,但是检测到本地有格式化插件,会优先使用本地格式化插件,
vscode编辑器配置文件 settings.json 增加以下配置
// settings.json
{
/** -------------------- vetur配置 -------------------- **/
"vetur.format.options.tabSize": 2,
"vetur.validation.script": false,
"vetur.validation.interpolation": false,
"vetur.validation.template": false,
"vetur.ignoreProjectWarning": true,
// 在函数名后面加上括号,类似这种形式 foo () {}
"javascript.format.insertSpaceBeforeFunctionParenthesis": true,
// 移除js语句的分号
"javascript.format.semicolons": "remove",
"vetur.format.defaultFormatter.html": "prettier",
"vetur.format.defaultFormatter.js": "prettier-eslint",
"vetur.format.defaultFormatter.ts": "prettier",
"vetur.format.defaultFormatter.css": "prettier",
"vetur.format.defaultFormatter.sass": "sass-formatter",
"vetur.format.defaultFormatter.postcss": "prettier",
"vetur.format.defaultFormatter.scss": "prettier",
"vetur.format.defaultFormatter.less": "prettier",
"vetur.format.defaultFormatter.stylus": "stylus-supremacy",
// 保持和 prettier 插件配置一致
"vetur.format.defaultFormatterOptions": {
"prettier": {
"printWidth": 160,
"singleQuote": true, // 使用单引号
"semi": false, // 末尾使用分号
"tabWidth": 2,
"arrowParens": "always",
"bracketSpacing": true,
"proseWrap": "preserve" // 代码超出是否要换行 preserve保留
}
}
}
6 集成 stylelint 样式规范
- 简介
stylelint 是一个强大、先进的 CSS 代码检查器,通过内置规则自动修复大多数样式代码格式问题。- 相关依赖介绍
stylelint ( stylelint 核心库 )
stylelint-config-prettier ( 解决stylelint与prettier冲突 )
stylelint-config-recommended-scss( css属性顺序的规则, 配合stylelint-order使用 )
stylelint-config-recommended-vue
stylelint-config-standard ( stylelint官方共享的标准规则集成 )
stylelint-config-standard-scss
stylelint-order ( 格式化css文件时对代码的属性进行排序 )- 安装依赖
npm i -D stylelint stylelint-config-prettier stylelint-config-recommended-scss stylelint-config-recommended-vue stylelint-config-standard stylelint-config-standard-scss stylelint-orde
在根目录上新建配置文件.stylelintrc.js 文件
module.exports = {
extends: [
'stylelint-config-standard',
'stylelint-config-html/vue',
'stylelint-config-recommended-vue',
'stylelint-config-standard-scss',
'stylelint-config-recommended-vue/scss',
'stylelint-config-prettier'
],
plugins: ['stylelint-order', 'stylelint-config-rational-order/plugin'],
rules: {
// 属性书写顺序
'order/properties-order': [],
// 类选择器的命名规则
'selector-class-pattern': [
'^([a-z][a-z0-9]*)(-[a-z0-9]+)*$',
{
message: 'Expected class selector to be kebab-case'
}
],
// at-rule-no-unknown: 屏蔽一些scss等语法检查
'at-rule-no-unknown': [true, { ignoreAtRules: ['mixin', 'extend', 'content', 'include', 'forward', 'if'] }],
// 要求或禁止在註釋之前有空行
'comment-empty-line-before': [
'always',
{
except: ['first-nested'],
ignore: ['stylelint-commands']
}
],
// 每个样式规则前后都有空行,除了第一条规则与规则前有注释
'rule-empty-line-before': [
'always-multi-line',
{
except: ['first-nested'],
ignore: ['after-comment']
}
],
// "@" 语句之前都有空行,但是忽略 "@" 语句在代码块中间与同个非代码块 "@" 语句之间的空行这两种情况
'at-rule-empty-line-before': ['always', { ignore: ['after-comment', 'inside-block', 'blockless-after-same-name-blockless'] }],
// 忽略伪类选择器 ::v-deep
'selector-pseudo-element-no-unknown': [
true,
{
ignorePseudoElements: ['/./', 'v-deep', '-webkit-']
}
],
// alpha 值的百分比或数字表示法
'alpha-value-notation': 'number',
// 使用rgba
'color-function-notation': 'legacy',
// 在声明之前要求允许空行(块级元素内生效,如:{x: x})
'declaration-empty-line-before': 'never',
// scss 变量名忽略警告
'scss/dollar-variable-pattern': [/./, { ignore: 'global' }],
// mixin变量名支持全部字符
'scss/at-mixin-pattern': /.+/,
// 颜色值不简写
'color-hex-length': 'long',
// 单引号
'string-quotes': 'single',
// 指定at-rules小写或大写的名字
'at-rule-name-case': 'lower',
// 禁止零长度的单位(可自动修复)
'length-zero-no-unit': true,
// 禁止在简写性中使用冗余值
'shorthand-property-no-redundant-values': true,
// 禁止出现空块
'block-no-empty': true,
// 禁止空注释
'comment-no-empty': true,
// 要求或禁止 url 使用引号
'function-url-quotes': 'always',
// 小数不带0
'number-leading-zero': 'always',
// 禁止声明快重复属性
'declaration-block-no-duplicate-properties': true,
// 禁止使用可以縮寫卻不縮寫的屬性。
'declaration-block-no-redundant-longhand-properties': true,
// 禁止在具有较高优先级的选择器后出现被其覆盖的较低优先级的选择器
'no-descending-specificity': true,
// 限制一个选择器中 ID 选择器的数量
'selector-max-id': 0,
// 最大嵌套深度
'max-nesting-depth': 5,
// @import中不包含.scss扩展名
'scss/at-import-partial-extension': 'always',
// 指定缩进
indentation: 2
}
}
在根目录上新建忽略配置文件.stylelintignore文件
src/styles/element.scss
src/styles/index.scss
dist
node_modules
7 自动化 husky + lint-staged 对代码进行校验
- 在代码提交前,一般都需使用 eslint、 prettier 、 stylelint 等工具,对当前的代码仓库进行一次格式化,然后在提交时,校验一下 commit 是否符合规范。主要需要使用到以下工具:husky、lint-staged、commit-msg
- husky
husky 继承了 git 下所有的钩子, 对 git 的 commit 操作进行校验,当我们进行 commit 操作时,会触发 husky 的 hook- lint-staged
对暂存的 git 文件运行 lint- commit-msg
对 git commit 格式进行校验- 第一步
在 package.json 添加 prepare,prepare 会在 npm i 之后触发,首次使用可手动触发一下prepare
"scripts": { "prepare": "husky install" }
- 第二步 生成 hook 相关文件,并注入钩子命令,执行命令
npx husky add .husky/pre-commit "npm run lint-staged" 或通过 npm i husky-init 执行初始化页面
- 第三步
如果commit没触发钩子,原因是hook文件权限不足,需添加文件操作权限 chmod +x .husky/pre-commit- 第四步 安装 npm i lint-staged, 并在 package.json 填写脚本
"lint-staged": { "**/*.{vue,js,jsx,tsx,ts,less,md,json}": "npm run prettier" }
- 第五步 配置 package.json
{ "script":{ "prepare": "husky install" }, "lint-staged": { "**/*.{vue,js,jsx,tsx,ts,less,md,json}": "npm run prettier" } }
- 第六步
安装 @commitlint/cli 和 @commitlint/config-conventional,执行以下命令npm i @commitlint/cli @commitlint/config-conventional -D
- 第七步 添加 commit-msg 文件,执行以下命令
npx husky add .husky/commit-msg 'yarn --no-install commitlint --edit "$1"'
- 第八步 新建 commitlint.config.js 配置文件
module.exports = { extends: ['@commitlint/config-conventional'] }
8 .vscode 配置
在根目录新建 .vscode/settings.json
{
"editor.tabSize": 2,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.fixAll.stylelint": true
},
"eslint.validate": ["vue", "html", "javascript", "typescript", "javascriptreact", "typescriptreact"],
"eslint.codeAction.showDocumentation": {
"enable": true
},
"eslint.format.enable": true,
"prettier.enable": true,
"prettier.semi": false,
"prettier.singleQuote": true,
"prettier.tabWidth": 2,
"prettier.printWidth": 800,
"prettier.useTabs": false,
"prettier.bracketSpacing": true,
"prettier.jsxBracketSameLine": true,
"prettier.arrowParens": "always",
"prettier.trailingComma": "none",
"vetur.format.options.tabSize": 2,
"vetur.validation.script": false,
"vetur.validation.interpolation": false,
"vetur.validation.template": false,
"javascript.format.insertSpaceBeforeFunctionParenthesis": true,
"javascript.format.semicolons": "remove",
"vetur.format.defaultFormatter.html": "prettier",
"vetur.format.defaultFormatter.js": "prettier-eslint",
"vetur.format.defaultFormatter.ts": "prettier",
"vetur.format.defaultFormatter.css": "prettier",
"vetur.format.defaultFormatter.sass": "sass-formatter",
"vetur.format.defaultFormatter.postcss": "prettier",
"vetur.format.defaultFormatter.scss": "prettier",
"vetur.format.defaultFormatter.less": "prettier",
"vetur.format.defaultFormatter.stylus": "stylus-supremacy",
"stylelint.enable": true,
"stylelint.validate": ["css", "less", "postcss", "scss", "vue", "sass"]
}