现在web开发变得更加美妙高效,在于开发工具设计得更好了,丰富性与易用性,都有所提高。丰富性带来了一个幸福的烦恼,就是针对实际应用场景,如何选择工具 ?

1. Vue Cli和Vite之间的选择

Vite的开发环境体验好,基于浏览器原生ES6 Modules提供的功能,不对ES高版本语法进行转译,省略掉耗时的打包流程, 可是考虑到:

1) 项目要用到真机调试功能,开发环境下调试代码时不能使用ES高版本的语法,用着不顺畅。

2) Vite的一些痛点:

  • Vite最新版2.7.x版本自带的less-loader, 将背景色的rgba属性转换成四位16进制在有些手机上存在兼容性问题。
  • 与某些第三方工具库(比如说Cache-Router)不兼容,编译会报错。
  • Vite的缓存机制,有时候让人有些困惑,代码修改了,重启之后都不生效,要手动删除node_modules下的.vite文件夹才生效。
  • 给命令行动态添加自定义参数不太方便。
  • Vite不支持装饰器语法,而有的第三方库用到了装饰器语法

3) Vite脚手架默认不集成TypeScript,Vue-Router,Vuex功能,使用起来不太方便

4) Vue Cli作为久经考验的成熟构建工具,稳定坑少,使用者众多,在生态环境和插件数量方面更好。

所以最终选择vue-cli最为Vue项目的脚手架。

安装最新版本vue脚手架

npm install -g @vue/cli@next

安装成功后通过查看版本命令,确认是否安装成功

vue -V
@vue/cli 5.0.0-rc.1

2 创建vue3项目

vue create vue3-demo

Vue CLI v5.0.0-rc.1
? Please pick a preset:
  Default ([Vue 2] babel, eslint)
  Default (Vue 3) ([Vue 3] babel, eslint) // 不选择默认的vue3配置,是因为没有vue-router+typescript功能,需要自己引入
> Manually select features // 手动选择特性

Vue CLI v5.0.0-rc.1
? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed)
>(*) Choose Vue version
(*) Babel // 添加babel
(*) TypeScript // 添加类型约束功能
( ) Progressive Web App (PWA) Support
(*) Router // 添加路由功能
(*) Vuex // 添加状态管理功能
(*) CSS Pre-processors // 添加样式预编译功能
(*) Linter / Formatter // 添加代码质量校验提示和格式化功能
( ) Unit Testing
( ) E2E Testing
Vue CLI v5.0.0-rc.1
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS, Router, Vuex, CSS Pre-processors, Linter
? Choose a version of Vue.js that you want to start the project with
2.x
> 3.x // 选择vue3
Vue CLI v5.0.0-rc.1
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS, Router, Vuex, CSS Pre-processors, Linter
? Choose a version of Vue.js that you want to start the project with 3.x
? Use class-style component syntax? (y/N) N // 是否使用class组件语法, ,选N 项目中用Composition API

为了在Vue中使用TypeScript中,许多开发者选择了Class-Style Component 解决方案,时至今日,还有另外一个方案,Composition API 撰写的代码会完美享用类型推导,并且也不用做太多额外的类型标注。这也同样意味着你写出的 JavaScript 代码几乎就是 TypeScript 的代码。即使是非 TypeScript 开发者也会因此得到更好的 IDE 类型支持而获益。

常规风格

export default {
data(){
return {
selectOptions: ['A1', 'A2'],
results: [],
// ...
}
}
}

class 组件风格

import { Vue, Component } from 'vue-property-decorator'
@Component
export default class Game extends Vue {
// 定义data
private selectOptions = ['A1', 'A2']
private results: string[] = []
...
}
? Use class-style component syntax? Yes

? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes  // 是否使用babel工具自动为转换后的 TypeScript 代码注入 polyfiills,此处选择 Y 

? Use history mode for router? (Requires proper server setup for index fallback in production) Yes   // 使用history网址路径风格,hash路径有点丑陋

? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Less    // sass在国内安装经常出错,所以选less

? Pick a linter / formatter config: Prettier  // 校验配置选择 eslint+prettier组合,沿袭项目使用习惯

? Pick additional lint features: Lint on save // 保存代码时校验代码质量, 提交代码时才去校验代码质量有些滞后

? Where do you prefer placing config for Babel, ESLint, etc. In dedicated config files // 将Babel,ESlint等配置文件从package.json中独立出来,因为json文件不能写注释

