Vue3 项目模版搭建(二)

617 阅读9分钟

模板技术信息:

模版工程化配置:

文章系列目录

Vue3 项目模版搭建(一)

Vue3 项目模版搭建(二)

前言

Vue3 项目模版搭建(一) 后续文章,内容主要为模版项目中的工程化基础配置,主要包含有:代码提交规范日志生成及发布 以及单元测试 等等。

项目github 地址: vue3-vite-ts-pnpm

代码规范

日常多人协作时,代码风格会略有不同。因而在项目协作中代码规范统一是必不可少的!而且良好的代码规范不仅可以让代码看起来更加整洁,而且可以提升代码的审查效率。

在这里则使用 eslintprettier 进行代码风格的基本规范。

配置 EditorConfig

VS Code 商店安装 EditorConfig for VS Code 插件,帮助统一编辑器风格 image-20220211103235017.png

配置 EditorConfig

在根目录下创建一个名为 .editorconfig 的配置文件,内容如下:

# Editor configuration, see http://editorconfig.org

root = true                        # 是否为根目录,支持不同层级单独配置

[*]                                # 适用所有文件
indent_style = space               # tab | space
indent_size = 4                    # 缩进
end_of_line = crlf                 # lf | cr | crlf
charset = utf-8                    # 字符集
trim_trailing_whitespace = true    # 自动切掉首尾空格
insert_final_newline = true        # 末尾空行

[*.{js,ts,vue,jsx,tsx}]            # 如何处理这些文件
indent_size = 2                    # 缩进为 2

[*.md]                             # 如何处理这些文件
trim_trailing_whitespace = false   # 不自动切掉首尾空格

配置 Prettier

VS Code 商店安装 Prettier - Code formatter 插件,帮助将代码格式化为统一风格 image-20220211103304673.png

安装 prettier

pnpm i prettier -D

配置 prettier

在根目录下创建一个名为 .prettierrc 的配置文件,内容如下:

{
    "useTabs": false,
    "tabWidth": 2,
    "printWidth": 80,
    "singleQuote": true,
    "trailingComma": "none",
    "bracketSpacing": true,
    "semi": true,
    "arrowParens": "avoid"
}

更多 prettierrc 字段配置说明可参考 eslint规则在项目中的整合(js、prettier、vue、typescript)官方文档

使用 prettier

通过 prettier 命令格式化统一代码风格,快捷键:Alt + Shift + Fopt + Shift + F

npx prettier --write .    # . 表示所有文档

配置 ESlint

VS Code 商店安装 ESLint 插件,帮助将代码格式化为统一风格 image-20220211105126325.png

安装 eslint

pnpm i eslint -D

配置 ESLint

通过下面命令初始化 eslint 配置

npx eslint --init

按照命令提示相对应的选项,如下图所示: image-20220211105544957.png PS:注意在最后一步不要选择 Yes 使用 npm 自动下载相关的依赖包,会出现报错。主要是版本相关和缺少依赖包的错误。 image-20220107191314419.png 手动安装 eslint 配置所需要的相应依赖包

pnpm i eslint-plugin-vue eslint-config-airbnb-base eslint-plugin-import @typescript-eslint/eslint-plugin @typescript-eslint/parser -D

安装后会自动在根目录下生成 .eslintrc.js 配置文件,使用 opt + Shift + F 快捷键可格式化配置文件代码,添加如下规则:

rules: {
	'linebreak-style': 0,
},

配置 Vue 规则

vue3 规则配置
extends: [
  'plugin:vue/essential',
  'airbnb-base',
  'plugin:vue/vue3-recommended', // vue3 的规则。vue2 使用 plugin:vue/recommended
],
vue 文件解析 parser
// 添加文件错误解析 parser
parser: 'vue-eslint-parser', // 解析 .vue 文件
ts 支持

对于 airbnb-base 规则,需单独添加 TypeScript 的支持

pnpm i eslint-config-airbnb-typescript -D
extends: [
  'plugin:vue/essential',
  'airbnb-base',
  'airbnb-typescript/base', // 添加 typescript 支持
  'plugin:vue/vue3-recommended', // vue3 的规则。vue2 使用 plugin:vue/recommended
],

使用 ESlint

package.json 文件中添加如下命令

"scripts": {
  ...,
  "lint": "eslint src/**/*.{vue,ts}",
   "lint:fix": "eslint src/**/*.{vue,ts} --fix",
  "lint:create": "eslint --init"
},

执行下面命令修复所有内容 eslint 相关问题,若此时仍有报错,可先了解是否为下面描述的 冲突及问题处理 相关问题,如果不是的话,则可能需手动进行修复处理。

pnpm run lint:fix

image-20220211113933305.png 修改 lint:fix 命令如下

