Vite
现在可谓是炙手可热,可能很多小伙伴还没有使用过Vite
,但是我相信大多数小伙伴已经在使用Vite
了,因为是太香了有没有。可能在使用过程中很多东西Vite
不是配置好的,并不像Vue-cli
配置的很周全,那么今天就说一下如何配置开发环境,其中主要涉及到的点有一下几个:
- TypeScript
- Vuex
- Vue-Router
E2E
- Cypress
Test unit
- Jest
- vtu
- Eslint + Perttite
- verify git commit message
- CI
- alias
Vite初始化项目
在开始之前首先要先使用Vite
创建项目,如果小伙伴已经对Vite
已经有了一定的了解,那么可以跳过。根据Vite
官网介绍可以使用npm
或yarn
来创建项目。
使用 NPM:
npm init vite@latest
使用 Yarn:
yarn create vite
使用 PNPM:
pnpx create-vite
输入完命令之后然后按照提示操作即可,因为在项目要支持TypeScript
所以我这里就选择的是vue-ts
。创建好之后Vite
会帮助我们把项目给创建好,可以发现Vite
所创建好的项目其实与使用Vue-cli
所创建的项目目录结构其实是差不多的,这里也就不多赘述了。
集成Vue-Router
Vue-Router
是大多数项目中比不可少的工具之一了,Vue-Router
可以让构建单页面应用变得更加的容易。包含的功能有:
- 嵌套的路由/视图表
- 模块化的、基于组件的路由配置
- 路由参数、查询、通配符
- 基于 Vue.js 过渡系统的视图过渡效果
- 细粒度的导航控制
- 带有自动激活的 CSS class 的链接
- HTML5 历史模式或 hash 模式,在 IE9 中自动降级
- 自定义的滚动条行为
以上截取自Vue-router官网
安装Vue-Router:
使用 NPM:
npm install vue-router@next --save
使用 Yarn:
yarn add vue-router@next --save
安装完成之后在src
目录下创建文件夹router/index.ts
,创建完成之后需要在Vue-Router
中对Vue-Router
进行初始化配置。我们暂时把初始化的工作搁置一下,先需要创建pages
文件夹,把需要展示的页面创建完成。
创建完成之后,接下来就是完善router/index.ts
中文件的初始化工作了:
import { createRouter, createWebHashHistory } from "vue-router";
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: "/home",
name: "Home",
alias: "/",
component: () => import("../pages/Home.vue")
},
{
path: "/about",
name: "About",
component: () => import("../pages/About.vue")
}
]
})
export default router;
接下来在main.ts
文件中集成Vue-Router
:
import { createApp } from 'vue';
import App from './App.vue';
import router from "./router";
const app = createApp(App);
app.use(router);
app.mount('#app');
测试一下,这里修改一下App.vue
的代码,测试一下我们的路由是否已经可以正常使用了。
<template>
<router-link to="/home">Home</router-link>
<router-link to="/about">About</router-link>
<router-view></router-view>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'App'
})
</script>
接下来启动服务就可以看到所配置的页面了,说明配置的路由已经生效了。Good Job
,真的很不错~~~
集成Vuex
Vuex
是Vue
所支持的状态管理工具,在在实际应用过程中也有很大的作用,当多个组件之间的数据流转变得非常困难,因此需要集中的对状态进行管理,Vuex
的状态存储是响应式的。当Vue
组件从store
中读取状态的时候,若store
中的状态发生变化,那么相应的组件也会相应地得到高效更新。
安装Vuex:
使用 NPM:
npm install vuex@next --save
使用 Yarn:
yarn add vuex@next --save
安装完成之后,首先添加store/index.ts
来初始化Vuex
。需要注意的是,如下示例使用了Vuex
命名空间。可能在实际项目中使用命名空间相对来说还是比较普遍的,避免进行状态管理的时候导致变量污染。
import { createStore } from "vuex";
const store = createStore({
modules: {
home: {
namespaced: true,
state: {
count: 1
},
mutations: {
add(state){
state.count++;
}
}
}
}
})
export default store;
集成到Vue
中:
import { createApp } from 'vue';
import App from './App.vue';
import router from "./router";
import store from "./store";
const app = createApp(App);
app.use(router);
app.use(store);
app.mount('#app');
现在Vuex
就已经被集成到Vue
中了为了保证集成的Vuex
是有效地,那么需要对此进行测试:
pages/Home.vue
<template>
<h1>Home</h1>
<h2>{{count}}</h2>
<button @click="handleClick">click</button>
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue';
import { useStore } from 'vuex';
export default defineComponent({
setup () {
const store = useStore();
const count = computed(() => store.state.home.count);
const handleClick = () => {
store.commit('home/add');
};
return {
handleClick,
count
};
}
})
</script>
当点击按钮的时候,就可以发现count
值也随着点击每次递增,那么store
是可以正常使用。Good Job
,真的很不错~~~
集成单元测试
在开发过程中为了保证程序的健壮性,就需要对程序进行单元测试,所以在项目初始化的时候,同样就需要为单元测试进行配置。配置中使用的工具是jest
,如果对于单元测试不太了解的,请自行百度学习,脱离本文重点,不多赘述。
安装相关依赖:
使用 NPM:
npm install jest -D # 单元测试工具 ^26.6.3
npm install @types/jest -D # 单元测试类型文件
npm install babel-jest -D # 支持es6模块 ^26.6.3
npm install @babel/preset-env -D # 支持es6模块 ^7.14.7
npm install vue-jest@next -D # 支持Vue文件 ^5.0.0-alpha.8
npm install ts-jest -D # 支持Ts ^26.5.1
npm install @vue/test-utils@next # Vue官方测试工具 2.0.0-rc.6
npm install @vue/test-utils@next -D # 2.0.0-rc.6
npm install @babel/preset-typescript # 支持Ts ^7.12.17
使用 Yarn:
yarn add jest --dev # 单元测试工具 ^26.6.3
yarn add @types/jest --dev # 单元测试类型文件
yarn add babel-jest --dev # 支持es6模块 ^26.6.3
yarn add @babel/preset-env --dev # 支持es6模块 ^7.14.7
yarn add vue-jest@next --dev # 支持Vue文件 ^5.0.0-alpha.8
yarn add ts-jest --dev # 支持Ts ^26.5.1
yarn add @vue/test-utils@next # Vue官方测试工具 2.0.0-rc.6
yarn add @babel/preset-typescript # 支持Ts ^7.12.17
依赖安装完成之后,在src
目录下创建tests
文件夹,这个文件夹用来存放关于测试相关的文件,因为我们不但有单元测试还有E2E
测试,所以要对两者进行区分。
因为在安装配置的时候可能会导致版本不兼容,导致的报错,所以在配置的时候添一定要注意版本号,在上面已经注释了版本号,需要注意一下。安装完所依赖之后,接下来就需要对单元测试进行配置。
在根目录创建jest.config.js
对Jest
进行初始化的基本配置:
module.exports = {
transform: { // babel预设
"^.+\\.vue$": "vue-jest", // 支持导入Vue文件
"^.+\\.jsx?$": "babel-jest", // 支持import语法
'^.+\\.tsx?$': 'ts-jest' // 支持ts
}
};
修改tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"types": ["vite/client", "jest"] // 指定类型为jest
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests" // 指定单元测试路径
]
}
因为Node
无法运行TypeScript
这里需要使用babel
对TypeScript
进行编译,要配置babel
的相关配置,在根目录创建babel.config.js
:
module.exports = {
transform: {
"^.+\\.vue$": "vue-jest",
"^.+\\.jsx?$": "babel-jest",
'^.+\\.tsx?$': 'ts-jest'
},
testMatch: [ // 匹配单元测试规则
"**/?(*.)+(test).[jt]s?(x)"
]
};
上面基本已经对单元测试的配置完成了,接下来就是测试是否能够正常运行单元测试,在根目录下面创建tests/unit
等文件夹(文件):
index.test.ts
import { mount } from "@vue/test-utils";
import demo from "./demo";
import Foo from "../../src/components/Foo.vue";
test("1+1=2", () => {
console.log(demo);
console.log(mount(Foo));
expect(1+1).toBe(2);
});
demo.ts
export default {
a: 1
};
之后就是运行单元测试,在package.json
中添加命令:
{
"scripts": {
"test:unit": "jest"
}
}
在src
目录下添加shims-vue.d.ts
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
运行一下就可以看到输出得结果,那么就代表我们的单元测试可以正常运行了,Good Job
,真的很不错~~~
集成E2E测试
可能很多小伙伴对于E2E
测试不是特别的熟悉,E2E
即端对端测试,属于黑盒测试,通过编写测试用例,自动化模拟用户操作,确保组件间通信正常,程序流数据传递如预期。
既然对E2E
有了一定的了解之后呢,那么就需要安装E2E
测试相关的模块的依赖,E2E
测试使用是cypress
依赖,首次安装的时候可能会慢,要耐心等待:
使用 NPM:
yarn add cypress -D # e2e测试工具
使用 Yarn:
yarn add cypress --dev # e2e测试工具
安装依赖完成之后需要对cypress
进行初始化,这个时候我们需要在package.json
中添加命令:
{
"scripts": {
"test:e2e": "cypress open"
}
}
执行完成之后呢会在根目录下创建一个cypress
文件夹,该文件夹里面包含了很多目录相关的文件,暂时先不管,之后在tests
文件夹中添加e2e
文件夹,把cypress
所有内容剪切到tests/e2e
中。
完成上述操作之后咧?cypress
在运行的时候会默认的去cypress
文件中去找相关依赖,但是现在已经把cypress
中的文件已经挪走了,那么我们就需要对cypress
进行配置,修改cypress
的基础路径,并指向到tests/e2e
文件即可。
在根目录创建cypress.json
文件:
{
"pluginsFile": "tests/e2e/plugins/index.ts",
"video": false // 关掉视频录制默认行为
}
细心的小伙伴可能已经发现了,上面所以引用的文件是以.ts
结尾的,但是在对应目录下面是.js
文件,这是为什么?因为我们的项目是以TypeScript
为基础的项目,所以我们E2E
测试也应该使用TypeScript
,这个时候我们应该把E2E
文件夹下所有.js
文件改为.ts
(需要注意的是,把integration
改成specs
,并删除里面所有测试用例)。
更改plugin
文件夹下面的index.ts
:
module.exports = (on, config) => {
return Object.assign({}, config, {
fixturesFolder: 'tests/e2e/fixtures',
integrationFolder: 'tests/e2e/specs',
screenshotsFolder: 'tests/e2e/screenshots',
videosFolder: 'tests/e2e/videos',
supportFile: 'tests/e2e/support/index.ts'
});
};
针对cypress
的单元测试已经完成了,但是刚才已经删除了测试用例,接下来就写一下测试用例,在tests/e2e/specs
文件夹下面创建:
first.specs.ts
describe("First ", () => {
it("before", () => {
cy.visit("http://localhost:3000/");
cy.get("button").click();
});
});
需要注意的是,因为cypress
是需要在项目启动的时候进行测试的,所以我们需要把本地的服务运行起来才可以。测试用例变现完成之后,就可以运行了。在弹出页面中会看到所有用例的文件,点击对应文件,就会在浏览器中打开了,浏览器左侧则是对应测试的步骤了。
经过上述的配置E2E
的配置已经基本完成了,由于两个测试全处于tests
中两个测试会互相影响么?
插曲
既然E2E
测试和单元测试都已经完成了,那么分别运行一下单元测试和E2E
测试,当运行单元测试后的时候,就会抛出一个错误。
● Test suite failed to run
tests/unit/index.spec.ts:8:15 - error TS2339:
Property 'toBe' does not exist on type 'Assertion'.
8 expect(1+1).toBe(2);
~~~~
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 3.234 s
Ran all test suites.
error Command failed with exit code 1.
很明显,我们的单元测试收到E2E
测试的影响,运行失败了,可以根据文件提示找到对应的位置,因为两个测试库的expect
冲突了,所以导致单元测试下expect
返回的对象内容不在是原来单元测试expect
了。
既然出现问题了就需要解决问题ing,在上面配置单元测试的时候,为了让单元测试支持TypeScript
在tsconfig.json
中添加了测试的路径,我们如果只指向到单元测试里面这个问题是不是就解决了,但是如果这样的话,cypress
无法再支持TypeScript
了,其实我们可以在E2E
再创建一个tsconfig.json
这个文件只应用于E2E
。
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"types": ["vite/client", "jest"]
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/unit" // 指定单元测试路径
]
}
tests/e2e/tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"]
}
}
之后再运行yarn test:unit
的时候就会发现不会报错了,那么经过这次更改e2e
是否受到影响了呢?运行yarn test:e2e
显然并没有发生任何错误,也可以正常运行的。Good Job
,真的很不错~~~
当运行yarn test:e2e
的时候,总会弹出一个窗口,但是当项目部署走CI
的时候,是没有办法进行点击的,这个时候应该怎么办呢?其实cypress
是有办法在终端执行的,通过npx cypress run
这个命令去在终端运行E2E
测试。
修改package.json
:
{
"scripts": {
"test:unit": "jest",
"test:e2e": "cypress open",
"test": "yarn test:unit && npx cypress run"
}
}
之后运行yarn test
就可以先运行单元测试,后运行E2E
测试了。
集成Git提交验证
在开发项目的时候可能并不是一个人进行开发的,可能会由多个人进行开发,那么作为标准的自动化来讲,对于Git
提交的时候,要有一些固定显著的格式来规范我们的项目开发人员,这个时候就需要使用某些工具进行约束。
安装相关依赖:
使用 NPM:
npm install yorkie -D
npm install chalk -D
使用 Yarn:
yarn add yorkie --dev
yarn add chalk --dev
安装完依赖之后,对yorkie
之后需要对其进行相关的配置,在package.json
中添加字段:
{
"gitHooks": {
"commit-msg": "node scripts/commitMessage.js"
}
}
在上面的配置中,运行了一个js
文件,那么这个js
文件中则是对提交内容的校验。
scripts/commitMessage.js
const chalk = require('chalk')
const msgPath = process.env.GIT_PARAMS
const msg = require('fs').readFileSync(msgPath, 'utf-8').trim()
const commitRE = /^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release)(\(.+\))?(.{1,10})?: .{1,50}/
const mergeRe = /^(Merge pull request|Merge branch)/
if (!commitRE.test(msg)) {
if (!mergeRe.test(msg)) {
console.log(msg)
console.error(
` ${chalk.bgRed.white(' ERROR ')} ${chalk.red(
`invalid commit message format.`,
)}\n\n` +
chalk.red(
` Proper commit message format is required for automated changelog generation. Examples:\n\n`,
) +
` ${chalk.green(`feat(compiler): add 'comments' option`)}\n` +
` ${chalk.green(
`fix(v-model): handle events on blur (close #28)`,
)}\n\n` +
chalk.red(
` See https://github.com/vuejs/vue-next/blob/master/.github/commit-convention.md for more details.\n`,
),
)
process.exit(1)
}
}
集成Eslint
Eslint
对于团队开发来说是一个很不错的工具,可以根据Eslint
的配置给约束开发者代码的风格,以及书写格式。
安装相关依赖:
使用 NPM:
npm install eslint -D
npm install eslint-plugin-vue -D
npm install @vue/eslint-config-typescript -D
npm install @typescript-eslint/parser -D
npm install @typescript-eslint/eslint-plugin -D
npm install typescript -D
npm install prettier -D
npm install eslint-plugin-prettier -D
npm install @vue/eslint-config-prettier -D
使用 Yarn:
yarn add eslint --dev
yarn add eslint-plugin-vue --dev
yarn add @vue/eslint-config-typescript --dev
yarn add @typescript-eslint/parser --dev
yarn add @typescript-eslint/eslint-plugin --dev
yarn add typescript --dev
yarn add prettier --dev
yarn add eslint-plugin-prettier --dev
yarn add @vue/eslint-config-prettier --dev
配置安装完成之后呢,还需要对eslint
进行配置,在根目录下创建.eslintrc
:
.eslintrc
{
"root": true,
"env": {
"browser": true,
"node": true,
"es2021": true
},
"extends": [
"plugin:vue/vue3-recommended",
"eslint:recommended",
"@vue/typescript/recommended"
],
"parserOptions": {
"ecmaVersion": 2021
}
}
配置项已经添加好了,如何去运行已经配置好的eslint
呢?接下来就需要在package.json
中添加命令:
{
"lint": "eslint --ext src/**/*.{ts,vue} --no-error-on-unmatched-pattern"
}
接下来运行一下yarn lint
就可以了,可以通过eslint
完成格式的校验了,现在的问题是什么,在执行yarn lint
的时候把所有的文件全部都校验了一次,这个可不是我们所希望的,如果有很多文件的话,那么速度将会很慢,那么有没有办法,只在git
提交的时候对修改的文件进行eslint
校验呢?
安装相关依赖:
使用 NPM:
npm install lint-staged -D
使用 Yarn:
yarn add lint-staged --dev
修改package.json
:
{
"gitHooks": {
"commit-msg": "node scripts/commitMessage.js",
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.{ts,vue}": "eslint --fix"
},
"scripts": {
"test:unit": "jest",
"test:e2e": "cypress open",
"test": "yarn test:unit && npx cypress run",
"lint": "npx prettier -w -u . && eslint --ext .ts,.vue src/** --no-error-on-unmatched-pattern",
"bea": "npx prettier -w -u ." // 美化代码
},
}
配置alias
在使用cli
的时候总是使用@
去引入某些文件,由于Vite
没有提供类似的配置,所以我们需要手动的对其进行一些相关的配置,才能继续使用@
符号去快捷的引入文件。
修改vite.config.ts
:
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { join } from "path";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: [
{
find: '@',
replacement: '/src',
},
{ find: 'views', replacement: '/src/views' },
{ find: 'components', replacement: '/src/components' },
]
}
});
修改tsconfig.json
:
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"types": ["vite/client", "jest"],
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/unit"
]
}
为了保证在单元测试中也可以使用@
引入src
下面的文件需要对jest.config.js
配置进行修改:
修改jest.config.js
:
module.exports = {
transform: {
'^.+\\.vue$': 'vue-jest',
'^.+\\.jsx?$': 'babel-jest',
'^.+\\.tsx?$': 'ts-jest',
},
testMatch: ['**/?(*.)+(test).[jt]s?(x)'],
moduleNameMapper: {
"@/(.*)$": "<rootDir>/src/$1"
}
};
结尾
使用Vite
对项目初始化还是存在很多坑的,比如在配置单元测试的时候的版本兼容,还有配置别名的时候需要注意多个文件之间的协调。
我们做了这么多的统一配置无非是为了能够让项目在开发过程中更加的规范,能够达成统一的效果,也能让我们的程序更加的健壮。革命尚未成功,同志仍需努力。
可能文章中一些见解存在一些问题,欢迎大家在评论区指出,大家一起学习,一起进步。如果文章对你有帮助的话,请点击赞吧~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。