? Save this as a preset for future projects? Y // 将此配置保存起来,用于将来的项目 ,下次用vue-cli生成项目时,可以看到之前保存的配置项

启动服务

cd vue3-demo && yarn serve

在VSCode中打开app.vue发现文件中有许多红色的告警波浪线,安装Vetur扩展,绝大多数语法报错消失。

3 配置vue文件保存时自动格式化

代码美化功能,是一个重要的影响开发体验的指标。书写潦草的代码,按下Ctrl+S保存之后,瞬间变成整洁有序, 这种视觉感受,让人神清气爽。

在项目下新建.vscode/settings.json,内容如下:

{
// ...
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[vue]": {
"editor.defaultFormatter": "octref.vetur"
},
"[json]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
// ...
}

修改项目下的.prettierrc文件为.prettierrc.js, 内容如下:

module.exports = {
// 1.一行代码的最大字符数,默认是80(printWidth: <int>)
printWidth: 120,
// 2.tab宽度为2空格(tabWidth: <int>)
tabWidth: 2,
// 3.是否使用tab来缩进,我们使用空格(useTabs: <bool>)
useTabs: false,
// 4.结尾是否添加分号
semi: true,
// 5.使用单引号(singleQuote: <bool>)
singleQuote: true,
// 6.object对象中key值是否加引号(quoteProps: "<as-needed|consistent|preserve>")as-needed只有在需求要的情况下加引号,consistent是有一个需要引号就统一加,preserve是保留用户输入的引号
quoteProps: 'as-needed',
// 7.在jsx文件中的引号需要单独设置(jsxSingleQuote: <bool>)
jsxSingleQuote: false,
// 8.尾部逗号设置,es5是尾部逗号兼容es5,none就是没有尾部逗号,all是指所有可能的情况,需要node8和es2017以上的环境。(trailingComma: "<es5|none|all>")
trailingComma: 'all',
// 9.object对象里面的key和value值和括号间的空格(bracketSpacing: <bool>)
bracketSpacing: true,// 10.箭头函数单个参数的情况是否省略括号,默认always是总是带括号(arrowParens: "<always|avoid>")
arrowParens: 'always',
// 11.range是format执行的范围,可以选执行一个文件的一部分,默认的设置是整个文件(rangeStart: <int> rangeEnd: <int>)
rangeStart: 0,
rangeEnd: Infinity,
// 12. requirePragma: <bool>,格式化有特定开头编译指示的文件 比如下面两种
/**
* @prettier
*/
// or
/**
* @format
*/
requirePragma: false,
// 13.insertPragma: <bool> 自动插入pragma到已经完成的format的文件开头
insertPragma: false,
// 14. proseWrap: "<always|never|preserve>" 文章换行,默认情况下会对你的markdown文件换行 进行format会控制在printwidth以内
proseWrap: 'always',
// 15. htmlWhitespaceSensitivity: "<css|strict|ignore>" html中的空格敏感性
// html文档片段 1<b>2</b>3 原本显示为123, 不设置忽略空格的话格式化后会变成 1<b> 2 </b>3 显示为1 2 3
htmlWhitespaceSensitivity: 'ignore',
// 16. vue script和style标签中是否缩进,开启可能会破坏编辑器的代码折叠
vueIndentScriptAndStyle: false,
// 17. endOfLine: "<lf|crlf|cr|auto>" 行尾换行符,默认是lf,
endOfLine: 'lf',
// 18. 控制被引号包裹的代码是否进行格式化, 默认是auto,
embeddedLanguageFormatting: 'off'
}

4 配置移动端UI库

做移动端开发,虽然定制性比较强。绝大多数UI库组件都用不到,但像Toast,Modal,Picker,Form,PullRefresh等组件几乎是必用,所以需要引入移动端UI库。

vue3移动端UI库的选择:

antd-mobile-vue-next 移入项目之后,编译报错
Vux UI风格是绿色系,与现有项目使用的蓝色系风格UI不符,  所以没用
Vant 是业界主流的移动端组件库之一,UI色系风格与历史项目相符,支持vue3,组件功能优于Vux,已Toast为例,Vant提供了网络加载的Toast, Vux未提供。Vant总共提供了69个(不含组合api)涵盖基础,表单,反馈,展示,导航,业务六大类组件。
 yarn add vant@3

按需引入

按需加载需要借助babel-plugin-import, 这样就可以只引入需要的组件,以减小项目体积