"lint:fix": "eslint src/**/*.{vue,ts} --fix",

冲突及问题处理

ts 文件解析问题

无法解析处理 ts 文件,详情见 How to fix eslintrc The file does not match your project config?.eslintrc.ts 添加下面配置信息:

 parserOptions: {
    ...,
    tsconfigRootDir: __dirname,
    project: './tsconfig.json',
  },

image-20220211114328083.png

vue 文件解析问题

无法解析处理 .vue 文件,.eslintrc.ts 添加下面配置信息:

  parserOptions: {
    ...,
    extraFileExtensions: ['.vue'],
  },

image-20220211114524747.png

解决 Prettier 与 ESLint 的冲突问题

这两个的规则有时存在冲突,一般情况下以 Prettier 优先;安装插件并在 .eslintrc.ts 添加相应配置信息

pnpm i eslint-plugin-prettier eslint-config-prettier -D                                
extends: [
  'plugin:vue/essential',
  'airbnb-base',
  "airbnb-typescript/base", // 添加 typescript 支持
  "plugin:vue/vue3-recommended", // 添加高亮行内容到文件 (vue3 的规则)。vue2 使用 plugin:vue/recommended
  'plugin:prettier/recommended', // 添加解决冲突插件
],
解决通过 @ 引入的路径问题

使用路径别名如 @ 可能会出现无法找到相应路径问题错误;安装插件并在 .eslintrc.ts 添加相应配置信息

pnpm i eslint-import-resolver-alias eslint-import-resolver-typescript -D

tsconfig.json 中添加

{
  "compilerOptions": {
    "baseUrl": ".",
    "types": ["vite/client", "node"],
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

.eslintrc.js 中添加

module.exports = {
  ...
  settings: {
    "import/parsers": {
      "@typescript-eslint/parser": [".ts", ".tsx"]
    },
    "import/resolver": {
      alias: {
        map: [["@", "./src"]],
        extensions: [".js", ".jsx"]
      },
      typescript: {
        alwaysTryTypes: true,
        project: "./tsconfig.json"
      }
    }
  },
  ...
}

解决 defineProps 等未定义的错误

使用 <script setup> 标签时,defineProps 等不再需要显示定义,不过这样 eslint 规则会报错,所以需要进行相应的配置

module.exports = {
  ...
  globals: {
    defineProps: "readonly",
    defineEmits: "readonly",
    defineExpose: "readonly",
    withDefaults: "readonly"
  }
  ...
};
解决函数参数无法修改问题

添加忽略参数无法修改规则的白名单,具体可参考 优雅解决: assignment to property of function parameter 'state'

"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
    ]
  }
]
其它 rules 配置
module.exports = {
  rules: {
    "prettier/prettier": ["error", { endOfLine: "auto" }], // 解决 prettier 行尾报错
    "vue/multi-word-component-names": "off", // 组件名称是否多单词
    "vue/no-multiple-template-root": "off", // 启用根层级多个标签
    "vue/script-setup-uses-vars": "error", // 标记 setup 中的变量为 used
    "import/prefer-default-export": "off", // 是否需要含有默认导出
    "vue/no-v-model-argument": "off", // 'v-model' directives require no argument
  }
};

husky + lint-staged

husky 添加勾子在相应的时机触发,进行 lint 检查、单元测试、代码美化等操作;lint-staged 则是对个人提交代码的验证规范及约束。更多可查看 husky + lint-staged + commitlint 安装配置

安装配置 husky

安装 husky

pnpm i husky --save-dev

配置 husky

package.json 中添加 prepare 脚本

{
  ...
  "scripts": {
    ...
    "prepare": "husky install", // 新增prepare脚本
  }
  ...
}

执行脚本命令,会创建 .husky/ 目录并指定该目录为 git hooks 所在的目录

pnpm run prepare

执行命令添加 git hooks,执行下面命令后 .husky/ 目录下会增加pre-commitshell 脚本文件。当在执行 git commit 命令时会执行该脚本

npx husky add .husky/pre-commit "npm run lint"

说明

🙅 如果手动添加或修改 huskygit hooks 脚本文件或内容,则会出现下面错误

fatal: cannot run .husky/pre-commit: No such file or directory

image-20220110162751360.png 正确做法(通过命令的方式添加脚本文件及内容信息)

npx husky add .husky/pre-commit "npm run lint"

PS:如果手动修改了出现上面找不到文件问题,最简单粗暴的方式是把 .husky/pre-commit 删除再执行上面命令重新添加

安装配置 lint-staged

安装 lint-staged

pnpm i lint-staged --save-dev

配置 lint-staged

package.json 中添加命令及配置内容如下

