Description:

Before, I built the background management system of Vue3 from zero to one in a project. When I wrote this paper, I wanted to use the current version, but as a result, I encountered many compatibility problems with plug-in versions. Remembering the pit I stepped on before, I gave up the idea because of the limited time and level.

This article uses node version 14.16.1. If you have a similar version of Node, try compatibility or use NVM to install it.

1. Vite creates a project


Speaking of Vite, if you are fed up with webpack startup service 40S +, hot update 6s+, be sure to have a look at Vite, really very fragrant!

Here, I also use Vite for project creation, and the documentation provides examples that can be used

yarn create vite my-vue-app --template vue
Copy the code

For Vite+Vue project creation, there are also several template presets provided below, since I’m using TS, the command I’m using here is

yarn create vite my-vue-app --template vue-ts
Copy the code

Then go to the directory, yarn installs dependencies, and Yarn Dev starts the service

Note: Because Vite keeps updating versioning issues, if you create a project using the above command, it will not be consistent with the code on the branch. Project Address

2. Integrate JEST unit tests


1. Install the jest

Yarn add [email protected] - DCopy the code

2. Create the first test

Create the tests folder in the root directory, and create an internal unit folder to store the unit test file. In the Unit folder, write our first test file index.spec.js

test('1+1=2',() => {
  expect(1+1).toBe(2)
})
Copy the code

Configure commands in package.json

"scripts": {
  "test-unit":"jest"
}
Copy the code

Run YARN test-unit and the first test case passes

3. Add the automatic prompt plug-in

There are no code hints when writing test cases above, which makes it very inefficient, so install @types/jest to implement code hints

Yarn add @ types/[email protected] - DCopy the code

4. Support the import

Next we’ll write a test file foo.js in the Unit folder

export default function (){
  return 'this is foo'
}
Copy the code

Modified index. Spec. Js

import foo from './foo.js'
test('1+1=2',() => {
  expect(1+1).toBe(2);
})
test('foo',() => {
  expect(foo()).toBe('this is foo')
})
Copy the code

An error occurred when yarn test-unit was executed again. Procedure

You will find that Jest does not recognize the import syntax because jest is based on the Node environment, so you need to convert the import syntax into a syntax that NodeJS can recognize

Create jest. Config.js in the root directory for jEST configuration