yarn add babel-plugin-import -D

对babel.config.js进行配置

module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
plugins: [
[
"import",
{
libraryName: "vant",
libraryDirectory: "es",
style: true,
},
"vant",
],
],
};

main.js中引入vant的样式

import { createApp } from "vue";
import App from "./App.vue";
import "vant/lib/index.css";
createApp(App).mount("#app");

在App.vue中引入组件

<template>
<div>
<Button type="primary">主要按钮</Button>
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js App" />
</div>
</template> <script>
import HelloWorld from "./components/HelloWorld.vue";
import { Button } from "vant";
export default {
name: "App",
components: {
HelloWorld,
Button,
},
};
</script>

5 配置开发环境请求代理

请求代理是解决本地开发请求跨域的最佳方式之一,对前后端代码都没有侵入性。  在vue.config.js中添加代理转发配置:

const { defineConfig } = require("@vue/cli-service");
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
port: 9000,
host: "localhost",
https: false,
open: "/",
proxy: {
"/api": {
target: "http://192.168.xx.xx:50000",
secure: false,
changeOrigin: true,
logLevel: "debug",
},
},
},
// ....
});

6 配置路径别名

项目统一使用路径别名,好处是在代码中不用写../../../之类让人看着有些云里雾里的文件引用路径,此外用短路径替代长路径,书写也更方便。而且编辑器对于别名路径也有提示,可以跳转。

需要注意的是,如果使用了TypeScript,除了要在vue.config.js中配置路径别名之外,还需要在tsconfig.json配置路径别名,否则虽然打包编译不报错,但是代码编辑器却会提示引用路径有错误。

vue.config.js路径别名配置

const path = require('path');

module.exports = {
configureWebpack: {
resolve: {
alias: {
'@': path.join(__dirname, 'src/')
}
}
}
}

tsconfig.json路径别名配置

{
"compilerOptions": {
// ...
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
}
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
// 包含自定义声明文件
"typings/**/*.d.ts",
],
// ...
}

7 设置自定义环境变量

开发调试的时候,需要动态在命令行添加动态参数,用以执行开发环境的调试逻辑,将自定义的命令行参数传到业务文件的方法是:

在package.json中传入自定义环境变量

{
// ...
"scripts": {
"start:wx": "ytt && vue-cli-service serve --mode local --wx true",
// ...
},
}

在vue.config.js中设置自定义环境变量

// ...
const webpack = require('webpack');
const { defineConfig } = require('@vue/cli-service');
const { wx, mode } = require('minimist')(process.argv.slice(2));
console.log({ wx, mode }); // console.log(process.env.VITE_API_HOST);
module.exports = defineConfig({
// ...
configureWebpack: {
plugins: [
// 定义环境变量
new webpack.DefinePlugin({
'process.env.WX_JS_SDK_ENABLED': wx, // 是否真机调试SDK模式
'process.env.CURRENT_ENV': JSON.stringify(mode),
}),
],
},
});

在业务文件中接收自定义环境变量

import { createApp } from 'vue';
import 'vant/lib/index.css';
import App from './App.vue';
import router from './router';
import store from './store'; console.log(process.env.WX_JS_SDK_ENABLED, process.env.CURRENT_ENV); createApp(App).use(store).use(router).mount('#app');

8 配置stylelint校验规则

stylelint的好处:

  • 可以发现样式书写问题,如无效的十六进制值;重复的选择器;未命名的动画名称;错误的线性渐变语法;后面的属性覆盖前面的属性;前面的选择器优先级更高,覆盖后面的属性;选择器下未设置任何属性等。
  • 能使所有人写的样式风格都一致,按照业内知名公司 (GitHub、Google、Airbnb)的样式规范要求写样式。
  • 保存时自动对样式书写进行优化(如采用样式的简写形式,删除无意义小数点前面的0,调整样式顺序等),修复可以修复的样式错误。

1.安装依赖

yarn  add -D stylelint stylelint-config-recess-order  stylelint-order stylelint-config-standard stylelint-less  stylelint-webpack-plugin postcss-html

2. 创建.stylelintrc.js 样式校验规则

