前言
OK,这里是分享与爱的大鹅鹅鹅,今天我们瞬间移动,来到脚手架实践栏目。这里已经准备了思维导图,让我们一起走近进入vite2 + vue3 + ts搭建脚手架的奇妙之旅,来了解vite和vue3带来了哪些优越的改变,为编程提效做出了哪些努力?
为什么要用vite?
借用作者的原话:
Vite,一个基于浏览器原生 ES imports 的开发服务器。利用浏览器去解析 imports,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随起随用。同时不仅有 Vue 文件支持,还搞定了热更新,而且热更新的速度不会随着模块增多而变慢。针对生产环境则可以把同一份代码用 rollup 打包。虽然现在还比较粗糙,但这个方向我觉得是有潜力的,做得好可以彻底解决改一行代码等半天热更新的问题。
需要注意:
- Vite 主要对应的场景是开发模式,原理是拦截浏览器发出的 ES imports 请求并做相应处理。(生产模式是用 rollup 打包)
- Vite 在开发模式下不需要打包,只需要编译浏览器发出的 HTTP 请求对应的文件即可,所以热更新速度很快。
- CommonJS 和 UMD 兼容性: 开发阶段中,Vite 的开发服务器将所有代码视为原生 ES 模块。因此,Vite 必须先将作为 CommonJS 或 UMD 发布的依赖项转换为 ESM。
生产模式下的打包不是 Vite 自身提供的,因此生产模式下如果你想要用 Webpack 打包也依然是可以的。从这个角度来说,Vite 可能更像是替代了 webpack-dev-server 的一个东西。
为什么要用Vue3?
-
性能优化
- 数据劫持方面的改变,由
ES5
的Object.defineProperty()
进行数据劫持,改变为ES6
的Proxy
进行数据代理。(原因:由于proxy可以动态判断该数据是否为深层嵌套数据,而object.defineProperty()为遍历深层嵌套数据,两者在数据劫持,数据变更判断上有时间的巨大差异。) - 打包策略,vue3支持了
tree-shaking
,排除任何未实际使用的代码,打包体积减小。降低了文件加载时间。 - diff优化,vue3对静态节点进行提升,所有的静态节点在进行对比时不会被遍历。减少了进行节点对比所需的时间。
- 数据劫持方面的改变,由
-
新增
Composition API
(组合式API)-
解决了Vue2.x版本的
options API
不能解决的复用和可读性差的缺陷。 -
新增了一个
setup()
生命周期函数,会在组件创建之前就执行。用setup
生命周期代替beforeCreate
和created
。const {ref,reactive,onMountend,toRefs} = Vue setup(props){ // 声明简单数据类型和复杂数据类型 // 只能通过.value的形式获取数据 const refValue = ref(null); // 只能声明复杂数据类型 // 声明的数据类型不能解构 // 声明的数据类型是proxy对象 const reactiveValue = reactive({state:0}); // 生命周期的使用(on加生命周期名字) onMountend(()=>{ // 在相应的生命周期内执行相应操作 }) // 该类型的数据不能解构,解构就会失去响应式特点 console.log(props); // 该方法将proxy对象转化成ref变量 toRefs(props); }
-
-
v-model绑定提升
支持绑定多个v-model进行双向绑定。
-
TypeScript支持
Vue3
完全由TS
进行重写,对类型判断的定义和使用有很强的表现。 -
生命周期优化
Vue2 ~~~~~~~~~~~ vue3 beforeCreate -> setup()(新增) created -> setup()(新增) beforeMount -> onBeforeMount mounted -> onMounted beforeUpdate -> onBeforeUpdate updated -> onUpdated beforeDestroy -> onBeforeUnmount(改名) destroyed -> onUnmounted(改名) activated -> onActivated deactivated -> onDeactivated
前置准备
-
浏览器
Chrome
(最新版本最佳)浏览器插件:
Vue.js devtools
(调试插件) -
编辑器
VsCode
Vscode 插件:
Vue Language Features (Volar)
(提供语法高亮提示等功能),Vue 3 Snippets
(vue3 快捷输入) -
环境
Nodejs
构建脚手架
编写本文时,版本说明:
- vite: "2.6.4";
- vue: "3.2.16";
选对目录后,命令行输入,并回车:
yarn create vite
进入下载构建项目流程,根据图形化指令选择操作。
vite.config.ts配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
function resolve(dir) {
return path.join(__dirname, dir)
}
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve('src'),
},
},
//启动服务配置
server: {
port: 8000,
open: true,
https: false,
cors: false // 允许跨域
proxy: {
'/api': {
target: 'http://172.0.0.1:8089',
changeOrigin: true,
ws: true,
},
},
},
// 生产环境打包配置
//去除 console debugger
build: {
target: 'es2015',
minify: 'terser', // 是否进行压缩,boolean | 'terser' | 'esbuild',默认使用terser
manifest: false, // 是否产出maifest.json
sourcemap: false, // 是否产出soucemap.json
outDir: 'build', // 产出目录
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
},
})
代码风格约束
Eslint 支持
yarn add eslint eslint-plugin-vue @typescript-eslint/eslint-plugin @typescript-eslint/parser --dev
这三个依赖的作用分别是:
eslint
: ESLint的核心代码;eslint-plugin-vue
:ESLint关于检测vue代码规范的插件;@typescript-eslint/parser
:ESLint的解析器,用于解析typescript,从而检查和规范Typescript代码;@typescript-eslint/eslint-plugin
:这是一个ESLint插件,包含了各类定义好的检测Typescript代码的规范;
注意:
@typescript-eslint/parser
和@typescript-eslint/eslint-plugin
使用相同的版本号很重要;
配置eslint
校验规则
项目下新建 .eslintrc.js
module.exports = {
root: true,
env: {
browser: true,
node: true,
es2021: true,
},
parser: "vue-eslint-parser",
extends: [
"eslint:recommended",
"plugin:vue/vue3-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
// eslint-config-prettier 的缩写
"prettier",
],
parserOptions: {
ecmaVersion: 12,
parser: "@typescript-eslint/parser",
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
// eslint-plugin-vue @typescript-eslint/eslint-plugin eslint-plugin-prettier的缩写
plugins: ["vue", "@typescript-eslint", "prettier"],
rules: {
"@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"no-var": "error",
"prettier/prettier": "error",
// 禁止出现console
"no-console": "warn",
// 禁用debugger
"no-debugger": "warn",
// 禁止出现重复的 case 标签
"no-duplicate-case": "warn",
// 禁止出现空语句块
"no-empty": "warn",
// 禁止不必要的括号
"no-extra-parens": "off",
// 禁止对 function 声明重新赋值
"no-func-assign": "warn",
// 禁止在 return、throw、continue 和 break 语句之后出现不可达代码
"no-unreachable": "warn",
// 强制所有控制语句使用一致的括号风格
curly: "warn",
// 要求 switch 语句中有 default 分支
"default-case": "warn",
// 强制尽可能地使用点号
"dot-notation": "warn",
// 要求使用 === 和 !==
eqeqeq: "warn",
// 禁止 if 语句中 return 语句之后有 else 块
"no-else-return": "warn",
// 禁止出现空函数
"no-empty-function": "warn",
// 禁用不必要的嵌套块
"no-lone-blocks": "warn",
// 禁止使用多个空格
"no-multi-spaces": "warn",
// 禁止多次声明同一变量
"no-redeclare": "warn",
// 禁止在 return 语句中使用赋值语句
"no-return-assign": "warn",
// 禁用不必要的 return await
"no-return-await": "warn",
// 禁止自我赋值
"no-self-assign": "warn",
// 禁止自身比较
"no-self-compare": "warn",
// 禁止不必要的 catch 子句
"no-useless-catch": "warn",
// 禁止多余的 return 语句
"no-useless-return": "warn",
// 禁止变量声明与外层作用域的变量同名
"no-shadow": "off",
// 允许delete变量
"no-delete-var": "off",
// 强制数组方括号中使用一致的空格
"array-bracket-spacing": "warn",
// 强制在代码块中使用一致的大括号风格
"brace-style": "warn",
// 强制使用骆驼拼写法命名约定
camelcase: "warn",
// 强制使用一致的缩进
indent: "off",
// 强制在 JSX 属性中一致地使用双引号或单引号
// 'jsx-quotes': 'warn',
// 强制可嵌套的块的最大深度4
"max-depth": "warn",
// 强制最大行数 300
// "max-lines": ["warn", { "max": 1200 }],
// 强制函数最大代码行数 50
// 'max-lines-per-function': ['warn', { max: 70 }],
// 强制函数块最多允许的的语句数量20
"max-statements": ["warn", 100],
// 强制回调函数最大嵌套深度
"max-nested-callbacks": ["warn", 3],
// 强制函数定义中最多允许的参数数量
"max-params": ["warn", 3],
// 强制每一行中所允许的最大语句数量
"max-statements-per-line": ["warn", { max: 1 }],
// 要求方法链中每个调用都有一个换行符
"newline-per-chained-call": ["warn", { ignoreChainWithDepth: 3 }],
// 禁止 if 作为唯一的语句出现在 else 语句中
"no-lonely-if": "warn",
// 禁止空格和 tab 的混合缩进
"no-mixed-spaces-and-tabs": "warn",
// 禁止出现多行空行
"no-multiple-empty-lines": "warn",
// 禁止出现;
semi: ["warn", "never"],
// 强制在块之前使用一致的空格
"space-before-blocks": "warn",
// 强制在 function的左括号之前使用一致的空格
// 'space-before-function-paren': ['warn', 'never'],
// 强制在圆括号内使用一致的空格
"space-in-parens": "warn",
// 要求操作符周围有空格
"space-infix-ops": "warn",
// 强制在一元操作符前后使用一致的空格
"space-unary-ops": "warn",
// 强制在注释中 // 或 /* 使用一致的空格
// "spaced-comment": "warn",
// 强制在 switch 的冒号左右有空格
"switch-colon-spacing": "warn",
// 强制箭头函数的箭头前后使用一致的空格
"arrow-spacing": "warn",
"no-var": "warn",
"prefer-const": "warn",
"prefer-rest-params": "warn",
"no-useless-escape": "warn",
"no-irregular-whitespace": "warn",
"no-prototype-builtins": "warn",
"no-fallthrough": "warn",
"no-extra-boolean-cast": "warn",
"no-case-declarations": "warn",
"no-async-promise-executor": "warn",
},
globals: {
defineProps: "readonly",
defineEmits: "readonly",
defineExpose: "readonly",
withDefaults: "readonly",
},
};
项目下新建 .eslintignore
# eslint 忽略检查 (根据项目需要自行添加)
**/*.js
"build"
"dist"
"public"
"node_modules"
检查修复
虽然,现在编辑器已经给出错误提示和修复方案,但需要我们一个一个去点击修复,还是挺麻烦的。很简单,我们只需设置编辑器保存文件时自动执行 eslint --fix 命令进行代码风格修复。
VSCode 在 settings.json 设置文件中,增加以下代码:
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
prettier 支持
yarn add prettier eslint-plugin-prettier eslint-config-prettier -D
prettier
:prettier插件的核心代码eslint-config-prettier
:解决ESLint中的样式规范和prettier中样式规范的冲突,以prettier的样式规范为准,使ESLint中的样式规范自动失效;eslint-plugin-prettier
:将prettier作为ESLint规范来使用
最后形成优先级:Prettier 配置规则 > ESLint 配置规则。
关于prettier ESLint的配置,已经在前面部分的配置****eslint
**** 校验规则,配置 .eslintrc.js
内容时已配置完成。
项目下新建 .prettierrc.js
配置 prettier
格式化规则:
{
"trailingComma": "es5",
"tabWidth": 2,
"jsxSingleQuote": true,
"jsxBracketSameLine": true,
"printWidth": 100,
"singleQuote": true,
"semi": false,
"overrides": [
{
"files": "*.json",
"options": {
"printWidth": 200
}
}
],
"arrowParens": "always"
}
项目下新建 .prettierignore
# 忽略格式化文件 (根据项目需要自行添加)
node_modules
dist
自动空格缩放保存不一致解决
vscode编辑器开启自动保存时,会自动设置tabsize,检查.prettierrc.js
下的"tabWidth": 2
,是否和vscode 设置的一致,不然可能会会有保存缩进空格不同步的情况。
MacOS使用Command + Sheft + P
,windows使用Ctrl + Sheft + P
快捷键---> 搜索“settings.json”。保持prettier
的缩进空格同编辑器设置的一致,设置如下:
"editor.tabSize": 2,
// vscode默认启用了根据文件类型自动设置tabsize的选项
"editor.detectIndentation": false,
package.json 配置
{
"script": {
"lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx",
"prettier": "prettier --write ."
}
}
上面配置完成后,可以运行以下命令
测试下代码检查个格式化
效果:
// eslint 检查
yarn lint
// prettier 自动格式化
yarn prettier
配置 husky + lint-staged
husky
是一个为 git 客户端增加 hook
的工具。我们可以在 pre-commit
中实现一些比如 lint 检查
、单元测试
、代码美化
等操作。
lint-staged
它是对个人要提交的代码的一个规范和约束。
前置条件:
确保在此之前安装并配置所有代码质量工具,如 Prettier 和 ESlint
;
使用husky
+ lint-staged
助力团队编码规范,husky
+ lint-staged
安装推荐使用 mrm
,它将根据 package.json
依赖项中的代码质量工具来安装和配置 husky
和 lint-staged
。
安装 mrm:
npm i mrm -D --registry=https://registry.npm.taobao.org
安装 lint-staged:
mrm
安装 lint-staged
会自动
把 husky
一起安装下来 。
npx mrm lint-staged
安装成功后会发现 package.json
中多了一下几个配置:
因为我们要结合 prettier
代码格式化,所有修改一下配置:
"husky": {
"hooks": {
"pre-commit": "lint-staged",
}
},
"lint-staged": {
"*.{ts,tsx,vue,js,jsx}": [
"yarn lint",
"prettier --write",
"git add"
]
}
Git Commit Message 提交规范配置
针对 git commit log 提交规范的问题,需要统一规范,如果我们提交的不符合指向的规范, 直接拒绝提交。
yarn add @commitlint/cli commitizen commitlint-config-cz cz-customizable -D
package.json
中配置:
"config": {
"commitizen": {
"path": "node_modules/cz-customizable"
}
},
// 结合 Husky
"husky": {
"hooks": {
...,
"commit-msg": "commitlint -e $GIT_PARAMS"
}
},
配置规则
根目录.cz-config.js
中写入自定义的配置:
'use strict'
module.exports = {
types: [
{
value: '💪 WIP',
name: '进度: 工作进度',
},
{
value: '✨ feat',
name: '功能: 新功能',
},
{
value: '🐞 fix',
name: '修复: 修复bug',
},
{
value: '🛠 refactor',
name: '重构: 代码重构',
},
{
value: '📚 docs',
name: '文档: 只有文档变更',
},
{
value: '🏁 test',
name: '测试: 添加一个测试',
},
{
value: '🗯 chore',
name: '工具: 没有修改源代码,只是变更构建流程或辅助工具。',
},
{
value: '💅 style',
name: '样式: 空格,分号等格式修复。',
},
{
value: '⏪ revert',
name: '回滚: 代码回退。',
},
{
value: '🏎 perf',
name: '性能: 提升性能。',
},
{
value: '🏗 build',
name: '构建: 变更项目构建或外部依赖(例如scopes: webpack、gulp、npm等)',
},
{
value: '🕹 ci',
name:
'集成: 更改持续集成软件的配置文件和package中的scripts命令,例如scopes: Travis, Circle等',
},
],
scopes: [],
messages: {
type: '选择一种你的提交类型:',
scope: '选择一个scope (可选):',
// used if allowCustomScopes is true
customScope: 'Denote the SCOPE of this change:',
subject: '短说明:\n',
body: '长说明,使用"|"换行(可选):\n',
breaking: '非兼容性说明 (可选):\n',
footer: '关联关闭的issue,例如:#31, #34(可选):\n',
confirmCommit: '确定提交说明?',
},
footerPrefix: 'TAPD: ',
allowCustomScopes: true,
allowBreakingChanges: ['特性', '修复'],
skipQuestions: ['scope', 'body', 'footer'],
}
根目录 .commitlintrc.js
中写入:
module.exports = {
extends: [
'cz'
],
rules: {
}
};
效果如下:
工具配置
css预加载配置
Vite 提供了对 .scss
, .sass
, .less
, .styl
和 .stylus
文件的内置支持。但必须安装相应的预处理器依赖。
yarn add less less-loader sass sass-loader dart-sass -D
router配置
路由一定得安装4.0.0以上版本,最好直接安装当前最新版本。
安装:
yarn add vue-router@4 -S
配置:
新版本的路由配置和之前非常相似,只有些许不同。新版本路由的API全部采用了函数式引入的方式,具备ts的类型提示。在router/index.ts
文件下写入:
import {
createRouter,
RouteRecordRaw,
createWebHistory,
// createWebHashHistory
} from 'vue-router'
const HelloWorld = () => import('@/views/HelloWorld.vue')
const ErrorPage = () => import('@/views/ErrorPage.vue')
const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld,
},
{
path: '/:pathMatch(.*)*', // 注意此处 404页面匹配规则和以前不相同,得采用这种配置方式才行
name: '404',
component: ErrorPage,
},
]
const router = createRouter({
history: createWebHistory(),
routes,
})
export default router
增加路由守卫:
import { RouteLocationNormalized, NavigationGuardNext,} from 'vue-router'
// 路由守卫和之前的实现方式一致 此处只是做了一个demo仅供演示
router.beforeEach(
(
to: RouteLocationNormalized,
from: RouteLocationNormalized,
next: NavigationGuardNext
) => {
// 获取userToken,根据业务场景可由localStorage也可由cookie中获取
const user = localStorage.getItem("user");
// 路由守卫判断
if (to.meta.type === "login" && user) {
next({ name: "home" });
return;
}
if (to.meta.type === "home" && !user) {
next({ name: "login" });
return;
}
next();
});
状态库配置
以下两者选择:
- vuex 4.0.0及以上版本;
- pinia(推荐);
UI库选择
- element-plus;
- naive UI(推荐);
常见的工具库配置
yarn add lodash-es normalize.css numeral -S
环境变量配置
vite
提供了两种模式:具有开发服务器的开发模式
(development)和生产模式
(production),支持.env
文件配置。以 VITE_
为前缀的变量才会暴露给经过 vite 处理的代码。具体环境变量配置,解释说明见环境变量和模式。
项目根目录新建:.env.development
:
NODE_ENV=development
VITE_APP_WEB_URL= 'YOUR WEB URL'
项目根目录新建:.env.production
:
NODE_ENV=production
VITE_APP_WEB_URL= 'YOUR WEB URL'
组件中使用:
console.log(import.meta.env.VITE_APP_WEB_URL)
配置 package.json
:
打包区分开发环境和生产环境
"build:dev": "vue-tsc --noEmit && vite build --mode development",
"build:pro": "vue-tsc --noEmit && vite build --mode production",
typeScript 的智能提示:
默认情况下,Vite 在 vite/client.d.ts
中为 import.meta.env
提供了类型定义。随着在 .env[mode]
文件中自定义了越来越多的环境变量,你可能想要在代码中获取这些以 VITE_
为前缀的用户自定义环境变量的 TypeScript 智能提示。
要想做到这一点,你可以在 src
目录下创建一个 env.d.ts
文件,接着按下面这样增加 ImportMetaEnv
的定义:
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_APP_TITLE: string
// 更多环境变量...
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
VsCode自定义代码片段
一些常用的业务代码,我们可以将其重构,利用vscode,构建自定义代码片段,在项目根目录,创建.vscode文件夹、project.code-snippets文件,目录如.vscode/project.code-snippets
。
在project.code-snippets文件内编写自定义代码片段。示例:
{
"components": {
"scope": "javascript, typescript, vue",
"prefix": "<component-setup>",
"body": [
"<template>",
"",
"</template>",
"",
"<script setup lang="ts">",
"import { inject, onMounted, ref } from "vue";",
"import { IStrings } from "@/locale/locale";",
"",
"interface IProps { name: string; }",
"const strings: IStrings | undefined = inject("strings");",
"const props = defineProps<IProps>();",
"onMounted(() => {});",
"</script>",
"<style scoped>",
"</style>"
],
"description": "Default Component Code of Vue3 + Typescript + Setup"
},
}
使用的话,在.vue文件中,写入<component-setup>
,编辑器会自动联想,自定义代码片段。然后进行选择确定,自定义代码片段就写入.vue文件中。
结语
以上就是本篇的全部内容,如果你觉得此文对你有一点点帮助,不妨点个赞,一键三连,鼓励一下大鹅鹅鹅,O(∩_∩)O哈哈~