{
  "scripts": {
   	...
    "lint": "lint-staged --allow-empty",
    ...
  },
  "lint-staged": {
    "src/**/!(*.min).js": [
      "prettier --write",
      "eslint --fix"
    ],
    "src/**/*.{ts,vue}": [
      "prettier --write",
      "eslint --fix"
    ],
    "src/**/*.{ts,js,vue,html,css,scss,sass,stylus}": [
      "prettier --write"
    ]
  },
}

提交规范

提交规范相关内容在该文章 Git Commit 规范及 CHANGELOG 定制生成 里面讲述的比较详细,这里就不再重新赘述啦!

注意⚠️

  • 将文章里面的 npm 改为 pnpm 执行依赖安装,保持统一
  • git cz 采用全局安装方式,如果采用项目安装的话,命令执行后相应包使用的是 npm 进行安装

单元测试

项目中添加单元测试可以更有效的的保证代码的质量,测试代码编写基本类型,之前写过一遍关于 RN 基于 Jest + testing-library 单元测试实践 测试文章,主要是通过模拟预期操作来进行对应代码的自动化测试过程。

安装依赖

安装测试依赖

pnpm i jest@26.6.3 ts-jest@26.5.6 @vue/test-utils@next vue-jest@next @types/jest eslint-plugin-jest -D

说明jestts-jest 可能存在版本冲突,运行测试内容会报错,需要指定相同的版本。如均为版本 26详情见 issues#351

安装测试需要的 babel 依赖

pnpm i @babel/core @babel/preset-env @babel/preset-typescript @vue/babel-plugin-jsx -D             
pnpm i babel-jest@26

说明babel-jest 由于版本问题,如果安装最新版 ^27,会引起 TypeError: babelJest.getCacheKey is not a function 的错误,所以需要安装 ^26 版本。详情见 issues#344

配置 jest

在根目录下添加 jest.config.js 配置文件,并添加下面内容

module.exports = {
  clearMocks: true,
  coverageDirectory: 'coverage',
  coverageProvider: 'v8',
  moduleFileExtensions: ['vue', 'js', 'json', 'jsx', 'ts', 'tsx', 'node'],
  testMatch: ['**/test/unit/**/?(*.)+(unit|test|spec).[jt]s?(x)'],
  testPathIgnorePatterns: ['/node_modules/'],
  transform: {
    '^.+\\.jsx?$': 'babel-jest',
    '^.+\\.vue?$': 'vue-jest',
    '^.+\\.tsx$': 'ts-jest'
  },
  moduleNameMapper: {
    // 支持源代码中相同的 `@` -> `src` 别名
    '^@/(.*)$': '<rootDir>/src/$1'
  },
  preset: 'ts-jest',
  testEnvironment: 'jsdom',
  collectCoverage: true,
  collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx,vue}', '!**/node_modules/**']
  // coverageReporters: ["text", "text-summary", "html"],
};

在根目录下添加 babel.config.js 配置文件,内容如下

module.exports = {
  presets: [
    ["@babel/preset-env", { targets: { node: "current" } }],
    "@babel/preset-typescript"
  ],
  plugins: ["@vue/babel-plugin-jsx"]
};

在 tsconfig.json 配置中添加下面内容

{
  "compilerOptions": {
    "types": ["vite/client", "node", "jest"]
  },
  "include": [
    ...
    "tests/**/*.ts"
  ]
}

在eslintrc.js 配置文件中添加下面内容

extends: [
  ...
  'plugin:jest/recommended',
  ...
],

执行测试

package.json 中添加测试命令

{
  "scripts": {
    ...
    "test": "jest",
    ...
  }
}

在项目根目录下添加测试目录及文件 test/unit/Test.spec.ts,内容如下:

import { mount } from '@vue/test-utils';
import HelloWorld from '@/components/HelloWorld.vue';

describe('Welcome Component Test', () => {
  const wrapper = mount(HelloWorld, {
    props: { msg: 'Hello Test!' }
  });

  it('load component', () => {
    const html = wrapper.text();
    console.log(html);
    expect(html).toContain('Hello Test!');
  });
});

执行下面测试命令

pnpm run test

image-20220211175243826.png

问题处理

  • 根目录下添加 env.d.ts 类型引用说明文件,处理 test 内模块引用问题。

image-20220211194443902.png

  • eslint 忽略文件 .eslintignore 添加需要忽略的配置文件

总结

文章知识回顾。我们可以了解到项目工程化的一些基本配置信息,主要包含以下内容知识:

  • eslint + prettier 代码规范
  • husky + lint-staged 代码提交规范
  • commitize + commitlint + standard-version 代码规范提交及日志自动生成
  • vue-test-utils + jest 单元测试

参考
从 0 搭建项目模板(vue3)
Git Commit 规范及 CHANGELOG 定制生成
RN 基于 Jest + testing-library 单元测试实践