module.exports = {
plugins: ['stylelint-less'],
extends: ['stylelint-order', 'stylelint-config-standard', 'stylelint-config-recess-order'],
rules: {
indentation: 2,
'at-rule-no-unknown': [true, { ignoreAtRules: ['mixin', 'extend', 'content', 'include'] }],
'no-empty-source': null, // null是关闭规则的意思--less文件内容可以为空
'no-descending-specificity': null, //禁止特异性较低的选择器在特异性较高的选择器之后重写
'font-family-no-missing-generic-family-keyword': null, // 关闭必须设置通用字体的规则
'property-no-unknown': [
true,
{
ignoreProperties: ['box-flex'], // 忽略某些未知属性的检测
},
],
'selector-pseudo-element-no-unknown': [
true,
{
ignorePseudoElements: ['ng-deep'], // 忽略ng-deep这种合法的伪元素选择器报警
},
],
'declaration-colon-newline-after': null, //一个属性过长的话可以写成多行
'media-feature-name-no-unknown': null, // 关闭禁止未知的媒体功能名
// 下面的排序规则是stylelint-config-recess-order的css排序规则,
// 要对某个属性排序进行调整,这个属性之前的样式排序都要配置在自定义属性排序中
'order/properties-order': [
{
// Must be first.
properties: ['all'],
},
{
// Position.
properties: ['position', 'top', 'right', 'bottom', 'left', 'z-index'],
},
{
// Display mode.
properties: ['box-sizing', 'display'],
},
{
// Flexible boxes.
properties: ['flex', 'flex-basis', 'flex-direction', 'flex-flow', 'flex-grow', 'flex-shrink', 'flex-wrap'],
},
{
// Grid layout.
properties: [
'grid',
'grid-area',
'grid-template',
'grid-template-areas',
'grid-template-rows',
'grid-template-columns',
'grid-row',
'grid-row-start',
'grid-row-end',
'grid-column',
'grid-column-start',
'grid-column-end',
'grid-auto-rows',
'grid-auto-columns',
'grid-auto-flow',
'grid-gap',
'grid-row-gap',
'grid-column-gap',
],
},
{
// Align.
properties: ['align-content', 'align-items', 'align-self'],
},
{
// Justify.
properties: ['justify-content', 'justify-items', 'justify-self'],
},
{
// Order.
properties: ['order'],
},
{
// Box model.
properties: [
'float',
'width',
'min-width',
'max-width',
'height',
'line-height',
'min-height',
'max-height',
'padding',
'padding-top',
'padding-right',
'padding-bottom',
'padding-left',
'margin',
'margin-top',
'margin-right',
'margin-bottom',
'margin-left',
'overflow',
'overflow-x',
'overflow-y',
'-webkit-overflow-scrolling',
'-ms-overflow-x',
'-ms-overflow-y',
'-ms-overflow-style',
'clip',
'clear',
],
},
{
// Typography.
properties: [
'font',
'font-family',
'font-size',
'font-style',
'font-weight',
'font-variant',
'font-size-adjust',
'font-stretch',
'font-effect',
'font-emphasize',
'font-emphasize-position',
'font-emphasize-style',
'-webkit-font-smoothing',
'-moz-osx-font-smoothing',
'font-smooth',
'hyphens',
'color',
'text-align',
'text-align-last',
'text-emphasis',
'text-emphasis-color',
'text-emphasis-style',
'text-emphasis-position',
'text-decoration',
'text-indent',
'text-justify',
'text-outline',
'-ms-text-overflow',
'text-overflow',
'text-overflow-ellipsis',
'text-overflow-mode',
'text-shadow',
'text-transform',
'text-wrap',
'-webkit-text-size-adjust',
'-ms-text-size-adjust',
'letter-spacing',
'word-break',
'word-spacing',
'word-wrap', // Legacy name for `overflow-wrap`
'overflow-wrap',
'tab-size',
'white-space',
'vertical-align',
'list-style',
'list-style-position',
'list-style-type',
'list-style-image',
],
},
{
// Accessibility & Interactions.
properties: [
'pointer-events',
'-ms-touch-action',
'touch-action',
'cursor',
'visibility',
'zoom',
'table-layout',
'empty-cells',
'caption-side',
'border-spacing',
'border-collapse',
'content',
'quotes',
'counter-reset',
'counter-increment',
'resize',
'user-select',
'nav-index',
'nav-up',
'nav-right',
'nav-down',
'nav-left',
],
},
{
// Background & Borders.
properties: [
'background',
'background-color',
'background-image',
"-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient",
'filter:progid:DXImageTransform.Microsoft.gradient',
'filter:progid:DXImageTransform.Microsoft.AlphaImageLoader',
'filter',
'background-repeat',
'background-attachment',
'background-position',
'background-position-x',
'background-position-y',
'background-clip',
'background-origin',
'background-size',
'background-blend-mode',
'isolation',
'border',
'border-color',
'border-style',
'border-width',
'border-top',
'border-top-color',
'border-top-style',
'border-top-width',
'border-right',
'border-right-color',
'border-right-style',
'border-right-width',
'border-bottom',
'border-bottom-color',
'border-bottom-style',
'border-bottom-width',
'border-left',
'border-left-color',
'border-left-style',
'border-left-width',
'border-radius',
'border-top-left-radius',
'border-top-right-radius',
'border-bottom-right-radius',
'border-bottom-left-radius',
'border-image',
'border-image-source',
'border-image-slice',
'border-image-width',
'border-image-outset',
'border-image-repeat',
'outline',
'outline-width',
'outline-style',
'outline-color',
'outline-offset',
'box-shadow',
'mix-blend-mode',
'filter:progid:DXImageTransform.Microsoft.Alpha(Opacity',
"-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
'opacity',
'-ms-interpolation-mode',
],
},
{
// SVG Presentation Attributes.
properties: [
'alignment-baseline',
'baseline-shift',
'dominant-baseline',
'text-anchor',
'word-spacing',
'writing-mode', 'fill',
'fill-opacity',
'fill-rule',
'stroke',
'stroke-dasharray',
'stroke-dashoffset',
'stroke-linecap',
'stroke-linejoin',
'stroke-miterlimit',
'stroke-opacity',
'stroke-width', 'color-interpolation',
'color-interpolation-filters',
'color-profile',
'color-rendering',
'flood-color',
'flood-opacity',
'image-rendering',
'lighting-color',
'marker-start',
'marker-mid',
'marker-end',
'mask',
'shape-rendering',
'stop-color',
'stop-opacity',
],
},
{
// Transitions & Animation.
properties: [
'transition',
'transition-delay',
'transition-timing-function',
'transition-duration',
'transition-property',
'transform',
'transform-origin',
'animation',
'animation-name',
'animation-duration',
'animation-play-state',
'animation-timing-function',
'animation-delay',
'animation-iteration-count',
'animation-direction',
],
},
],
},
};

