現在web開發變得更加美妙高效,在於開發工具設計得更好了,豐富性與易用性,都有所提高。豐富性帶來了一個幸福的煩惱,就是針對實際應用場景,如何選擇工具 ?
1. Vue Cli和Vite之間的選擇
Vite的開發環境體驗好,基於瀏覽器原生ES6 Modules提供的功能,不對ES高版本語法進行轉譯,省略掉耗時的打包流程, 可是考慮到:
1) 項目要用到真機調試功能,開發環境下調試代碼時不能使用ES高版本的語法,用着不順暢。
后面發現可用@vitejs/plugin-legacy解決此問題。
import legacy from '@vitejs/plugin-legacy';
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項目的腳手架。若是新項目,個人還是比較推薦使用Vite,構建速度確實快。
安裝最新版本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發現文件中有許多紅色的告警波浪線,安裝Volar擴展,,絕大多數語法報錯消失。順便說一下為什么要使用Volar擴展,Vetur對<script setup>里面定義的響應式變量支持度不夠好。
<script setup> // ... // 僅用於template,未在script中被使用,會報 count is declared but its value is never read.Vetur(6133) const count = ref(1) //... </script>

3 配置vue文件保存時自動格式化
代碼美化功能,是一個重要的影響開發體驗的指標。書寫潦草的代碼,按下Ctrl+S保存之后,瞬間變成整潔有序, 這種視覺感受,讓人神清氣爽。
在項目下新建.vscode/settings.json,內容如下:
{ // ... "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "[vue]": { "editor.defaultFormatter": "johnsoncodehk.volar" }, "[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,那么如何快速地檢測出項目出是否存在着大段的重復代碼,靠人工檢查顯然不可取,這種重復體力活應該交給工具。
檢測前端代碼重復率的工具有jsinspect、jscpd,PMD-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/*
{
// 重復率閾值 "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:輸出類型 |
參考文獻
