Recently in follow starting from 0 handy with you to build a set of specifications Vue3. Article x project engineering environment to establish some detail problems in the process of learning, through various query solution finally, and ultimately achieve a set of with code specification + + + automated unit test specification submitted the front end of the deployment environment, write this article records the process. Related requirements are as follows:

  • Architectural structures,
  • Code specification
  • Submit specifications
  • Unit testing
  • Automated deployment

Architectural structures,

  • Initializing the architecture

  1. Initialize the vite
npm init @vitejs/app
Copy the code
  1. The terminal is initialized

  • Modify the vite. Config. Js

Import {defineConfig} from 'vite' import vue from '@vitejs/plugin-vue' // If the editor says path module cannot be found, You can install it @ types/node - > NPM I @ types/node - D import path from export 'path' / / https://vitejs.dev/config/ default defineConfig({ plugins: [vue()], resolve:{ alias:{ '@':path.resolve(__dirname,'src') } }, base:'./', server:{ port:4000, open:true, cors:true } })Copy the code
  • Initialize the project directory

Vue3 - vite ├ ─. Gitignore ├ ─. Vscode │ └ ─ extensions. The json ├ ─ index. The HTML ├ ─ package - lock. Json ├ ─ package. The json ├ ─ public │ └ ─ the favicon. Ico ├ ─ README. Md ├ ─ SRC │ ├ ─ App. Vue │ ├ ─ assets │ │ └ ─ logo. The PNG │ ├ ─ common │ ├ ─ components │ │ └ ─ The HelloWorld. Vue │ ├ ─ env. Which s │ ├ ─ main. Ts │ ├ ─ the router │ ├ ─ store │ ├ ─ style │ ├ ─ utils │ └ ─ views ├ ─ tests ├ ─ Tsconfig. Json └ ─ vite. Config. TsCopy the code
  • Initializing a Route

  1. Install the routing
npm install vue-router@4
Copy the code
  1. Configuring routing Files
import {createRouter,createWebHistory,RouteRecordRaw} from 'vue-router'
import Home from '@/src/views/home.vue'
import Vuex from '@/src/views/vuex.vue'
const routes: Array<RouteRecordRaw>=[
    {
        path:'/',
        name:'home',
        components:Home
    },{
        path:'vuex',
        name:'vuex',
        components:Vuex
    },
    {
        path:'/axios',
        name:'axios',
        component:()=>import('@/views/axios')
    }
]
const router = createRouter({
    history:createWebHistory(),
    routes
})
export default router;
Copy the code
  1. Mount the routing
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
const app= createApp(App);
app.use(router).mount('#app')

Copy the code
  • Initialize vuex

  1. Install vuex
npm install vuex@next
Copy the code
  1. Configure the store
import { InjectionKey } from 'vue'
import { createStore, Store, useStore as baseUseStore } from 'vuex'
import RootStateTypes, { AllStateTypes } from './types'

import numFactoryModule from './modules/NumFactory'

export const store = createStore<RootStateTypes>({
  state: {
    text: 'This is Vuex Root.state.text'
  },
  getters: {},
  mutations: {},
  actions: {},
  modules: {
    numFactoryModule
  }
})

export const key: InjectionKey<Store<RootStateTypes>> = Symbol('vue-store')

export function useStore<T = AllStateTypes>() {
  return baseUseStore<T>(key)
}
Copy the code
  1. Mount vuex
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
import { key, store } from './store/index'
const app= createApp(App);
app.use(router).use(store,key).mount('#app')
Copy the code
  • Integrated UI framework ### Element Plus

  1. The installation Element Plus
npm install element-plus
Copy the code
  1. To select load on Demand, install is required firstunplugin-vue-components