编译时自动修复

// ...
const { defineConfig } = require('@vue/cli-service');
const StylelintPlugin = require('stylelint-webpack-plugin'); module.exports = defineConfig({
// ...
configureWebpack: {
plugins: [
// ...
new StylelintPlugin({
files: ['src/**/*.vue'],
// 编译时自动修复
fix: true,
// 这样配才能修复vue文件style片段中的less语法
customSyntax: 'postcss-html',
}),
],
},
});

安装VSCode stylelint扩展

在.vscode/settings.json中配置保存代码时自动修复样式错误

{
"editor.codeActionsOnSave": {
// ...
"source.fixAll.stylelint": true
},
// 关闭vscode自带的css,less,scss报错提示
"css.validate": false,
"less.validate": false,
"scss.validate": false,
"stylelint.validate": ["css", "less"]
}

9 配置yapi-to-typescript

typescript面世以来,经历了一个从厌烦到喜欢的过程,厌恶的是要在原来开发的基础上,多做一些繁杂数据类型定义的工作,喜欢的是确实帮助开发者发现了许多语法错误,享受到接口和传参的便利提示, 综合起来,还是利大于弊,所以 越来越多的开发者开始加入ts大家庭。yapi-to-typescript这个工具,可以帮我们省去接口数据类型定义的工作量。让我们更愉快的与ts玩耍。

安装依赖

yarn add -D yapi-to-typescript

创建ytt.config.ts配置文件

import { defineConfig } from 'yapi-to-typescript';

