对于前端的代码,各种各样的书写风格都可能出现。
比如这样的:
handelSelect(item) {
this.chechedType = item
this.$emit("genSelect", item);
},handleClick(val) { console.log(val)}
对于这种代码我们必须要一种强制的约束才能避免它的出现,从而导致项目中出现看不懂的代码。
vite2.0已经发布有一段时间了,最近准备用在公司的项目上,第一步当然是开始搭建vite2.0的CLI,初步的想法是集成jest、eslint、prettier、stylelint、vue-test-unit。
首先,初始化一个vite2.0的项目:
yarn create @vitejs/app
在template选项中选择vue-ts
这样我们就得到了一个干净的vite+Vue 3.0工程模板。
接下来往里面集成:
首先是editorconfig,这里我使用的编辑器是Vscode。 项目的根目录中新建.editorconfig文件,内容如下:
# http://editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
max_line_length = 100
trim_trailing_whitespace = true
[*.md]
max_line_length = 0
然后在vscode的插件中安装eslint并配置:
现在应用商店中找到它:
接下来编辑vscode的setting项,让它能够支持eslint的功能:
这个setting文件位于/Users/你的用户名/Library/Application Support/Code/User/settings.json
(MAC)
加入下面的这一段代码:
"eslint.codeAction.showDocumentation": {
"enable": true // 在工作区启动并显示eslint
},
"eslint.format.enable": true, // 启用eslint的功能
"eslint.probe": [ // 启用eslint支持的项
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"html",
"vue",
"markdown"
],
"editor.codeActionsOnSave": { // 保存代码时自动修复代码的格式错误
"source.fixAll.eslint": true
},
"eslint.nodeEnv": ""
安装eslint:
由于我要使用到typescript、prettier、vue3.0 所以它们对应的插件也要装上:
yarn add -D eslint-config-prettier eslint eslint-plugin-import eslint-plugin-prettier eslint-plugin-vue prettier @typescript-eslint/eslint-plugin @typescript-eslint/parser
编辑eslintrc.js:
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: [
'plugin:vue/vue3-recommended', // 导入vue3的格式建议拓展
'plugin:@typescript-eslint/recommended', // 使用ts导入ts的格式建议拓展
],
parserOptions: {
ecmaVersion: 2020,
parser: '@typescript-eslint/parser',
sourceType: 'module',
jsxPragma: 'React', // jsx的解析方式
ecmaFeatures: {
jsx: true,
tsx: true,
},
},
parser: 'vue-eslint-parser',
plugins: ['vue', '@typescript-eslint', 'prettier'],
rules: {
// js/ts
'eol-last': 'error', // 禁止文件末尾保留一行空行
'no-trailing-spaces': 'error', // 禁用行尾空白
'comma-style': ['error', 'last'], // 逗号的风格,在末尾补上逗号
'comma-dangle': ['error', 'always-multiline'], // 在[].{}中换行的尾部用上逗号
'quotes': ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }], // 默认单引号
'camelcase': ['error', { properties: 'never' }], // 驼峰语法
'semi': ['error', 'never'], // 禁止使用半分号
'indent': ['error', 2, { SwitchCase: 1 }], // 前空隙,2个单位
'object-curly-spacing': ['error', 'always'], // 强制在{}中使用一致的空格
'arrow-parens': ['error', 'as-needed'], // 箭头函数需要括号
'@typescript-eslint/explicit-module-boundary-types': 'off', // ts的约束
'@typescript-eslint/no-explicit-any': 'off', // ts的约束
'@typescript-eslint/member-delimiter-style': [ // ts的约束
'error',
{
multiline: {
delimiter: 'none',
requireLast: false,
},
singleline: {
delimiter: 'semi',
requireLast: true,
},
},
],
// vue相关约束
'vue/no-v-html': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/html-self-closing': [
'error',
{
html: {
void: 'never',
normal: 'never',
component: 'always',
},
},
],
'vue/max-attributes-per-line': [
'error',
{
singleline: 3,
multiline: 1,
},
],
'vue/require-default-prop': 'off',
'vue/html-closing-bracket-spacing': 'error',
},
}
接下来编辑.eslintignore
:
*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
/public
/docs
.husky
.local
/bin
Dockerfile
编辑.prettierrc.js
:
module.exports = {
printWidth: 100,
tabWidth: 2,
useTabs: false, // 使用空格缩进
semi: true, // 分号
vueIndentScriptAndStyle: true,
singleQuote: true,
quoteProps: 'as-needed',
bracketSpacing: true, //对象大括号直接是否有空格,默认为true,效果:{ foo: bar }
trailingComma: 'es5',
jsxBracketSameLine: false,
jsxSingleQuote: false, // jsx 属性使用双引号
arrowParens: 'avoid', // 箭头函数只有一个参数的时候可以忽略括号
insertPragma: false,
requirePragma: false,
proseWrap: 'preserve', // 换行方式
htmlWhitespaceSensitivity: 'strict',
endOfLine: 'auto', // 行结束符使用 Unix 格式
rangeStart: 0
};
至此,我们的js代码已经能在保存的时候自动修复格式的错误了。
接下来我们安装stylelint:
yarn add -D stylelint stylelint-config-prettier stylelint-config-standard
新建stylelint.config.js
文件:
module.exports = {
root: true,
extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
rules: {
// 不要使用已被 autoprefixer 支持的浏览器前缀
'media-feature-name-no-vendor-prefix': true,
'at-rule-no-vendor-prefix': true,
'selector-no-vendor-prefix': true,
'property-no-vendor-prefix': true,
'value-no-vendor-prefix': true,
},
ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.tsx', '**/*.ts'],
};
现在错误格式的CSS也能被指示出来了。
接入jest
在协作开发的过程中,有严格代码规范特别重要,并且能做好前端的单元测试特别重要,鉴于这个原因,我们接下来将在项目中引入jest,在vue-cli在能够勾选完成单元测试的一些配置和引用,这里我将说明一下不同的配置项,不同的包的作用是什么。
首先,我们要导入jest的库:
yarn add @types/jest babel-jest ts-jest jest vue-jest --dev
由于我使用的是Vue 3.0所以在这里需要指定vue-jest
的版本为:5.0.0-alpha.5
这里,我模仿elementUI的packages设定来做,使用lerna来做packages的拆分,每个package一个package.json,接下来构建lerna.json:
{
"packages": [
"packages/*"
],
"version": "independent",
"npmClient": "yarn",
"useWorkspaces": true
}
在根目录的package.json中指定workplace:
{
...
"private": true,
...
"workspaces": [
"packages/*"
],
...
}
然后是jest.config.js
的配置项:
module.exports = {
globals: {
// work around: https://github.com/kulshekhar/ts-jest/issues/748#issuecomment-423528659
'ts-jest': {
diagnostics: {
ignoreCodes: [151001],
},
},
},
testEnvironment: 'jsdom', // 测试的环境
transform: {
'^.+\\.vue$': 'vue-jest',
'^.+\\.(t|j)sx?$': [
'babel-jest',
{
presets: [
[
'@babel/preset-env',
{
targets: {
node: true,
},
},
],
'@babel/preset-typescript',
],
plugins: ['@vue/babel-plugin-jsx'], // 主要是配置jsx运行环境
},
],
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
// u can change this option to a more specific folder for test single component or util when dev
// for example, ['<rootDir>/packages/input']
roots: ['<rootDir>'],
}
有了这些我们可以开始正式的编写属于我们的package了:
新建一个package
目录,在下面新建src
,__test__
目录
其中,__test__
目录用于放测试的脚本,这里我写了一个最简单的demo:
index.vue:
<template>
<div>
{{ content }}
</div>
</template>
<script lang='ts'>
import {
defineComponent,
} from 'vue'
export default defineComponent({
name: 'MyComponentA',
props: {
content: {
type: String,
default: '',
},
},
})
</script>
myComponentA.spec.ts:
import { mount } from '@vue/test-utils'
import myComponentA from '../src/index.vue'
describe('myComponentA.vue', ( )=> {
const testText = 'this is a beautiful girl !'
test('render', () => {
const wrapper = mount(myComponentA, {
props: {
content:testText,
},
})
expect(wrapper.text()).toEqual(testText) // 检查渲染出来的文本是否包含上面的内容 涉及一些jest的API
})
})
写好上面的内容后,我们在根目录运行jest
:
测试通过!
这里是demo的代码
接下来,我还要往里面集成jest进行自动化测试。