Module. exports = {// converters transform: {// jest parses js through babel-jest "^.+\\.jsx? $": "babel-jest" } };Copy the code

Install Babel – jest

Yarn add [email protected] - DCopy the code

Because Babel is used, you also need to create the Babel configuration in the root directory babel.config.js

Module. exports = {presets: [[// install the official preset plugin "@babel/preset-env", // specify the target of the resolution is the native Node version {targets: {node: "current" } } ], ], };Copy the code

Install @ Babel/preset – env

Yarn add @ Babel/[email protected] - DCopy the code

Run yarn test-unit again and the test passes

5. Support.vue files

Create foo. vue under SRC/Componens

<template>
  <div>
    Foo
  </div>
</template>
Copy the code

Modified index. Spec. Js

import foo from './foo.js' import Foo from '.. /.. /src/components/Foo.vue 'test('1+1=2',() => { expect(1+1).toBe(2); }) test('foo',() => { expect(foo()).toBe('this is foo') }) test('Foo',() => { console.log('Foo',Foo) })Copy the code

After yarn test-unit is executed, an error occurs. The syntax of the VUE cannot be parsed

Here we need to add rules to parse.vue files in jest. Config. js

Module. exports = {// converters transform: {// jest parses js through babel-jest "^.+\\.jsx? $", "Babel - jest", / / jest vue of time through the vue - jest parse "^. + \ \. Vue $"," vue - jest "}};Copy the code

Install the vue – jest

yarn add vue-jest@next -D
Copy the code

The yarn test-unit test fails again because the TS-Jest dependency is missing

3

Install the ts – a jest

Yarn add [email protected] - DCopy the code

Run yarn test-unit again and the test succeeds

6. Install Vue Test Utils

Vue Test UtilsVue unit test library Vue unit test library Vue unit test library Vue unit test library Vue unit test library

yarn add @vue/test-utils@next -D
Copy the code

Modified index. Spec. Js

import foo from './foo.js' import {mount} from '@vue/test-utils' import Foo from '.. /.. /src/components/Foo.vue 'test('1+1=2',() => { expect(1+1).toBe(2); }) test('foo',() => { expect(foo()).toBe('this is foo') }) test('Foo',() => { console.log('Foo',Foo) console.log('mount',mount(Foo)) })Copy the code

The yarn test-unit test succeeds. Procedure

7. Support for ts

If you change the js test file to.ts and yarn test-unit, you must add converter configuration in jest. Config. js as before

Module. exports = {// converters transform: {// jest parses js through babel-jest "^.+\\.jsx? $", "Babel - jest", / / jest vue of time through the vue - jest parse "^. + \ \. Vue $"," vue - jest, "/ / jest ts by ts - jest parse" ^. + \ \. TSX? $": "ts-jest" } };Copy the code

Ts-jest has been installed before, so there is no need to repeat the installation

Modify the babel.config.js configuration

Module. exports = {presets: [[// install the official preset plugin "@babel/preset-env", // specify the target of the resolution is the native Node version {targets: {node: "current" } } ], "@babel/preset-typescript" ] };Copy the code

Install @ Babel/preset – typescript

Yarn add @ Babel/[email protected] - DCopy the code

Run yarn test-unit test. Pass the Project Address test.

3. Integrate Cypress E2E tests


1. Install the Cypress

Yarn add [email protected] - DCopy the code

Package. json Command “test-e2e”:”cypress open “and run it

The first time we perform initialization, we will create a cypress folder in the root directory, there will be cypress-related files, after initialization will automatically open a window

So there will be a popup box that we can choose which CI environment we want to use Cypress in, but we don’t need it here, so we can just turn it off, okay

In the upper right corner, you can switch to the relevant document of the browser running the test environment

Here are all the test cases, clicking on which opens in the browser to test against the script

2. Adjust the directory

In our project, we wanted everything related to tests to be placed in the Tests folder, so we created the e2E folder under tests and copied all the files from the root directory cypress

Yarn test-e2e: Cypress checks whether there is a Cypress folder in the root directory every time. If there is no cypress folder, you need to modify the configuration in cypress.json

{
  "pluginsFile":"tests/e2e/plugins/index.js"
}
Copy the code

Then modify the configuration documentation in plugins/index.js

module.exports = (on, config) => { // `on` is used to hook into various events Cypress emits // `config` is the resolved Cypress config return // fixtures path fixturesFolder: "tests/e2e/fixtures", // fixtures: "Tests /e2e/specs", // screenshotsFolder path to save screenshots from the cy.screenshotsFolder () command or if a test fails during Cypress: VideosFolder: "Tests /e2e/videos", // The path of the files loaded before loading the test files. This file is compiled and bundled. (by false disabled) supportFile: "tests/e2e/support/index. The js"}); }Copy the code

Note that the previous Integration folder has been renamed to Specs

Perform yarn test – e2e

The following pop-up window appears

The Cypress folder is not created in the root directory

3. Support for ts

First, change all.js files in the e2e folder to.ts

Then modify the configuration in e2e/plugins/index.ts

module.exports = (on: any, config: Cypress.PluginConfig) => { // `on` is used to hook into various events Cypress emits // `config` is the resolved Cypress Config return Object. Assign ({}, config, {// fixtures path fixturesFolder: Fixtures: "Tests /e2e/fixtures", // Fixtures: "Tests /e2e/specs", // screenshotsFolder path to save screenshots from the cy.screenshotsFolder () command or if a test fails during Cypress: VideosFolder: "Tests /e2e/videos", // The path of the files loaded before loading the test files. This file is compiled and bundled. (by false disabled) supportFile: "tests/e2e/support/index. The ts",}); };Copy the code

Modify the configuration in cypress.json

{
  "pluginsFile":"tests/e2e/plugins//index.ts"
}
Copy the code

Clear the sample test files under tests/e2e/specs and create index.spec.ts

describe("index", () => {
  it("button click", () => {
      cy.visit("http://localhost:3000/");
      cy.get("button").click();
  });
});
Copy the code

Run yarn test-e2e. The following window pops up:

Click on index.spec.js and Cypress will open the configured browser and execute the test script for us

You can see that the button click has been triggered because the red value at the top changes from 0 to 1 and the button Click test case in index.spec.ts is prompted to pass on the left

4. Solve the problem of JEST test coverage of E2E

If yarn test-unit is executed, an error message is displayed

At this point, we find that executing the Jest unit test also executes the cyress test file, changes the jest.config.js configuration, and specifies the test script matching rules

Module. exports = {// converters transform: {// jest parses js through babel-jest "^.+\\.jsx? $", "Babel - jest", / / jest vue of time through the vue - jest parse "^. + \ \. Vue $"," vue - jest, "/ / jest ts by ts - jest parse" ^. + \ \. TSX? $", "ts - jest"}, / / configure the test script file matching rules testMatch: [" * * / tests/unit /? (*) + (spec). [jt] s? (x) "],};Copy the code

Run yarn test-unit yarn test-e2e in sequence. The discovery succeeds

5. Integrate Jest & Cypress tests

Package. json Command “test”:” NPM run test-unit && NPM run test-e2e” and run the command

You can see in the terminal that the JEST test has passed and the Cypress window has opened, at which point we want the Cypress test to be running on the terminal as well.

Cypress provides another command to perform tests, cypress run, which we add to package.json

“Test-e2e-ci “:”cypress run” and run it. The cypress test can be performed on the terminal

"test":"npm run test-unit && npm run test-e2e-ci"
Copy the code

Run yarn test. Both jest and Cypress can be completed on the terminal

6. Disable video generation by Cypress

When we performed cypress tests on the terminal, we found a video folder in the Tests /e2e folder containing an index.sepc.ts.mp4 file. When we opened it, we found that the video was a screen recording of the test process. In this case, we don’t need the.mp4 file. It takes up memory and increases test time

{
  "pluginsFile":"tests/e2e/plugins/index.ts",
  "video":false
}
Copy the code

At this point, the integrated Cypress E2E test is complete. Project Address

4. Integration eslint


1. Install ESLint and its dependencies

Yarn add [email protected] [email protected] @vue/[email protected] @typescript-eslint/[email protected] @ typescript - eslint/[email protected] - DCopy the code

eslint

Without further ado, our target, code inspection tool

eslint-plugin-vue

The official ESLint plugin for vue.js provides support for Vue code in.js files

@vue/eslint-config-typescript

Support for writing TS code in Vue components

@typescript-eslint/parser

A TS parser for ESLint

@typescript-eslint/eslint-plugin

The ESLint plugin for TS

Next create an.eslintrc file in the root directory for the ESLint configuration

{// Specify the current directory as the root directory "root": true, // environment configuration item "env": {// Whether browser environment "browser": true, // Whether node environment "node": True, // ES2021 supports "ES2021 ": true}, // introduces configuration item "extends": [ // vue3 "plugin:vue/vue3-recommended", // eslint "eslint:recommended", / / the vue typescript "@ vue/typescript/it"], / / parser configuration "parserOptions" : {/ / to use grammar ECMAScript version "ecmaVersion" : 2021}}Copy the code

Configure the eslint command in package.json for scripts

"lint":"eslint --ext .ts,vue src/**"
Copy the code

Check all.ts,.vue files in SRC directory

In this case, run yarn lint

You’ll notice that there are some warnings and errors

Let’s add one more command here

"lint:fix":"eslint --ext .ts,vue src/** --fix"
Copy the code

Fix will help us automatically fix some of the warnings

After running YARN Lint :fix, all warnings disappear except one error

For images that do not have a parser configured, you can configure the.eslintignore file in the root directory to make esLint ignore certain files or directories

node_modules
dist
src/assets
index.html
Copy the code

Run yarn Lint :fix again and the discovery can pass

2. Integrated lint – staged

Git staging: git staging: git staging: git staging: git staging: git staging: git staging: git staging: git staging

Lint-passage and Yorkie are required here, using passage passage

Yarn add [email protected] [email protected] -dCopy the code

To install, you need to do some configuration in package.json

"gitHooks": {
  "pre-commit": "lint-staged"},
"lint-staged": {
  "*.{ts,vue}": "eslint --fix"
}
Copy the code

This configuration will call Lint-staged, which will perform eslint –fix on all.ts,.vue files before committing

App.vue: HelloWorld app.vue: HelloWorld app.vue: HelloWorld app.vue: HelloWorld app.vue: HelloWorld app.vue

It indicates that the verification we configured has taken effect. Project Address

5. Integrated Prettier


Prettier helps us beautify and unify our code, so we integrate it here too.

Installing Prettier and related dependencies

Yarn add [email protected] [email protected] @vue/[email protected] -dCopy the code

eslint-plugin-prettier

Support for Prettier to work in ESLint

@vue/eslint-config-prettier

Supports partial conflicts between esLint code verification rules and Prettier code verification rules

The configuration is added to the.eslintrc file

{// Specify the current directory as the root directory "root": true, // environment configuration item "env": {// Whether browser environment "browser": true, // Whether node environment "node": True, // ES2021 supports "ES2021 ": true}, // introduces configuration item "extends": [ // vue3 "plugin:vue/vue3-recommended", // eslint "eslint:recommended", // vue typescript "@vue/typescript/recommended", "@vue/prettier", "@vue/prettier/@typescript-eslint" ], // Parser configuration "parserOptions": {// to use the ECMAScript syntax version "ecmaVersion": 2021}}Copy the code

The NPX prettier -w -u command is used.

-w: Edit files in-place. (Beware!) Edit files in place. (Beware!)

-u: Ignore unknown files. Ignore unknown files.

. Specify the current path

Prettier formatting some files, opening changes to app.vue

Prettier automatically modifies newlines, Spaces, double quotes and so on according to prettier’s rules

You can then document Prettier by creating an.prettierrc file in the root directory

{whether ending semicolon "semi": true, whether single quotation mark "singleQuote": false}Copy the code

If prettier was removed from a file, NPX prettier -w-u. Prettier would add a semicolon at the end of a line

Finally, prettier was integrated into Lint-staged and package.json was modified for ease of use

"lint-staged": {
  "*.{ts,vue}": "eslint --fix",
  "*": "prettier -w -u"
}
Copy the code

By then, the project integration prettier was complete. Project Address

6. Integrate COMMIT Message verification


The specification of the Commit Message is also important for the team. A specification of the Commit message will make it very clear when we look back at git history, and here we are using uVU’s approach in VUE

This method relies on the Yorkie library, which we installed when we integrated Lint-staged and will not repeat here.

Configuration package. Json gitHooks

"gitHooks": {
  "commit-msg":"node scripts/verify-commit-msg.js",
  "pre-commit": "lint-staged"
}
Copy the code

Scripts /verify-commit-msg.js

The verify-commit-msg.js file can be copied directly from your vUE project.

The general logic of this file is to read the commit message in the Git file through the FS module and verify it through the re.

If the verification fails, an error message is displayed and git commit is blocked

One possible problem here is that ESLint will issue a warning when copying verify-commit-msg.js to the file

Require statement not part of import statement.
Copy the code

You can disable the verification by configuring the following rules in.eslintrc

"rules":{
  "@typescript-eslint/no-var-requires": 0
}
Copy the code

The chalk library is used in verify-commit-msg.js, and chalk provides the function of setting console colors in the terminal

Install chalk yarn add chalk -d

Git commit -m “test” can intercept a commit mesage that does not meet the requirement

I am running Windows 10 and found chalk is not in effect, so I need to add the second line of code below in verify-commit-msg.js

Git commit -m “test” is used to test chalk

At this point, the commit- MSG integration is complete. Project Address

7. Add test to gitHooks


Above we added jest unit tests and Cypress e2E tests and integrated them, but generally we don’t want to execute the tests manually every time we commit code, we want to automate the tests to ensure that the code pushed to Git is correct. We do this by adding Git hooks to package.json

"gitHooks": {
  "commit-msg": "node scripts/verify-commit-msg.js",
  "pre-commit": "lint-staged",
  "pre-push": "npm run test"
}
Copy the code

This is set to run the test command before git push, where we configured the jest and cypress tests so that the test script is run before git push

This step is relatively simple, and the code is merged into the branch that integrates the commit- MSG step. Project Address

8. Configure the alias path alias


The purpose of a path alias is to simplify operations to a specified path by specifying symbols.

1. Configuration vite. Config. Js

For example, helloworld.vue is used in views/ home. vue

import HelloWorld from ".. /components/HelloWorld.vue";Copy the code

If level deep some, such as working in the views/Goods/List/index. The vue, just need to

import HelloWorld from ".. /.. /.. /components/HelloWorld.vue";Copy the code

As you can see, this is cumbersome, and if the location of the helloWorld.vue file changes, all the helloWorld.vue incoming code is cumbersome to modify. To solve this problem, Vite also provides a method to configure the alias. Modify vite.config.js as follows:

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { resolve } from "path";
// https://vitejs.dev/config/
export default defineConfig({
  resolve: {
    alias: {
      "@": resolve("./src")
    },
  },  
  plugins: [
    vue()
  ]
})
Copy the code

Here we have set the @ symbol to point to the./ SRC directory. In the future, no matter in which file, use the following code to import

Helloworld.vue, file location changes, can also be unified replacement

import HelloWorld from "@/components/HelloWorld.vue";
Copy the code

The location of the file has changed, and there is no need to adjust it, which is a great convenience for us.

But we’re not done here. When introducing code, you can see that vscode has a path prompt when we write./, but when we write @/, there is no path prompt, so we need to do some configuration for ts.

2. Configure the TS to support aliases

{
  "compilerOptions": {
    "target": "esnext",    
    "useDefineForClassFields": true,    
    "module": "esnext",    
    "moduleResolution": "node",    
    "strict": true,    
    "jsx": "preserve",    
    "sourceMap": true,    
    "resolveJsonModule": true,    
    "esModuleInterop": true,    
    "lib": ["esnext", "dom"],    
    "types": ["vite/client", "jest", "node"],    
    "baseUrl":"./",    
    "paths":{      
      "@/*":["src/*"]    
    }  
  },  
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}
Copy the code

BaseUrl: Specifies the current directory

Paths is our alias configuration, which means the same as the configuration in vite.config.js, go back to the.vue file again, use @alias to introduce HelloWorld

3. Configure jEST to support aliases

Next we try to use alias in jest unit tests, modifying tests/unit/index.spec.ts

import foo from "./foo";
import { mount } from "@vue/test-utils";
import Foo from "@/components/Foo.vue";
test("1+1=2", () => {
  expect(1 + 1).toBe(2);
});
test("foo", () => {
  expect(foo()).toBe("this is foo");
});
test("Foo", () => {
  console.log("Foo", Foo);  
  console.log("mount", mount(Foo));
});
Copy the code

Vscode will give us an error message after the modification

Then we try to execute YARN test-unit

Jest does not recognize @path alias, so we need to modify jest. Config.js

Module. exports = {// converters transform: {// jest parses js through babel-jest "^.+\\.jsx? $", "Babel - jest", / / jest vue of time through the vue - jest parse "^. + \ \. Vue $"," vue - jest, "/ / jest ts by ts - jest parse" ^. + \ \. TSX? $", "ts - jest"}, / / configure the test script file matching rules testMatch: [" * * / tests/unit /? (*) + (spec). [jt] s? "(x)], / / configuration path alias moduleNameMapper: { "^@/(.*)$": "<rootDir>/src/$1" } };Copy the code

Then run yarn test-unit again and the test succeeds. Project Address

9. Integrate Vue Router


Vue Router is the official route to Vue. Js

yarn add vue-router@next
Copy the code

Create a router folder in SRC and write index.ts

import { createRouter, createWebHashHistory } from "vue-router"; export const routes = [ { path: "/", redirect: "/home" },{ path: "/home", name: "Home", component: () => import("@/views/Home.vue") },{ path: "/login", name: "Login", component: () => import("@/views/Login.vue") },{ path: "/404", name: "404", hidden: true, meta: { notNeedAuth: true }, component: () = > import (" @ / views / 404. Vue ")}, / / match all path used vue2 * vue3 / : pathMatch (. *) or / : catchAll (. *) {path: "/:catchAll(.*)", redirect: "/404" } ]; Const router = createRouter({history: createWebHashHistory(), routes}); export default router;Copy the code

Here are the basic usage, do not repeat, see the documentation.

Modify the App. Vue

<template>
  <router-view>
  </router-view>
</template>
<style>
  #app {
    font-family: Avenir, Helvetica, Arial, sans-serif;  
    -webkit-font-smoothing: antialiased;  
    -moz-osx-font-smoothing: grayscale;  
    text-align: center;  
    color: #2c3e50;  
    margin-top: 60px;
 }
 </style>
Copy the code

Create views/Home. Vue

<template> <div> <p>This is Home</p> <img alt="Vue logo" src="@/assets/logo.png" /> <HelloWorld msg="Hello Vite + Vue 3 + TypeScript" /> </div> </template> <script lang="ts"> import { defineComponent } from "vue"; import HelloWorld from "@/components/HelloWorld.vue"; export default defineComponent({ name: "Home", components: { HelloWorld }, setup() { return {}; }}); </script>Copy the code

Create views/Login. Vue

<template> <div>This is Login</div> </template> <script lang="ts"> import { defineComponent } from "vue"; export default defineComponent({ name: "Login", setup() { return {}; }}); </script>Copy the code

Main. ts Imports the Vue router

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router/index";
createApp(App).use(router).mount("#app");
Copy the code

At this point, vue Router integration is complete. Project Address

10. Integrated Vuex


Vuex is a state management mode + library developed specifically for vue.js applications. It uses centralized storage to manage the state of all the components of the application, and the corresponding rules to ensure that the state changes in a predictable way, directly installed.

yarn add vuex@next
Copy the code

Create a store folder in SRC. For example, create a user module.

src/store/index.ts

import { createStore } from "vuex";
import getters from "./getters";
import user from "./modules/user";
const modules = {  user,};
const store = createStore({  modules,  getters,});
export default store;
Copy the code

src/store/modules/user.ts

export default { 
  namespaced: true,  
  state: {  
    userInfo: {    
      userId:"001",      
      name: "wzy"
    }
  },  
  mutations: { 
 
  },  
  actions: { 
 
  }
};
Copy the code

src/store/getters.ts

type state = { user: { userInfo: { name: string; token: string; avatar: string; roles: string[]; }; }}; export default { userInfo: (state: state) => state.user.userInfo };Copy the code

The main ts introduced vuex

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router/index";
import store from "./store/index";
createApp(App)
.use(store)
.use(router)
.mount("#app");
Copy the code

SRC/views/Home. Use vue

<template> <div> <p>This is Home</p> <img alt="Vue logo" src="@/assets/logo.png" /> <HelloWorld msg="Hello Vite + Vue 3 + TypeScript" /> <p>Name: {{ userInfo.name }}</p> </div> </template> <script lang="ts"> import { defineComponent } from "vue"; import { useStore } from "vuex"; import HelloWorld from "@/components/HelloWorld.vue"; export default defineComponent({ name: "Home", components: {HelloWorld}, setup() {// Get typed store const store = useStore(); Const userInfo = store.getters. UserInfo; return { userInfo }; } }) </script>Copy the code

At this point, vuEX integration is complete. Project Address

11. Integration Element3


Element3, a Vue 3.0-based desktop component library for developers, designers, and product managers. The installation

yarn add element3
Copy the code

Element3 is introduced in main.ts

Some components are imported on demand

import { createApp } from "vue"; import App from "./App.vue"; import router from "./router/index"; import store from "./store/index"; // Element3 style file import "Element3 /lib/theme-chalk/index.css"; import { ElIcon, ElButton, ElForm, ElFormItem, ElInput } from "element3"; createApp(App) .use(store) .use(router) .use(ElIcon) .use(ElButton) .use(ElForm) .use(ElFormItem) .use(ElInput) .mount("#app");Copy the code

Modify the SRC/views/Login. Vue

<template> <div class="login_main" @keyup.enter="login"> <! </h3> <el-form ref="form" :model="param" :rules="rules"> <el-form-item prop="name"> <el-input V-model ="param.name" prefix-icon="el-icon-user" placeholder=" account "> </el-input> </el-form-item> <el-form-item prop="password"> <el-input v-model="param.password" prefix-icon="el-icon-lock" Placeholder =" password "show-password autocomplete ></el-input> </el-form-item> <el-button class="w_100" type="primary" </el-button> </el-form> </div> </div> </template> <script lang="ts"> import {defineComponent, ref, reactive } from "vue"; Export default defineComponent({name: "Login", setup() {// form const form = ref(null); Const param = reactive({name: "", password: "",}); // Form validation rule const rules = reactive({name: [{required: true, message: "please input the account ", trigger: "blur"},], password: [{required: true, message: "Please input password ", trigger: "blur"}],}); // Password form type const passInputType = ref("password"); // Change password form type const changeInputType = (val: string) => {passinputType. value = val; }; Const login = () => {form.value.validate((valid: Boolean) => {if (valid) {console.log("login validates!") ); } else { return false; }}); }; return { form, param, rules, passInputType, changeInputType, login, }; }}); </script> <style scoped> .login_main { display: flex; align-items: center; justify-content: center; } .content { width: 500px; } </style>Copy the code

The modified login page is as follows:

At this point, element3 integration is complete. Project Address

12. Integrate Axios + MockJS + sass


1. The integrated axios

An HTTP library is definitely needed for projects involving front-end and back-end interactions, and here we integrate the most commonly used axiOS

yarn add axios
Copy the code

Create an utils folder under SRC to hold our utility methods

Write Request. ts to wrap axios

import axios from "axios"; import { Message } from "element3"; // Create an axios instance const service = axios.create({baseURL: import.meta.env.BASE_URL, timeout: 10000}); / / request interceptor service. Interceptors. Request. Use ((config) = > {return config. }, (error) => { return Promise.reject(error); }); / / response interceptor service. Interceptors. Response. Use ((response: any) = > {const res = response. The data; if (res.header.code ! == 0) { Message.error(res.header.msg || "Error"); return Promise.reject( new Error(res.header.msg || "Error")); } return res; }, (error) => { Message.error("request error"); return Promise.reject(error); }); / encapsulated interface request method * * * * @ param url domain name after the need to supplement the interface address * @ param method interface request way * @ param data d * / request data body type method = | "get" | | "get" "delete" | "DELETE" | "head" | "HEAD" | "options" | "OPTIONS" | "post" | "POST" | "put" | "PUT" | "patch" | "PATCH" | "purge" | "PURGE" | "link" | "LINK" | "unlink" | "UNLINK"; const request = ( url: string, method: Method, data: Record<string, unknown> ) => { return service({ url, method, data, }); }; export default request;Copy the code

Create an API folder under SRC to store all interface request methods

SRC/API create user. Ts write user related interface request

import request from ".. /utils/request"; type Method = | "get" | "GET" | "delete" | "DELETE" | "head" | "HEAD" | "options" | "OPTIONS" | "post" | "POST" | "put" | "PUT" | "patch" | "PATCH" | "purge" | "PURGE" | "link" | "LINK" | "unlink" | "UNLINK"; const curryRequest = ( url: string, method: Method, data? : Record<string, unknown> | any ) => { return request( `/module/user/${url}`, method, data ) }; Export function apiLogin(data: {name: string; password: string; }): PromiseLike<any> { return curryRequest("login", "post", data); }Copy the code

Put the login operation in store/modules/user.ts actions, and improve mutations

import { apiLogin } from "@/api/user"; type userInfo = { userId: string; name: string; }; type state = { userInfo: userInfo; }; type context = { state: Record<string, unknown>; mutations: Record<string, unknown>; actions: Record<string, unknown>; dispatch: any; commit: any; }; type loginData = { name: string; password: string; }; export default { namespaced: true, state: { userInfo: { userId: "", name: "" }, }, mutations: SET_USERINFO(state:state,val:userInfo){state.userInfo = val; }}, actions: {// login({commit}: context, data: LoginData) {return new Promise((resolve) => {apiLogin(data). Then (async (res) => {commit("SET_USERINFO", { userId: res.body.userId, name: res.body.name, }); resolve("success"); })})}}}Copy the code

Update the Login. Vue

<template> <div class="login_main" @keyup.enter="login"> <! </h3> <el-form ref="form" :model="param" :rules="rules"> <el-form-item prop="name"> <el-input V-model ="param.name" prefix-icon="el-icon-user" placeholder=" account "> </el-input> </el-form-item> <el-form-item prop="password"> <el-input v-model="param.password" prefix-icon="el-icon-lock" Placeholder =" password "show-password autocomplete ></el-input> </el-form-item> <el-button class="w_100" type="primary" </el-button> </el-form> </div> </div> </template> <script lang="ts"> import {defineComponent, ref, reactive } from "vue"; import { useStore } from "vuex"; import { useRouter } from "vue-router"; Export default defineComponent({name: "Login", setup() {// sotre instance const store = useStore(); // route instance const router = useRouter(); // form const form = ref(null); Const param = reactive({name: "", password: "",}); // Form validation rule const rules = reactive({name: [{required: true, message: "please input the account ", trigger: "blur"},], password: [{required: true, message: "Please input password ", trigger: "blur"}],}); // Password form type const passInputType = ref("password"); // Change password form type const changeInputType = (val: string) => {passinputType. value = val; }; // const login = () => {form.value.validate((valid: boolean) => { if (valid) { store.dispatch("user/login", param).then(() => { router.push({ name: "Home" }); }); } else { return false; }}); }; return { form, param, rules, passInputType, changeInputType, login, }; } }) </script> <style scoped> .login_main { display: flex; align-items: center; justify-content: center; } .content { width: 500px; } </style>Copy the code

I generally recommend router.push({name: “Home”}) for route jump, because the name defined by each route does not change, but the path may be adjusted. In this way, the problem of modifying the corresponding route operation after the path change is avoided

At this point, the request-related logic is written, but when we build the framework, the background is usually in the initial stage, and the interface is not ready, so mockJS is needed to help us simulate the interface request

2. Integrated mockjs

Install mockjs

Yarn add [email protected]Copy the code

Install vite – plugin – the mock

Yarn add [email protected] - DCopy the code

Modify viet.config. js to introduce mockjs

import { UserConfigExport, ConfigEnv,loadEnv } from "vite"; import vue from "@vitejs/plugin-vue"; import { resolve } from "path"; import { viteMockServe } from "vite-plugin-mock"; export default ({ command, mode }: ConfigEnv): UserConfigExport => { const plugins = [vue()]; const env = loadEnv(mode, process.cwd()); If (mode === "development") {plugins.push(viteMockServe({mockPath: "mock", localEnabled: command === "serve" }) ); } return { resolve: { alias: { "@": resolve("./src") }, }, plugins } };Copy the code

Create the mock folder in the root directory of your project and create user.ts to write the user-related mock interface

export default [ { url: `/module/user/login`, method: "post", response: (req) => { return { header: { code: 0, msg: "OK,"}, body: {userId: "001", name: ` ${the req. Body. The name} xiaoming `}}}}];Copy the code

Open the login page, enter account 1 and password 1, and click Login

The console can see that the request was successfully initiated and the response received, and the page jumps to Home and gets userInfo

3. The integrated sass

Related documents Install sASS

yarn add sass -D
Copy the code

Modify the SRC /views/ login. vue style test

<style lang="scss" scoped>
$bg: #364d81;
.login_main {
  width: 100%;  
  height: 100%;  
  display: flex;  
  align-items: center;  
  justify-content: center;  
  background: $bg;  
  .content {  
    width: 500px;    
    .title {    
      color: #fff;    
    }  
  }}
</style>
Copy the code

At this point, the sASS integration is complete.

4. Jest unit tests do not support import.meta.env

We thought we were done here, but when we unit tested SRC /utils/request.ts

tests/unit/request.spec.ts

import request from "@/utils/request";
test("request", () => {
  expect(request).not.toBeNull();  
  expect(request).not.toBeUndefined();
});
Copy the code

Jest error found

Here before we tsconfig. Js is configured in the “module” : “esnext”, in fact, the problem is the current ts – no jest library to import. The meta. Do support env, it adopted the following methods

Modify the vite. Config. Js

import { UserConfigExport, ConfigEnv,loadEnv } from "vite"; import vue from "@vitejs/plugin-vue"; import { resolve } from "path"; import { viteMockServe } from "vite-plugin-mock"; export default ({ command, mode }: ConfigEnv): UserConfigExport => { const plugins = [vue()]; const env = loadEnv(mode, process.cwd()); If (mode === "development") {plugins.push(viteMockServe({mockPath: "mock", localEnabled: Command === "serve"}))} const envWithProcessPrefix = object.entries (env).reduce( (prev, [key, val]) => { return { ... Prev, / / environment variable to add process. The env [" process. The env. "+ key] : `" ${val} "`}; }, {}); return { base: "./", resolve: { alias: { "@": resolve("./src"), }, }, plugins, define: envWithProcessPrefix, }};Copy the code

Save the environment-specific variables you get in process.env and expose them externally

Modify the request. Ts

import axios from "axios"; import { Message } from "element3"; // Create an axios instance const service = axios.create({baseURL: process.env.VITE_BASE_URL, timeout: 10000});Copy the code

BaseURL uses variables under process.env

Run yarn test-unit. The test succeeds.

At this point, the integration with Axios + MockJS +sass is complete. Project Address

End


At this point, this article is over, the follow-up will build background management system on this basis, interested in the point of attention!

If you have any questions or suggestions about this article, please leave a comment!