/**
* 生成Api接口名称 Interface和ChangeCase数据类型参见node_modules\yapi-to-typescript\lib\esm\index.d.ts定义
* @param interfaceInfo : Interface
* @param changeCase:ChangeCase
* @returns 请求响应接口名称--pascal命名
*/
function genApiInterfaceName(interfaceInfo, changeCase) {
// 取解析路径dir最尾部的路径作为前缀路径
const lastPath = interfaceInfo.parsedPath.dir.split('/').pop();
// 拼接前缀路径+文件名称
return `${changeCase.pascalCase(lastPath)}${changeCase.pascalCase(interfaceInfo.parsedPath.name)}`;
} export default defineConfig([
{
serverUrl: 'https://yapi.xxx.com',
typesOnly: true,
target: 'typescript',
reactHooks: {
enabled: false,
},
prodEnvName: '项目名称',
// 将生成文件路径转化成小驼峰命名方式
outputFilePath: (interfaceInfo, changeCase) => {
// 文件夹名称取api-url路径末尾2个
const filePathArr = interfaceInfo.path.split('/').slice(-2);
const filePath = filePathArr.map((item) => changeCase.camelCase(item)).join('/');
return `typings/httpTypes/${filePath}.ts`;
},
// 生成ts文件中请求参数interface名称,将下划线命名转换成pascal命名
getRequestDataTypeName: (interfaceInfo, changeCase) => {
return `${genApiInterfaceName(interfaceInfo, changeCase)}Request`;
},
// 生成ts文件中请求响应数据interface名称,将下划线命名转换成pascal命名
getResponseDataTypeName: (interfaceInfo, changeCase) => {
return `${genApiInterfaceName(interfaceInfo, changeCase)}Response`;
},
// 响应数据中要生成ts数据类型的键名
dataKey: 'retdata',
projects: [
{
// token获取方式: 在yapi-设置-token配置中查看
token: 'xxx',
// 分类id查找方式: 点击接口左侧的分类菜单,查看url地址栏最后面的数字获取
// 分类id配置特别重要,配置错了无法生成对应的ts数据类型定义文件
categories: [
{
id: [xxx], // 民生立减金API分类id
},
],
},
],
},
]);

3.在package.json中配置ytt指令

{
// ...
"scripts": {
"start": "ytt && vue-cli-service serve --mode local",
"build": "ytt && vue-cli-service build --mode local",
"ytt": "ytt",
},
}

4.在.gitignore中添加对httpTypes下文件的忽略

# ...
/typings/httpTypes/*
# ...

10 配置commitlint

commit message 是程序员开发的日常高频操作,自然状态下commit message 呈现五花八门的书写风格,不利于阅读和维护,规范的 commit message 有助于团队做 code review, 输出清晰明了的 CHANGELOG, 有利于项目的长期维护。

安装依赖包

yarn add -D husky conventional-changelog-cli @commitlint/{cli,config-conventional}

创建提交校验配置文件commitlint.config.js

/**
* git commit最佳实践
* 1.经常commit,One Thing,One Commit
* 2.commit之前测试,不要commit一半工作;
* 3.编写规范的commit message
*/ /**
* Commit message 包括三个部分:Header,Body 和 Footer
* <type>(<scope>): <subject>
* 空一行
* <body>
* 空一行
* <footer>
*/
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
// Header包括三个字段:type(必需)、scope(可选)和subject(必需)。最多200字
'header-max-length': [2, 'always', 200],
// 提交类型<type>枚举
'type-enum': [
2,
'always',
[
'init', // 项目初始化
'clean', // 清理过时无用文件
'merge', // 合并代码
'style', // 修改样式文件(包括css/less/sass,图片,字体文件)
'format', // 格式化,不影响代码含义的修改,比如空格、格式缩进、缺失的分号等
'build', // 改变构建流程、或者增加依赖库、工具等 如webpack.config.js,package.json yarn.lock
'chore', // 各种配置文件的修改, 如.gitignore,tsconfig.json,.vscode,.tenone, eslint/stylelint,envConfig
'ci', // 对CI配置文件或脚本进行了修改
'docs', // 修改项目说明文档
'feat', // 新增功能
'fix', // 修复bug
'perf', // 性能优化
'refactor', // 既不是修复bug也不是添加功能的代码重构
'revert', // 版本回退
'test', // 修改测试用例
],
],
// 格式-可选值
// 'lower-case' 小写 lowercase
// 'upper-case' 大写 UPPERCASE
// 'camel-case' 小驼峰 camelCase
// 'kebab-case' 短横线 kebab-case
// 'pascal-case' 大驼峰 PascalCase
// 'sentence-case' 首字母大写 Sentence case
// 'snake-case' 下划线 snake_case
// 'start-case' 所有首字母大写 start-case
// <type> 不能为空
'type-empty': [2, 'never'],
// <type> 格式 小写
'type-case': [2, 'always', 'lower-case'],
// <scope> 关闭改动范围不能为空规则
'scope-empty': [0, 'never'],
// <scope> 格式 小写
'scope-case': [2, 'always', 'lower-case'],
// <subject> 不能为空
'subject-empty': [2, 'never'],
// <subject> 关闭 以.为结束标志
'subject-full-stop': [0, 'never', '.'],
// <subject> 格式
'subject-case': [2, 'never', []],
// <body> 以空行开头
'body-leading-blank': [1, 'always'],
// <footer> 以空行开头
'footer-leading-blank': [1, 'always'],
},
};