npm install unplugin-vue-components
Copy the code
  1. Configuration vite. Config. Js
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default {
  plugins: [
    // ...
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
}
Copy the code
  1. Add style – import. Ts

Add style-import.ts to the utis directory to install required components

import { App } from 'vue' import { ElIcon, ElLoading, ElCard, ElButton} from 'element-plus' /** * Import element Plus components on demand * Vite plugin https://github.com/element-plus/vite-plugin-element-plus * @param app {App} */ export default function styleImport(app: App) { ; [ElButton, ElCard, ElLoading, ElIcon].forEach((v) => { app.use(v) }) return app }Copy the code
  1. The main element js mount – plus
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
import { key, store } from './store/index'
import styleImport from './utils/style-import'
const app= createApp(App);
styleImport(app).use(router).use(store,key).mount('#app')
Copy the code
  • Integrated axios

  1. Install axios
npm i axios
Copy the code
  1. Configuration axios

Create axios.ts in the utils directory

import Axios from 'axios' import { ElMessage } from 'element-plus' const baseURL = 'https://api.github.com' const axios = Axios.create({ baseURL, timeout: 20000 / / request timeout 20 s}) / / front interceptor (before a request to intercept) axios. Interceptors. Request. Use ((response) = > {/ * * * according to the actual circumstance of your project to do processing * config Nothing is done to config here, Return */ return response}, (error) = > {return Promise. Reject (error)}) / / rear interceptor (access to the response when the intercept) axios. Interceptors. Response. Use ((response) = > {/ * * * Do response and error based on what your project is doing * I'm not doing anything with response and error, Return */ return response}, (error) => { if (error.response && error.response.data) { const code = error.response.status const msg = error.response.data.message ElMessage.error(`Code: ${code}, Message: ${msg}`) console.error(`[Axios Error]`, error.response) } else { ElMessage.error(`${error}`) } return Promise.reject(error) } ) export default axiosCopy the code
  • Integrated CSS precompiler Stylus/Sass/Less

The loader is installed in Vite, so you do not need to deal with it separately. You only need to download the relevant development dependencies

npm i stylus -D 
# or 
npm i sass -D 
npm i less -D
Copy the code

At this point, One based on TypeScript + Vite + Vue3 + Vue Router + Vuex + Element Plus + Axios + Stylus/Sass/Less After setting up the front-end project development environment, the next step is to configure code detection + submission detection + unit testing + automated deployment.

Code specification

Integrate the EditorConfig configuration

EditorConfig helps maintain a consistent coding style for multiple developers working on the same project on different IDE editors.

Website: editorconfig.org

Add the.editorConfig file to the project root directory:

# Editor configuration, See http://editorconfig.org # root = true [*] # all files applicable charset = UTF-8 # utF-8 Indent_style = space # indented style (TAB | space) indent_size = 2 # # end_of_line indentation size = lf control line type (lf | cr | CRLF) Trim_trailing_whitespace = true # Insert_final_newline = true # Always insert a newline at the end of the file [*.md] # indicates that the following rules apply only to MD files max_line_length = off trim_trailing_whitespace = falseCopy the code

Note: VSCode uses EditorConfig to download EditorConfig for VSCode from the plugin market

Integrating the Prettier configuration

Prettier Prettier is a powerful code formatting tool that supports JavaScript, TypeScript, CSS, SCSS, Less, JSX, Angular, Vue, GraphQL, JSON, Markdown, etc. Basically the front end can use the file format it can be done, is the most popular code formatting tool.

Liverpoolfc.tv: prettier. IO /

  1. Install the Prettier
npm i prettier -D
Copy the code
  1. configuration.prettierrc

The. Prettierrc file is created in the root directory of the project, where the configuration is as follows:

{
  "useTabs": false,
  "tabWidth": 2,
  "printWidth": 100,
  "singleQuote": true,
  "trailingComma": "none",
  "bracketSpacing": true,
  "semi": false
}
Copy the code

Note:

  • The VSCode editor Prettier requires downloading the plug-in Prettier-code Formatter to use Prettier for configuration

Prettier after Prettier is configured, when VSCode formatting is used, the editor formats the Prettier configuration file according to the rules of the Prettier configuration file, avoiding the coding style differences caused by different editors where Prettier is configured.

Integrate ESLint configuration

ESLint is a tool for finding and reporting problems in code, and for auto-fixing some problems. Its core is the ability to analyze code to check code quality and style problems through pattern matching of AST (Abstract Syntax Tree) obtained from code parsing.

As we mentioned before as team members programming ability and coding habits between different quality problems caused by the code, we use ESLint to solve, while writing code to find problems, if found wrong, prompt is given rules, and automatically repair, go down for a long time, can make team members gravitate to the same kind of coding style.

  1. Install ESLint
npm i eslint -D
Copy the code
  1. Configuration ESLint

After ESLint is installed successfully, execute NPX ESLint –init and follow terminal instructions to complete a series of Settings to create the configuration file.

Based on the above selection, ESLint will automatically look for missing dependencies, which we select hereYesDownload and install these dependencies using NPM.

Note: If the automatic installation dependency fails, manual installation is required

npm i @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-airbnb-base eslint-plugin-import eslint-plugin-vue -D
Copy the code
  1. ESLint configuration files.eslintrc.js

After the previous step, the.eslintrc.js configuration file is automatically generated in the project root directory:

module.exports = { env: { browser: true, es2021: true, node: true }, extends: [ 'plugin:vue/vue3-essential', 'airbnb-base', 'plugin:jest/recommended', 'plugin: prettier/it / / add a prettier plug-in], parserOptions: {ecmaVersion: 13, the parser: '@typescript-eslint/parser', sourceType: 'module' }, plugins: ['vue', '@typescript-eslint'], rules: { 'generator-star-spacing': 'off', 'no-debugger': 'off', 'no-tabs': 'off', 'no-unused-vars': 'off', 'no-console': 'off', 'no-irregular-whitespace': 'off', 'import/no-unresolved': 'off', 'import/extensions': 'off', 'import/no-absolute-path': 'off', 'import/no-extraneous-dependencies': 'off', 'vue/no-multiple-template-root': 'off', 'no-param-reassign': [ 'error', { props: true, ignorePropertyModificationsFor: [ 'e', // for e.returnvalue 'ctx', // for Koa routing 'req', // for Express requests 'request', // for Express requests 'res', // for Express responses 'response', // for Express responses 'state' // for vuex state ] } ] }, settings: { 'import/resolver': { typescript: { project: `${__dirname}/tsconfig.json` } } } }Copy the code

Note:

  • To use the ESLint configuration file for VSCode, you need to download the plugin ESLint from the plugin market

After the configuration is complete, we enable ESLin in VSCode. When writing code, ESLint will check the code in real time according to our configured rules, and will give error messages and fix solutions if any problems are found. Although, now the editor has given error prompts and fixes, but we need to click one by one to fix, or quite troublesome. Very simple, we just set the editor to automatically execute when saving the fileeslint --fixCommand for code style fixes.

  • VSCode insettings.jsonAdd the following code to the Settings file:
"editor.codeActionsOnSave": { "source.fixAll.eslint": true }
Copy the code
  • EsLint reports an error when typescript uses import

You need to install eslint-plugin-import and eslint-import-resolver-typescript plug-ins to configure esLint to use tsconfig.js path

"paths": { "@/*": ["./*"]}
Copy the code

8. Resolve conflict between Prettier and ESLint

When you add extra configuration rules for ESLint and Prettier to your project, there are often rules that conflict.

The ESLint configuration in this project uses the Airbnb JavaScript style guide validation. One of the rules is to put a semicolon after the end of code, while we added an unsemicolon after the end of code in the Prettier configuration file, so there’s a conflict, Prettier formatting code occurs after Prettier is used, ESLint detects formatting errors and throws an error.

Eslint-plugin-prettier and eslint-config-prettier are used to solve conflicts between the two.

  • eslint-plugin-prettierPrettier’s rule into ESLint’s rule
  • eslint-config-prettierDisable the rule in ESLint that conflicts with Prettier.

Prettier Configuration Rule > ESLint Configates rules.

  • in.eslintrc.jsAdd the prettier plug-in
Extends: [' plugin: vue/vue3 - essential ', 'reality - base', 'the plugin: prettier/it / / add a prettier plug-in].Copy the code

Integrate Husky and Lint-staged

We already integrate ESLint and Prettier into the project, where they verify code in real time and, to a certain extent, regulate it, but some people on the team may find the restrictions cumbersome and choose to ignore “hints”. Write your code in your own style, or disable the tools altogether, and commit your code directly to the repository. Over time, ESLint becomes useless.

So, we also need to make certain that the repository code is spec compliant by making it impossible to commit code that has not passed ESLint detection and fixes.

To solve this problem, you need to use a Git Hook. When a local Git commit is performed, ESLint checks and fixes the committed code (i.e., ESLint –fix). If the code fails to pass the ESLint rule, the commit is disabled.

To achieve this feature, we resorted to Husky + Lint-staged. Husky — Git Hook, which can be set to trigger Git commands at various stages (pre-commit, commit-msg, pre-push, etc.). Lint-staged — Run linters on files temporarily stored in Git.

  • Configuration husky

Use the husky-init command to quickly initialize a husky configuration in your project

npx husky-init ; npm install
Copy the code

This command does four things:

  1. Install Husky to development dependencies

  1. Create in the project root directory.huskydirectory

  1. in.huskyThe directory to createpre-commitHook, and initializepre-commitCommand tonpm test

  1. Modify thepackage.json 的 scripts, an increase of"prepare": "husky install"

Here, husky is configured and now we can use it:

Husky contains many hooks, such as pre-commit, commit-msg, and pre-push. Here, we use pre-commit to trigger the ESLint command.

Alter.husky/pre-commit hook trigger command:

eslint --fix ./src --ext .vue,.js,.ts
Copy the code

The above pre-commit hook file does the following: Git commit -m “XXX” : $git commit -m “XXX” : $git commit -m “XXX” : $git commit -m

However, there is a problem: sometimes we need to implement ESLint –fix for all files when we have changed only one or two files. If this were a history project and we configured ESLint rules halfway through, then other unmodified “history” files would also be checked when submitting code, which could result in a large number of ESLint errors, obviously not the desired result.

We want to use ESLint only to fix the code we wrote this time and not affect the rest of the code. So there’s a magical tool called Lint-Staged.

Configuration lint – staged

Lint-staged this tool, commonly used in conjunction with Husky, allows Husky hook triggered commands to only act on Git add files (files in git staging) without affecting other files.

  1. Install the lint – staged
npm i lint-staged -D
Copy the code
  1. inpackage.jsonTo add lint-staged configuration items
"lint-staged": { "*.{vue,js,ts}": "eslint --fix" }
Copy the code
  1. Modify the.husky/pre-commitThe trigger command of hook is:npx lint-staged

Husky and Lint-staged configurations are now complete. Add./ SRC/git commit -m “test…” Eslint –fix will be executed for only the two files test-1.js and test-2.ts. If ESLint passes, the commit succeeds, otherwise the commit terminates. This ensures that the code we submit to the Git repository is canonical.

Submit specifications

Commit Message format specification

Commit Message consists of Header, Body, and Footer.

<Header> <Body> <Footer> Copy the codeCopy the code

Header

The Header section contains three fields type (required), Scope (optional), and subject (required).

<type>(<scope>): <subject> Copies codeCopy the code
type

Type specifies the commit type of the commit (it must be one of the following).

value describe
feat Add a new feature
fix Fix a Bug
docs Document change
style Code formatting (does not affect functionality, such as space, semicolon, and other formatting fixes)
refactor Code refactoring
perf To improve the performance
test test
build Changing project builds or external dependencies (e.g. scopes: webpack, gulp, NPM, etc.)
ci Change the scripts commands in the continuous integration software configuration files and packages, such as scopes: Travis, Circle, etc
chore Change the build process or assistive tools
revert Code back
scope

Scope Specifies the scope of the impact of the commit. Scope is determined by project. For example, it can be divided by menu or function module in business project, or component library development. (scope can be omitted)

subject

Subject is a brief description of the commit. The length of the subject is no more than 50 characters. Subject generally complies with the following specifications:

  • Use the first person present tense starting with a verb, e.g. change instead of changed or changes
  • The first letter is lowercase
  • Ending without a period (.)

Integrate the CommitLint validation commit specification

In the “Code Specification” section, we talked about how, despite the specification, in a multi-person project, some people will always do what they want, so we added a restriction to the submission of code: Only commitLint/config-Conventional and @commitLint/CLI commit messages are allowed to pass.

  • Install commitlint

npm i @commitlint/config-conventional @commitlint/cli -D
Copy the code
  • Configuration commitlint

Create a file named commitlint.config.js in the root directory of your project and fill it with the following:

module.exports = { extends: ['@commitlint/config-conventional'] }
Copy the code
  • .huskyDirectory creationcommit-msgfile

Create a commit- MSG file in the. Husky directory and run the commit message authentication command there

#! /bin/sh . "$(dirname "$0")/_/husky.sh" npx --no-install commitlint --editCopy the code
  • Commitlint validation

  • Submission information that does not conform to the specification

As shown in the following figure, the submission information 111 does not meet the specifications and the submission fails.

  • Submit information that conforms to the specification

Commitlint test: Commitlint test complies with the specification and is successfully committed to the repository.

Unit testing

Unit testing is a very important part of project development, complete testing can provide quality assurance for code and business, reduce the occurrence of bugs

  • Installation development dependency

npm i @vue/test-utils@next jest vue-jest@next ts-jest -D
Copy the code
  • Create the JEST configuration file

Create a new jest.config.js file in the project root directory:

module.exports = { moduleFileExtensions: ['vue', 'js', 'ts'], preset: 'ts-jest', testEnvironment: 'jsdom', transform: {' ^. + \ \. Vue $' : 'vue - jest, / / the vue file using the vue - jest conversion' $' ^. + \ \. Ts: 'ts-jest' // ts files with ts-jest conversions}, // match __tests__.js/.ts files or xx.test.js/ts xx.spec.js/ts testRegex in other directories: '(/__tests__/.*|(\\.|/)(test|spec))\\.(ts)$' }Copy the code
  • Create a unit test file

In the jest. Config. js file above, we configure unit tests to match only any.ts file in the __tests__ directory or xx.test.ts/xx.spec.ts file in other directories.

Here, we create the Tests directory under the project root to store the unit test file

├ ─ ─ SRC / └ ─ ─ tests / / / unit Test ├ ─ ─ Test. The spec. Ts / / the Test component testsCopy the code
  • Test.spec.ts
import { mount } from '@vue/test-utils' import Test from '.. /src/views/Test.vue' test('Test.vue', async () => { const wrapper = mount(Test) expect(wrapper.html()).toContain('Unit Test Page') expect(wrapper.html()).toContain('count is: 0') await wrapper.find('button').trigger('click') expect(wrapper.html()).toContain('count is: 1') })Copy the code
  • Test.vue
<template>
  <div class="test-container page-container">
    <div class="page-title">Unit Test Page</div>
    <p>count is: {{ count }}</p>
    <button @click="increment">increment</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  name: 'VuexDemo',
  setup() {
    const count = ref<number>(0)
    const increment = () => {
      count.value += 1
    }
    return { count, increment }
  }
})
</script>

Copy the code
  • Integrated @ types/jest

As shown above, when we use VSCode/WebStrom/IDEA, in the unit test file, the IDE will indicate that certain methods (test, describe, IT, expect, etc.) do not exist, which can be fixed by installing @types/jest.

npm i @types/jest -D
Copy the code

The TypeScript compiler will also tell you that jest methods and types are missing. We need to add @types/jest to ts.config.json (TypeScript configuration file) in the root directory:

{ "compilerOptions": { ... "types": ["vite/client", "jest"] }, }
Copy the code
  • Add eslint – plugin – jest

Because we integrated ESLint into the project, as shown above, it clearly failed ESLint rule verification. Therefore, we also need to add the eslint-plugin-jest plugin to ESLint to unvalidate jEST.

  • Install eslint – plugin – jest
npm i eslint-plugin-jest -D
Copy the code
  • Add eslint-plugin-jest to the esLint configuration file.eslintrc.js 中
extends: [ 'plugin:vue/vue3-essential', 'airbnb-base', 'plugin:jest/recommended', 'the plugin: prettier/it / / add prettier plugins],Copy the code
  • Executing unit tests

In the scripts of the package.json file in the root directory, add a unit test command: “test”: “jest”

Jest uses the jest config file to find.ts files in __tests__ or.spec.ts and.test.ts files in any other directory. The unit test method is then executed.

Note:

  • Unit test constraints

Previously, we used Husky to constrain the code style specification and commit information specification in the pre-commit and commit-msg phases of Git, respectively. In this step, we do unit tests in the pre-push phase, and let the code push to the remote repository only if all the unit tests pass, otherwise we abort the push.

Use the husky command to automatically create a pre-push hook file in the.husky directory and execute the unit test command NPM run test there.

#! /bin/sh . "$(dirname "$0")/_/husky.sh" npm run testCopy the code

Now, we can conduct unit tests in Git push first. Only when all unit tests pass, can push succeed

Automatic deployment

This project is to build a standard front-end engineering environment, for which we use CI (Continuous Integration) to complete the final deployment of the project.

Common CI tools include GitHub Actions, GitLab CI, Travis CI, Circle CI, etc.

Here, we use GitHub Actions.

  • What are GitHub Actions

GitHub Actions is GitHub’s continuous integration service. Continuous integration consists of Actions such as grabbing code, running tests, logging into remote servers, publishing to third-party services, and more. GitHub calls these Actions Actions.

  • Configuration making Actions

Since GitHub Actions are only valid for the GitHub repository, we create the GitHub repository to host the project code

Where, we use:

  • masterBranches store project source code
  • gh-pagesBranches store packaged static files

The GH-Pages branch is a fixed branch of the GitHub Pages service. You can access the static file resources of this branch through HTTP.

  • Create a lot Token

Create a GitHub Token with repo and Workflow permissions

Note: Newly generated tokens are displayed only once and saved for later use. If it is lost, it can be regenerated

  • Add Secret to the repository

Add the new Token to GitHub repository Secrets and name the new secret VUE3_DEPLOY (whatever you like).

Steps: Repository -> Settings -> Secrets -> New Repository Secret.

Newly created SecretVUE3_DEPLOYThis is used in the Actions configuration file, keep the two places the same!

  • Create the Actions configuration file

  1. Create in the project root directory.githubDirectory.
  2. in.githubDirectory creationworkflowsDirectory.
  3. inworkflowsDirectory creationdeploy.ymlFile.
Jobs: deploy: runs-on: Ubuntu -latest steps: - uses: actions/checkout@v2 - name: Setup Node.js v14.x uses: actions/setup-node@v1 with: node-version: '14.x' - name: Install run: NPM Install # Install dependencies - name: Build run: NPM run Build # package - name: Deploy uses: Peaceiris /actions-gh-pages@v3 # Deploy to GitHub Pages action with: publish_dir:./dist # deploy to dist folder github_token: ${{secrets. Vue3_deploy}} # secret user_name: ${{secrets.MY_USER_NAME}} user_email: ${{secrets.my_user_email}} commit_message: Update Vite2.x + vue3. x + TypeScript Starter # Git commit information for deploymentCopy the code
  • Automatic deployment trigger mechanism

When a new submission is pushed to the GitHub repository, GitHub Actions are triggered to execute commands in the GitHub Action configuration file on the GitHub server, such as: Install dependencies, project packaging, etc., then deploy the packaged static files to GitHub Pages, and finally, we have domain access.

Through the domain nameJingyuanhe. Making. IO/vue3 – typesc…Visit the project

The last

This article is a reference to others, thanks again from 0 to take you to build a standard Vue3. X project engineering environment, mainly to record some pits encountered in the learning process, to prevent the same problems in the future.