3. 创建提交校验shell脚本 husky.sh和commit-msg

yarn husky install

在.husky文件夹下创建commit-msg文件

npx husky add .husky/commit-msg

在.husky/commit-msg文件中写入

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
# 提交记录检查
yarn commitlint --edit $1
# 代码重复率检测
yarn jscpd
# 格式化检查
yarn format:check
# eslint检查
yarn lint:check

11 配置代码重复率检测工具jscpd

代码的简洁之道有一条铁律是 Don't Repeat Yourself,那么如何快速地检测出项目出是否存在着大段的重复代码,靠人工检查显然不可取,这种重复体力活应该交给工具。

检测前端代码重复率的工具有jsinspectjscpdPMD-CPD(PMD's Copy/Paste Detector)

  • jsinspect工具支持js和jsx格式的文件,基于抽象语法树,可以检测出结构类似的代码块
  • PMD-CPD工具支持js文件检测,也可以自己开发扩展包来解析指定的语言
  • jscpd工具支持文件格式广泛,如js、jsx、vue、ts、less,java、oc等。其重复率判定依据为一定长度标识符的MD5值是否相同

每个工具各有其优缺点,若只需要检测js或jsx文件,且对检测结果要求较高,可以选择jsinspect或者PMD-CPD工具,若考虑检测工具的通用性,可以选择jscpd工具。

安装:
npm install -g jscpd
用法:
jscpd  src/*
在项目下创建.jscpd.json配置文件
{ 
// 重复率阈值
"threshold": 0.1,
// 报告输出格式
"reporters": [
"html",
"console"
],
"ignore": [
"dist/**",
"node_modules/**"
],
// 文件路径使用相对路径
"absolute": false
}
 --min-tokens  -k:代码的最小块大小。小于的代码块min-tokens将被跳过,默认为50;
 --min-lines  -l:最小代码行数,默认为5;
 --max-lines  -x: 最大代码行数,默认为1000;
 --max-size  -z:最大文件大小,单位为kb,默认100;
 --threshold  -t:重复级别的阈值,当项目重复级别大于该阈值时报错退出,默认为空;
 --ignore  -i:忽略的文件类型;
 --reporters  -r:输出类型

参考文献

你在寻找Vue3移动端项目框架嘛?请看这里的更多相关文章

  1. APP开发选择什么框架好? 请看这里!

    背景 App的开发一般都需要满足Android和iOS两个系统环境,也就意味着一个App需要定制两套实现方案,造成开发成本和维护成本都很高.为了解决这个问题,最好的办法就是实现一套代码跨端运行,所以H ...

  2. 动端逐渐出了许多的移动端的框架,比如Sencha Touch、JQTouch、Jquery-moblie、jqMobi等等。这些框架都有优缺点,不同的框架应用在不同的项目中。现简单阐述一下各框架的优缺点:

    移动前端工作的那些事---前端制作之微信小技巧篇   (2013-11-15 15:20) 转载▼ 标签: it css3/javascript html5 webapp 手机网站搭建 分类: 前端制 ...

  3. next.js、nuxt.js等服务端渲染框架构建的项目部署到服务器,并用PM2守护程序

    前端渲染:vue.react等单页面项目应该这样子部署到服务器 貌似从前几年,前后端分离逐渐就开始流行起来,把一些渲染计算的工作抛向前端以便减轻服务端的压力,但为啥现在又开始流行在服务端渲染了呢?如v ...

  4. 从零开始搭建Electron+Vue+Webpack项目框架,一套代码,同时构建客户端、web端(一)

    摘要:随着前端技术的飞速发展,越来越多的技术领域开始被前端工程师踏足.从NodeJs问世至今,各种前端工具脚手架.服务端框架层出不穷,“全栈工程师”对于前端开发者来说,再也不只是说说而已.在NodeJ ...

  5. 【原创】从零开始搭建Electron+Vue+Webpack项目框架(六)Electron打包,同时构建客户端和web端

    导航: (一)Electron跑起来(二)从零搭建Vue全家桶+webpack项目框架(三)Electron+Vue+Webpack,联合调试整个项目(四)Electron配置润色(五)预加载及自动更 ...

  6. day97:MoFang:移动端APP开发准备&移动端项目搭建&APICloud前端框架

    目录 1.移动端开发相关概念 1.APP类型 2.移动端屏幕介绍 3.移动端自适配方案 4.元信息(meta) 2.APP开发准备 1.注册APPCLoud账号 2.下载APP开发编辑器 3.下载AP ...

  7. 【原创】从零开始搭建Electron+Vue+Webpack项目框架,一套代码,同时构建客户端、web端(二)

    摘要:上篇文章说到了如何新建工程,并启动一个最简单的Electron应用.“跑起来”了Electron,那就接着把Vue“跑起来”吧.有一点需要说明的是,webpack是贯穿这个系列始终的,我也是本着 ...

  8. 用 Vue 改造 Bootstrap,渐进提升项目框架[转]

    GitChat 作者:Meathill 原文:用 Vue 改造 Bootstrap,渐进提升项目框架 关注微信公众号:「GitChat 技术杂谈」 一本正经的讲技术 [不要错过文末彩蛋] 前言 Vue ...

  9. 基于 vite 创建 vue3 全家桶项目(vite + vue3 + tsx + pinia)

    vite 最近非常火,它是 vue 作者尤大神发布前端构建工具,底层基于 Rollup,无论是启动速度还是热加载速度都非常快.vite 随 vue3 正式版一起发布,刚开始的时候与 vue 绑定在一起 ...

随机推荐

  1. 解决git push报错error: failed to push some refs to 的问题

    这个问题发生的背景一般是: 想把自己本地的某个项目关联到远程仓库并推送上去,接着他会做如下操作: 本地项目->远程创建仓库->本地关联远程->推送最新代码 最后一个步骤发生问题: 那 ...

  2. pipeline 共享库

    目录 一.简介 二.共享库扩展 共享库使用 共享库结构 pipeline模板 一些小问题 三.共享库例子 使用公共变量 使用共享库的src方法 使用共享库的vars方法 四.插件实现pipeline ...

  3. 【论文笔记】Recommendations as Treatments: Debiasing Learning and Evaluation

    Recommendations as Treatments: Debiasing Learning and Evaluation Authors: Tobias Schnabel, Adith Swa ...

  4. [BUUCTF]REVERSE——helloword

    helloword 题目是安卓逆向.安卓逆向工具下载地址 用APKIDE打开附件,ctf+f调出检索版,检索main函数,能看到flag字符串 flag{7631a988259a00816deda84 ...

  5. PDF补丁丁将发布开放源代码的1.0版本

    近况 一个月前的今天,母亲永远离开了我. 想起四个月前,我送她了去住院.入院后,做了检查.检查结果没出,我的生日就到了.母亲很关心我的生日.在电话里,她祝我身体健康,又问媳妇有没有给我做生日餐桌的菜肴 ...

  6. CF1265B Beautiful Numbers 题解

    Content 给定一个 \(1\sim n\) 的排列,请求出对于 \(1\leqslant m\leqslant n\),是否存在一个区间满足这个区间是一个 \(1\sim m\) 的排列. 数据 ...

  7. CF1077A Frog Jumping 题解

    Content 在一个数轴上有一个动点,初始时在 \(0\) 这个位置上,接下来有若干次操作,对于第 \(i\) 次操作: 如果 \(i\) 是奇数,那么动点往右移 \(a\) 个单位. 如果 \(i ...

  8. java 图形化小工具Abstract Window Toolit

      老掉牙的历史 Java1.0在发布的时候,就为我们提供了GUI操作的库,这个库系统在所有的平台下都可以运行,这套基本的类库被称作抽象窗口工具集(Abstract Window Toolit),简称 ...

  9. Stun协议实现

    在现实Internet网络环境中,大多数计算机主机都位于防火墙或NAT之后,只有少部分主机能够直接接入Internet.很多时候,我们希望网络中的两台主机能够直接进行通信(即所谓的P2P通信),而不需 ...

  10. 通过css实现表格的斜线

    效果图 实现思路 编辑一个svg文件,可以自定义线条颜色和粗细. 将svg文件转为base64格式,作为背景图属性设置. svg转base64的网址:https://www.sojson.com/im ...