一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

前端實(shí)用程序包utils - 開發(fā)工作流(一)

 nullPlus 2023-02-03 發(fā)布于浙江

寫在前面

在開始之前,我們先思考下,創(chuàng)建一個(gè)規(guī)范的項(xiàng)目我們需要關(guān)注哪些點(diǎn)?我覺得吧,第一個(gè)是創(chuàng)建信息的完整性,一個(gè)信息完整的項(xiàng)目可以引導(dǎo)讀者與作者交流與合作,這個(gè)在后面的package.json里面向大家介紹;第二個(gè)是代碼的規(guī)范性和兼容性,正所謂,沒有規(guī)矩不成方圓,良好的代碼規(guī)范會(huì)巧妙地杜絕屎上雕花的行為發(fā)生,這個(gè)后面跟大家介紹下eslint+prettier+babal的知識(shí)點(diǎn);第三個(gè)項(xiàng)目目錄的規(guī)范性,這個(gè)也會(huì)在后面介紹?;谇懊嫒c(diǎn),我們可以做出一個(gè)自產(chǎn)自銷的項(xiàng)目,如果把這個(gè)過程比作拉翔,那它會(huì)很通暢,拉的很舒服,不會(huì)便秘。但是遠(yuǎn)遠(yuǎn)不夠,就比如程序員A拿到程序員B寫的項(xiàng)目,那么程序員B怎么去證明給A看,我的槍好使且我的話可信。這就引入了后面兩個(gè)話題,第四點(diǎn)就是把你的作品發(fā)出去讓別人能看得到,《何以笙簫默》中有句臺(tái)詞,“如果我們走散你找不到我,那我就站在最高的舞臺(tái)中央讓你看見我?!蹦型麄兟牰藛??你想要脫單,一個(gè)不成熟的建議,站在舞臺(tái)中央,發(fā)出滋滋滋的求偶聲,跳出Michael Jackson妖嬈的舞步,just beat it,just beat it.喜歡你的說不定就有了,主動(dòng)一點(diǎn)就會(huì)有故事。這個(gè)后面筆者介紹下git工作流以及npm的發(fā)包;第五點(diǎn)就是測(cè)試,提高可信度。這里我會(huì)結(jié)合karmamocha、chaitraviscodecov來向大家介紹單元測(cè)試、持續(xù)集成、代碼覆蓋率測(cè)試。最后的話,我會(huì)結(jié)合相關(guān)的開發(fā)工具做一個(gè)簡(jiǎn)單的搭配使用介紹吧。好的,我們開始吧。


項(xiàng)目創(chuàng)建

注意: 因?yàn)楣P者目前前端接觸的比較多,所以這個(gè)庫(kù)的定義就是給前端環(huán)境用的,不是很推薦用在nodejs開發(fā)上使用,因?yàn)槠浜竺嫔婕暗搅艘恍〥OM之類的操作是對(duì)nodjs沒什么卵用的,所以采用ES Module的語法來書寫,若想在node環(huán)境使用,請(qǐng)配合babel,webpack等工具使用,請(qǐng)確保電腦上安裝了nodejs環(huán)境。

舉個(gè)例子,比如我要?jiǎng)?chuàng)建一個(gè)項(xiàng)目叫utils,可以怎么做?(考慮到0基礎(chǔ)的同學(xué),我會(huì)講的比較細(xì),老司機(jī)請(qǐng)直接跳過這章節(jié))

如果你只是想玩玩,不想一步一步去配置,那么你只需要執(zhí)行mkdir utils && npm init -y, 這句話的意思是說創(chuàng)建了一個(gè)文件夾叫utils,然后初始化一個(gè)npm管理的項(xiàng)目,-y表示yes,也就是都選是。這個(gè)時(shí)候它就會(huì)在項(xiàng)目文件夾下創(chuàng)建一個(gè)粗糙的package.json文件。

新手我還是建議你一步一個(gè)腳印走一遍,執(zhí)行mkdir utils && npm init,它會(huì)一步一步讓你確認(rèn)該項(xiàng)目的相關(guān)描述啊,協(xié)議啊,聯(lián)系方式啊,項(xiàng)目地址啥的,這里筆者貼出一份該項(xiàng)目的npm配置。

配置說明:

  • name: 項(xiàng)目名
  • version: 項(xiàng)目版本號(hào)
  • description: 項(xiàng)目描述
  • main: 項(xiàng)目主入口文件
  • scripts: 項(xiàng)目執(zhí)行npm命令
  • repository: 項(xiàng)目倉(cāng)庫(kù)
  • keywords: 項(xiàng)目關(guān)鍵詞
  • author: 項(xiàng)目作者
  • license: 授權(quán)協(xié)議
  • bugs: bug反饋
  • homepages: 項(xiàng)目主頁
  • devDependencies: 開發(fā)環(huán)境依賴,不會(huì)隨項(xiàng)目打包, 使用npm i @ataola/utils -D安裝
  • dependencies: 開發(fā)環(huán)境依賴,會(huì)隨著項(xiàng)目打包,使用npm i @ataola/utils -S 安裝
  • husky: 在本地提交之前,做一次lint反饋,這個(gè)需要安裝相關(guān)npm包再配置
  • lint-staged: 只會(huì)校驗(yàn)提交修改的部分,這個(gè)也是需要安裝相關(guān)npm包再配置,建議你和樓上那位一起用
{
  "name""@ataola/utils",
  "version""0.1.5",
  "description""ataola's utils: maybe publish a feature one week, to record something i think or meet.",
  "main""index.js",
  "scripts": {
    "push""./push",
    "pull""./pull",
    "codecov""codecov",
    "eslint""eslint . --ext .js --fix",
    "husky:prepare""husky install",
    "husky:add""husky add .husky/pre-commit 'npm run lint'",
    "git:add""git add -A",
    "lint""lint-staged",
    "karma:init""karma init ./karma.conf.js",
    "karma:test""karma start ./karma.conf.js",
    "format""prettier --write '**/*.{js,jsx,ts,tsx,json,md}'"
  },
  "repository": {
    "type""git",
    "url""git+https://github.com/ataola/utils.git"
  },
  "keywords": [
    "javascript",
    "utils"
  ],
  "author""ataola (zjt613@gmail.com)",
  "license""MIT",
  "bugs": {
    "url""https://github.com/ataola/utils/issues"
  },
  "homepage""https://github.com/ataola/utils#readme",
  "devDependencies": {
    "@babel/core""^7.13.15",
    "@babel/eslint-parser""^7.13.14",
    "@babel/plugin-proposal-class-properties""^7.13.0",
    "@babel/plugin-transform-arrow-functions""^7.13.0",
    "@babel/plugin-transform-async-to-generator""^7.13.0",
    "@babel/plugin-transform-runtime""^7.13.15",
    "@babel/polyfill""^7.12.1",
    "@babel/preset-env""^7.13.15",
    "@babel/runtime""^7.13.10",
    "babel-eslint""^10.1.0",
    "babel-loader""^8.2.2",
    "babel-plugin-istanbul""^6.0.0",
    "chai""^4.3.4",
    "codecov""^3.8.1",
    "core-js""^3.11.0",
    "eslint""^7.24.0",
    "eslint-config-prettier""^8.1.0",
    "eslint-plugin-prettier""^3.3.1",
    "husky""^6.0.0",
    "karma""^6.3.2",
    "karma-chai""^0.1.0",
    "karma-chrome-launcher""^3.1.0",
    "karma-coverage""^2.0.3",
    "karma-mocha""^2.0.1",
    "karma-mocha-reporter""^2.2.5",
    "karma-webpack""^5.0.0",
    "lint-staged""^10.5.4",
    "mocha""^8.3.2",
    "prettier""^2.2.1",
    "webpack""^5.31.2"
  },
  "husky": {
    "hooks": {
      "pre-commit""lint-staged"
    }
  },
  "lint-staged": {
    "*.{js,ts,jsx,tsx}": [
      "eslint . --fix",
      "prettier --config .prettierrc --write ."
    ]
  }
}

查詢npm的相關(guān)命令是npm --help, 比如我不知道npm init后面可以跟什么,那么執(zhí)行npm init --help就可以羅列出相關(guān)信息。

?  ~ npm init --help

npm init [--force|-f|--yes|-y|--scope]
npm init <@scope> (same as `npx <@scope>/create`)
npm init [<@scope>/]<name> (same as `npx [<@scope>/]create-<name>`)

aliases: create, innit
?  ~

如果你發(fā)現(xiàn)npm install很慢,多半是長(zhǎng)城的問題,建議你改成國(guó)內(nèi)的淘寶源npm install --registry=https://registry.npm., 如果發(fā)現(xiàn)也還是不好使,終極解決方案: 科X學(xué)X上X網(wǎng),逃~。

代碼規(guī)范

努力做好六件事:

  • 不同編輯器下的代碼規(guī)范
  • eslint作語法規(guī)范
  • prettier作格式規(guī)范
  • 做好代碼兼容性處理
  • 手動(dòng)擋控制單文件格式化
  • 提交代碼前確認(rèn)所修改文件或者整個(gè)項(xiàng)目代碼規(guī)范

EditorConfig

這個(gè)對(duì)應(yīng)我們上面努力做好的第一件事 - 不同編輯器下的代碼規(guī)范。在現(xiàn)實(shí)多人開發(fā)中,由于開發(fā)者的行為習(xí)慣不同可以會(huì)導(dǎo)致代碼的風(fēng)格有所不同,有些人喜歡用vscode,有些人喜歡用webstorm,也許他們用的編輯器是一樣的,但是由于開發(fā)者在全局配置了一些設(shè)置,會(huì)導(dǎo)致整個(gè)項(xiàng)目代碼不符合預(yù)期,所以,我們需要一個(gè)在編輯器層面去協(xié)調(diào)各個(gè)編輯器環(huán)境下的代碼風(fēng)格,EditorConfig是一個(gè)不錯(cuò)的選擇,這個(gè)是本項(xiàng)目用到的關(guān)于EditorConfig的一些配置。

配置說明:

  • root=true: 表示是最頂層的配置文件,發(fā)現(xiàn)設(shè)為true時(shí),才會(huì)停止查找.editorconfig文件

When opening a file, EditorConfig plugins look for a file named .editorconfig in the directory of the opened file and in every parent directory. A search for .editorconfig files will stop if the root filepath is reached or an EditorConfig file with root=true is found.

EditorConfig files are read top to bottom and the most recent rules found take precedence. Properties from matching EditorConfig sections are applied in the order they were read, so properties in closer files take precedence.

原文地址:https://github.com/editorconfig/editorconfig/issues/376

  • [*]: 表示所有文件
  • end_of_line = lf 注意這個(gè)不是if,而是lf, 表示換行符,它有lf、crlfcr等等,跟系統(tǒng)關(guān)系比較大,反正大家都統(tǒng)一一下用lf,可以看下這個(gè)有名的故事-GitHub 第一坑:換行符自動(dòng)轉(zhuǎn)換
  • insert_final_newline = true: 表示在末尾插入新行
  • [*.{js,py}]: 表示js和python文件
  • charset = utf-8: 表示字符集為utf-8
  • indent_style = space: 表示代碼鎖進(jìn)格式用空格
  • indent_size = 2: 表示一個(gè)縮進(jìn)大小兩個(gè)空格
  • quote_type = single: 字符串設(shè)置為單引號(hào)
  • trim_trailing_whitespace = true: 表示是否在行尾修剪空白
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

# top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true

# Denotes whether to trim whitespace at the end of lines
trim_trailing_whitespace = true

# Matches multiple files with brace expansion notation
[*.{js}]
charset = utf-8
quote_type = single
indent_style = space
indent_size = 2

[{package.json,.travis.yml}]
indent_style = space
indent_size = 2

額,我覺得學(xué)這部分是有捷徑的,就是去嫖名項(xiàng)目它們的配置,然后把它們搞懂再應(yīng)用到自己或者團(tuán)隊(duì)的項(xiàng)目中。比如JQuery, Bootstrap的,跟對(duì)項(xiàng)目,做對(duì)事可以少走很多彎路的。

ESLint

這個(gè)對(duì)應(yīng)第二件事 -eslint作語法規(guī)范。eslint用來做一些js語法規(guī)范,避免一些語法上的錯(cuò)誤,當(dāng)然也可以做格式上的規(guī)范。這個(gè)是本項(xiàng)目用到的關(guān)于eslint的一些配置。

配置說明:

  • extends:  繼承,表示它繼承了某些配置, 比如eslint:recommended表示繼承了其推薦的配置,可以繼承多個(gè)的,用數(shù)組表示

  • plugins: 表示安裝的插件, 寫配置的時(shí)候可以省略前面的前綴eslint-plugin-

  • parserOptions: 表示解析選項(xiàng)

    • ecmaVersion: 表示es語法的版本, 默認(rèn)為 3, 5。2015表示es6, 后面可自推
    • sourceType: 默認(rèn)是scirpt,如果是ES模塊用module
    • ecmaFeatures: 表示額外的語言特性
  • parser: 解析器,比如babel-eslint, 表示一個(gè)對(duì)Babel解析器的包裝,使其能夠與 ESLint 兼容

  • rules: 表示 啟用的規(guī)則及其各自的錯(cuò)誤級(jí)別, 0, 1,2分別對(duì)應(yīng)off, warn, error

    • no-console: 表示禁止調(diào)用console對(duì)象的方法
    • func-names: 禁止命名的 function 表達(dá)式
    • no-unused-vars: 表示禁止未使用的變量
    • object-shorthand: 要求變量自變量簡(jiǎn)寫
    • prettier/prettier: 表示eslint下prettier的規(guī)則兼容
    • arrow-body-style: 要求箭頭函數(shù)使用大括號(hào)
    • prefer-arrow-callback: 要求使用箭頭函數(shù)作為回調(diào)
    • camelcase: 使用駝峰拼寫法
    • space-before-function-paren: 禁止函數(shù)圓括號(hào)之前有空格
  • env: 指定腳本的運(yùn)行環(huán)境,比如在其里面寫"es6": true, 表示自動(dòng)啟動(dòng)es6語法, "browser": true表示支持瀏覽器環(huán)境

{
  "extends": ["prettier""plugin:prettier/recommended"],
  "plugins": ["prettier"],
  "parserOptions": {
    "ecmaVersion"2015,
    "sourceType""module",
    "ecmaFeatures": {
      "jsx"true,
      "globalReturn"true,
      "impliedStrict"true
    }
  },
  "parser""babel-eslint",
  "rules": {
    "no-console""off",
    "func-names""off",
    "no-unused-vars""warn",
    "object-shorthand""off",
    "prettier/prettier": [
      "error",
      {
        "endOfLine""auto",
        "singleQuote"true,
        "trailingComma""es5"
      }
    ],
    "arrow-body-style""off",
    "prefer-arrow-callback""off",
    "camelcase""off",
    "no-new""off",
    "space-before-function-paren""off"
  },
  "env": {
    "es6"true,
    "browser"true
  }
}

Prettier

這個(gè)對(duì)應(yīng)第三件事 - prettier作代碼的格式規(guī)范, 這個(gè)是本項(xiàng)目關(guān)于prettier的配置

配置說明:

  • semi: 句尾添加分號(hào)
  • tabWidth: 縮進(jìn)字節(jié)數(shù)
  • singleQuote: 使用單引號(hào)代替雙引號(hào)
  • endOfLine: 結(jié)尾是 \n \r \n\r auto
  • trailingComma : 在對(duì)象或數(shù)組最后一個(gè)元素后面是否加逗號(hào)
  • bracketSpacing:在對(duì)象,數(shù)組括號(hào)與文字之間加空格 "{ foo: bar }"
  • alwaysParens:(x) => {} 箭頭函數(shù)參數(shù)只有一個(gè)時(shí)是否要有小括號(hào)。avoid:省略括號(hào)
  • eslintIntegration: 不讓prettier使用eslint的代碼格式進(jìn)行校驗(yàn)
  • jsxSingleQuote: 在jsx中使用單引號(hào)代替雙引號(hào)
{
  "semi"true,
  "tabWidth"2,
  "singleQuote"true,
  "endOfLine""lf",
  "trailingComma""es5",
  "bracketSpacing"true,
  "alwaysParens""always",
  "eslintIntegration"true,
  "jsxSingleQuote"true
}

看到這里,我們先停一停思考下,這么多配置,它們會(huì)不會(huì)產(chǎn)生沖突呢?那我要怎么去避免沖突,或者解決沖突呢?其實(shí)樓上已經(jīng)提到了用eslintIntegration不讓prettier使用eslint的代碼風(fēng)格校驗(yàn)。然后在之前的eslint學(xué)習(xí)中,也可以通過在rule下新增規(guī)則作為補(bǔ)充。

babel

這個(gè)對(duì)應(yīng)第四件事 -做好代碼兼容性處理。babel是一個(gè)Javascript編譯器,可以將高版本的es語法,轉(zhuǎn)換成低版本的,以便能夠運(yùn)行在低版本瀏覽器或者其他環(huán)境,樓下是這個(gè)項(xiàng)目的babel的配置文件

配置說明:

  • presets: 預(yù)設(shè),進(jìn)行相關(guān)語法轉(zhuǎn)義
  • plugins:插件,補(bǔ)丁轉(zhuǎn)義器,彌補(bǔ)樓上先天不足
  • env:環(huán)境變量
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "browsers": [">0.25%""not ie 11""not op_mini all"]
        },
        "exclude": [
          "@babel/plugin-transform-async-to-generator",
          "@babel/plugin-transform-arrow-functions"
        ],
        "corejs": { "version""3.8""proposals"true },
        "useBuiltIns""usage"
      }
    ]
  ],
  "plugins": [
    "@babel/transform-runtime",
    "@babel/plugin-proposal-class-properties"
  ],
  "env": {
    "test": {
      "plugins": ["istanbul"]
    }
  }
}

可以看下我之前寫的關(guān)于babel的一篇文章- Babel:下一代Javascript語法編譯器

一般來講有其配置文件,也會(huì)有其配置忽略文件, 比如``.prettierrc.prettierignore`, 其它的讀者自行觸類旁通,然后配置的文件格式也有很多種,比如說json文件,js文件,rc結(jié)尾的文件等等, 這里純粹是個(gè)人習(xí)慣, 筆者一般是用 .xxxrc

手動(dòng)擋控制單文件格式化

這里筆者以手動(dòng)擋開頭,我覺得非常應(yīng)景和帶感。與之對(duì)應(yīng)的便是自動(dòng)擋智能格式化。舉個(gè)例子吧,比如你選擇邊打邊格式化,未免也太浪費(fèi)資源了,而且可能它格式化的會(huì)和你當(dāng)時(shí)的想法有沖突。所以每次按下CTRL + S進(jìn)行格式化的話,是一個(gè)很好的方案。它就好比開車,停車的話,掛空擋,拉手剎,下車干飯,是一氣呵成的,那個(gè)CTRL + S就好比駕駛員手握的掛擋器,帶感。什么?剎車失靈?不存在的,阿Sir?。。?/p>

來看一下效果:

vscode-code-format

提交代碼前確認(rèn)所修改文件或者整個(gè)項(xiàng)目代碼規(guī)范

前面我們提到的是我們?cè)谄綍r(shí)開發(fā)中,對(duì)于單個(gè)文件的代碼規(guī)范手段,那么對(duì)于整個(gè)項(xiàng)目,我們應(yīng)該在每次提交前再去檢查確認(rèn)一遍,這樣子我們提交到遠(yuǎn)程的代碼才有保障。細(xì)心的同學(xué)可能已經(jīng)發(fā)現(xiàn)了,是的,在文章開頭講到的package.json中可以配置huskylint-staged去做這件事。husky做提交前的檢查, 而lint-staged則優(yōu)化了檢查的范圍是要提交檢查的,從而加快速度提高效率。

由于husky和lint-staged的版本不同配置也不同,這里筆者用的是最新的配置,具體的參考了這位國(guó)際友人的文章https:///sprout2000/items/29e8a637dda259bab26d

我這里的話, 就是在每次提交的時(shí)候?qū)s、ts等文件進(jìn)行eslint和prettier格式化,配置如下:

 "husky": {
    "hooks": {
      "pre-commit""lint-staged"
    }
  },
  "lint-staged": {
    "*.{js,ts,jsx,tsx}": [
      "eslint . --fix",
    ]
  }

來看一下效果:

husky-lint-staged

這里為了讓大家更明顯直觀看到效果,筆者沒有加prettier格式化那一句在lint-staged里面,后續(xù)加上后,關(guān)于格式的問題會(huì)被自動(dòng)修復(fù), 如下

 "husky": {
    "hooks": {
      "pre-commit""lint-staged"
    }
  },
  "lint-staged": {
    "*.{js,ts,jsx,tsx}": [
      "eslint . --fix",
      "prettier --config .prettierrc --write ."
    ]
  }

效果如下

root@ccb5f768c839:/home/coder/utils# git commit -m "test husky and lint-staged"

> @ataola/utils@0.1.5 lint-staged
> lint-staged

? Preparing...
? Running tasks...
? Applying modifications...
? Cleaning up...
[main 0e5f4d3] sadasd
 1 file changed, 2 insertions(+), 1 deletion(-)
root@ccb5f768c839:/home/coder/utils

項(xiàng)目目錄

目錄說明:

  • LICENSE:  授權(quán)文件

  • README.md : 說明文件

  • coverage : 代碼覆蓋率文件夾

  • docs:  文檔文件夾

  • img:  圖片文件夾

  • index.js:  入口文件

  • log: 日志文件夾

  • node_modules :  安裝的npm依賴文件夾

  • package-lock.json:  npm的配置文件鎖

  • package.json:  npm的配置文件

  • pull:  拉取遠(yuǎn)程github倉(cāng)庫(kù)的腳本

  • push:  上傳遠(yuǎn)程github倉(cāng)庫(kù)以及npm發(fā)包的腳本

  • test: 單元測(cè)試文件夾

?  utils git:(main) tree -L 1
.
├── LICENSE
├── README.md
├── coverage
├── docs
├── img
├── index.js
├── karma.conf.js
├── lib
├── logs
├── node_modules
├── package-lock.json
├── package.json
├── pull
├── push
└── test

7 directories, 8 files
?  utils git:(main)

項(xiàng)目命名規(guī)范建議:

  • 應(yīng)該使其文件或文件名命名具有語意,不會(huì)你就翻字典

    • 推薦 城市 city
    • 鄙視 城市 chengshi
    • 嚴(yán)重鄙視 城市 cs
  • 要么用命名縮寫,要么用全名,建議全名用復(fù)數(shù)形式

    因?yàn)閕mg是image的縮寫,你再加個(gè)s就沒有啥語意了,而全名的images表示圖片,這里可能有讀者會(huì)鉆牛角尖,你那個(gè)docs不是和樓上沖突了嗎?不是的, doc英文單詞是文檔,docs是其復(fù)數(shù)形式, 這要和document區(qū)分開。

    • 推薦縮寫 img
    • 不推薦縮寫 imgs
    • 推薦全寫 images
    • 不推薦全寫 image

我們可以通過tree命令去查看項(xiàng)目文件結(jié)構(gòu),-L表示深度層數(shù), mac用戶可以通過brew install tree安裝,ubuntu用戶可以通過apt-get install tree -y安裝,centos用戶可以通過yum install tree -y安裝,window用戶請(qǐng)下載相關(guān)tree包并配置到path環(huán)境變量里去, 或者去搜下window下的包管理命令`

git工作流和npm

努力做兩件事:

  • 用腳本偷懶代替一行一行的敲命令,或者IDE點(diǎn)點(diǎn)點(diǎn)
  • 把雞蛋放在墻內(nèi)和墻外兩個(gè)籃子里

腳本一把梭,梭,梭哈

我們先思考下,在git工作流中,有這樣三個(gè)概念, 萌萌噠的我, 遠(yuǎn)程倉(cāng)庫(kù),本地倉(cāng)庫(kù)。那,以這三個(gè)概念造句子,可以這么玩。萌萌噠的我爽朗地把本地倉(cāng)庫(kù)推向了遠(yuǎn)程倉(cāng)庫(kù),遠(yuǎn)程倉(cāng)庫(kù)被萌萌噠的我瀟灑地拉到了本地倉(cāng)庫(kù)。是的,這個(gè)在生活中有很形象的例子,還是萌萌噠的我饑饞碌碌地推開肯德基的大門去干飯,半個(gè)小時(shí)過去了,滿懷滋潤(rùn)的我拉開了肯德基的大門揚(yáng)長(zhǎng)而去。綜上所述,我們大致可以概括出兩個(gè)行為,推(push)和拉(pull),好上腳本。

push

#!/usr/bin/env bash

set -e

function git_branch_name() {
    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/'
}

function e() {
    echo "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓"
    printf "┃$(tput bold) %-40s $(tput sgr0)┃\n" "$*"
    echo "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛"
    "$@"
}

CURRENT_BRANCH=$(git_branch_name)

if [[ $CURRENT_BRANCH = feature/* ]]; then
  e git stash
  e git checkout main
  e git pull
  e git checkout "$CURRENT_BRANCH"
  e git merge main
  e git push
  e git stash pop || true
elif [[ $CURRENT_BRANCH = main ]]; then
  e git stash
  e git push
  e nrm use npm
  e npm publish --access public
  e nrm use taobao
  e git stash pop || true
fi

在push這個(gè)行為上,我們需要考慮兩點(diǎn)。第一,遠(yuǎn)程代碼有更新嗎?跟我本地會(huì)有沖突嗎?第二,我當(dāng)前是在哪個(gè)分支,我代碼才剛寫到一半,我不想提交這么辦?git stash就是將你當(dāng)前的代碼改動(dòng)存入暫緩區(qū),使得其恢復(fù)上一次提交的狀態(tài),這個(gè)時(shí)候你從遠(yuǎn)程拉下來代碼,再去merge下,然后你執(zhí)行git stash pop,git checkout是切換分支。

上面代碼的意思是,如果我是在某個(gè)特性分支,那么就先把我目前的改動(dòng)存入暫緩區(qū),然后切到主分支main,去拉取遠(yuǎn)程代碼,然后切回我當(dāng)前的分支,再去對(duì)主分支進(jìn)行merge,然后執(zhí)行push,最后再把我的改動(dòng)從暫緩區(qū)拿出來,然后就可以繼續(xù)開發(fā)了。如果我當(dāng)前是主分支,那太開心了,先把當(dāng)前改動(dòng)存入暫緩區(qū),然后直接push,再來個(gè)npm發(fā)包,然后把當(dāng)前改動(dòng)彈出來。

pull

#!/usr/bin/env bash

set -e


function git_branch_name() {
    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/'
}

function e() {
    echo "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓"
    printf "┃$(tput bold) %-40s $(tput sgr0)┃\n" "$*"
    echo "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛"
    "$@"
}

CURRENT_BRANCH=$(git_branch_name)

if [[ $CURRENT_BRANCH = feature/* ]]; then
  e git stash
  e git checkout main
  e git pull
  e git checkout "$CURRENT_BRANCH"
  e git merge main
  e git stash pop || true
elif [[ $CURRENT_BRANCH = main ]]; then
  e git stash
  e git pull
  e git stash pop || true
fi

這個(gè)pull和上面的push類似的,就不贅述了,讀者照著樓上的push去理解下pull吧。

多個(gè)remote的真香定律

為什么會(huì)有這個(gè)想法呢?由于不可描述的原因,墻對(duì)于天朝開發(fā)者來說始終是一個(gè)神秘的存在,當(dāng)我們?cè)谑褂肎itHub的時(shí)候,有時(shí)會(huì)遇到DNS污染,有時(shí)可能是墻的問題,總之就是提交也很難提交上去,拉也拉不下來。特別是在自己的云服務(wù)器上去拉GitHub上的代碼,等的花兒都謝了,算了放棄吧,先走為敬。這個(gè)時(shí)候碼云是個(gè)神奇的存在,用它拉取代碼速度是相當(dāng)?shù)目?,于是我蠢蠢欲?dòng)地加了一個(gè)碼云的remote,直接提交到碼云了,這樣子一個(gè)好處是,我本地就起一份代碼就好了,用不著同一個(gè)項(xiàng)目搞兩份代碼。嗯,remote真香?。?!

下面是我添加碼云的remote地址,然后把它上傳到碼云的步驟:

git remote add gitee https:///taoge2021/utils.git
git fetch gitee
git checkout -b gitee-main gitee/main
git merge main
git push gitee main

npm

這個(gè)其實(shí)在樓上代碼已經(jīng)有所體現(xiàn)了,這里簡(jiǎn)單講下就是,你先去https://www./去注冊(cè)一個(gè)賬號(hào),然后本地npm login去登陸這個(gè)賬號(hào),如果你想發(fā)布一個(gè)形如@ataola/utils的包,那么執(zhí)行npm publish --access public, 如果你不想的話npm publish就可以了。

注意:發(fā)包的時(shí)候不要切到淘寶源,是在npm源上提交,可以通過 npm config set registry作轉(zhuǎn)化, 也可以用nrm這個(gè)包作源的管理

測(cè)試、持續(xù)集成和代碼覆蓋率

努力做三件事:

  • 單元測(cè)試
  • 持續(xù)集成測(cè)試
  • 代碼覆蓋率測(cè)試

karma + mocha + chai

做測(cè)試的技術(shù)選型搭配其實(shí)有很多,我這里用到樓上這三位。是這樣子的,因?yàn)槲疫@個(gè)庫(kù)定義是給前端用的,后續(xù)會(huì)涉及到一些DOM,BOM等等的相關(guān)測(cè)試,我期望它是真的開了個(gè)瀏覽器去測(cè)試我的代碼。而Karma這個(gè)測(cè)試運(yùn)行器它可以做到這點(diǎn),而且它還是開源的。mocha是比較有名的測(cè)試框架,后面的chai是用來作斷言的。

karam的配置創(chuàng)建可以看下package.json里面我配置的script腳本

 "karma:init""karma init ./karma.conf.js",
 "karma:test""karma start ./karma.conf.js",

npm run karma:init表示創(chuàng)建一個(gè)karma的配置文件,而npm run karma:test表示啟動(dòng)karma相關(guān)測(cè)試。

附上一份karma.conf.js, 由于配置較多,這里如果默認(rèn)生成的話,大部分都不需要你動(dòng),就挑幾個(gè)講下,具體的還是要去看官方文檔的http://karma-runner./6.3/config/configuration-file.html

  • framework: 表示你裝的一些框架
  • plugins: 故名思義,裝的插件
  • files: 表示要加載瀏覽器的文件
  • preprocessors: 一些預(yù)處理操作
  • browsers: 可提供的瀏覽器
  • webpack: 暴露的webpack配置接口
  • mochaReporter:暴露的mocha配置接口
// Karma configuration
// Generated on Sat Apr 10 2021 00:13:46 GMT+0800 (中國(guó)標(biāo)準(zhǔn)時(shí)間)

module.exports = function (config{
  config.set({
    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath'',

    // frameworks to use
    // available frameworks: https:///browse/keyword/karma-adapter
    frameworks: ['mocha''chai''webpack'],
    plugins: [
      'karma-chrome-launcher',
      'karma-mocha',
      'karma-mocha-reporter',
      'karma-chai',
      'karma-webpack',
      'karma-coverage',
    ],

    // list of files / patterns to load in the browser
    // test all
    files: ['lib/**/*.js''test/**/*.js'],
    // test single file
    // files: ['test/**/judge.test.js'],

    // list of files / patterns to exclude
    exclude: [],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https:///browse/keyword/karma-preprocessor
    // test all
    preprocessors: {
      'lib/**/*.js': ['webpack''coverage'],
      'test/**/*.js': ['webpack'],
    },
    // test single file
    // preprocessors: {
    //   'test/**/judge.test.js': ['webpack'],
    // },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https:///browse/keyword/karma-reporter
    reporters: ['progress'],
    // https://github.com/litixsoft/karma-mocha-reporter
    reporters: ['mocha''coverage'],
    mochaReporter: {
      colors: {
        success'blue',
        info'bgGreen',
        warning'cyan',
        error'bgRed',
      },
      symbols: {
        success'+',
        info'#',
        warning'!',
        error'x',
      },
      output'autowatch',
      showDifftrue,
      divider'',
    },
    coverageReporter: {
      dir'coverage/',
      reporters: [
        { type'lcov'subdir'.' },
        { type'text'subdir'.'file'text.txt' },
        { type'text-summary'subdir'.'file'text-summary.txt' },
      ],
    },

    // web server port
    port9876,

    // enable / disable colors in the output (reporters and logs)
    colorstrue,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatchtrue,

    // start these browsers
    // available browser launchers: https:///browse/keyword/karma-launcher
    browsers: ['Chrome''ChromeHeadless''ChromeHeadlessNoSandbox'],

    // you can define custom flags
    customLaunchers: {
      ChromeHeadlessNoSandbox: {
        base'ChromeHeadless',
        flags: ['--no-sandbox'],
      },
    },

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: !!process.env.CI,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrencyInfinity,
    webpack: {
      mode'development',
      //       entry: ['@babel/polyfill'],
      //       entry: ['./index.js'],
      module: {
        rules: [
          {
            test/\.js$/,
            exclude/node_modules/,
            use: {
              loader'babel-loader',
              options: {
                presets: [
                  [
                    '@babel/preset-env',
                    {
                      corejs: { version'3.8'proposalstrue },
                      useBuiltIns'usage',
                    },
                  ],
                ],
                plugins: ['istanbul'],
              },
            },
          },
        ],
      },
    },
  });
};

這里如果我是寫Node的話,我會(huì)用jest,因?yàn)榕渲脮?huì)簡(jiǎn)單些。具體的讀者可以閱讀下我之前寫的文章使用jest進(jìn)行單元測(cè)試, 附上一個(gè)完整實(shí)戰(zhàn)的例子,這個(gè)是我刷leetcode做的單元測(cè)試的項(xiàng)目地址,https://github.com/ataola/coding

travis

travis是做持續(xù)集成的,貼一份筆者的配置,需要注意的是,版本的不同可能配置也不太一樣,具體的還是要去看官方文檔https://docs./

language: node_js
node_js: stable

notifications:
  email:
    recipients:
      - zjt613@gmail.com
    on_success: change
    on_failure: always

branches:
  only:
    - main

cache:
  apt: true
  directories:
    - node_modules

os: linux
# https://docs./user/reference/overview/
dist: xenial
addons:
  chrome: stable
services:
  - xvfb
sudo: required

# turn off the clone of submodules for change the SSH to HTTPS in .gitmodules to avoid the error
git:
  submodules: false

before_install:
  - 'export DISPLAY=:99.0'
  - sleep 3 # give xvfb some time to start
  - '/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16'
  - google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &

install:
  - npm set progress=false
  - npm install

script:
  - npm run karma:test

after_script:
  - npm run codecov

codecov

codecov是做代碼覆蓋率測(cè)試的, 執(zhí)行npm install codecov -D去安裝它,然后在packge.json里面配置好script就好了"codecov": "codecov", 我們?cè)谧龀掷m(xù)集成的時(shí)候,最下面在執(zhí)行完相關(guān)karma測(cè)試后,最后會(huì)執(zhí)行npm run codecov去讀取 coverage 目錄中的 lcov.info 文件,然后上傳到 Codecov 網(wǎng)站

測(cè)試這塊做了這么多工作,其實(shí)就是當(dāng)了一回場(chǎng)面人,在倉(cāng)庫(kù)首頁給它一個(gè)特寫,這里加了travis持續(xù)集成的構(gòu)建結(jié)果和codecov的代碼覆蓋率以增加項(xiàng)目的可信度和逼格。

unit test

VSCode 開發(fā)環(huán)境

思考兩件事:

  • 如何配置不同的開發(fā)環(huán)境,區(qū)分開發(fā)環(huán)境的共性和不同,以及其引起的不同(權(quán)衡不同項(xiàng)目利弊)
  • 最小化插件原則,提高電腦運(yùn)行效率,不搞花里胡哨,不裝逼,把電腦當(dāng)朋友

環(huán)境的共性和不同

為什么會(huì)有這個(gè)問題,也還是源自生活中遇到的事。筆者最開始為了一步到位,將相關(guān)的prettier、eslint等等的相關(guān)配置都寫到了全局的,也就是user下面,后來在拉取項(xiàng)目的時(shí)候發(fā)現(xiàn),很多時(shí)候特別是多人開發(fā),由于eslint和prettier的配置不一樣,或者根本就沒有這塊的配置,導(dǎo)致代碼堆積如屎山難以維護(hù),這促使我有了進(jìn)一步的思考是,區(qū)分編輯器的共性和不同。舉個(gè)例子,比如說terminal這個(gè)插件,它其實(shí)可以配置調(diào)節(jié)在終端光標(biāo)的粗細(xì),我就不是很喜歡那種肥肥的光標(biāo),就把它改成line,這種是屬于不同,是你的個(gè)性,不會(huì)因?yàn)檎f你設(shè)置了這個(gè)會(huì)影響到整個(gè)項(xiàng)目,別人電腦里沒設(shè)置還是肥肥的光標(biāo)。那么什么是共性,就比如最開始筆者說的將prettier、eslint配置到全局的做法,違背了共性,這里需要說明的一點(diǎn)是,違背不代表我是錯(cuò)的,在這件事情上沒有對(duì)錯(cuò),大環(huán)境決定的,如果一只隊(duì)伍里大家都認(rèn)為 1 + 1 =3,那么即使你認(rèn)為1 + 1 = 2,從大局上考慮,這里就姑且遷就下1 + 1 = 3吧,你可以沉默不說話,但你心里要有你堅(jiān)定的真理的答案,這個(gè)叫站隊(duì)。

具體的解決方案我認(rèn)為是,你可以在全局里去配置以那種方式去做一件事,但是具體的規(guī)則和形式需要單獨(dú)拎出來,不能寫全局里面??梢孕陆ㄒ粋€(gè).vscode文件夾,然后在這個(gè)項(xiàng)目里面單獨(dú)配置,結(jié)合.prettierrc、.eslintrc等,可以參考下這個(gè)項(xiàng)目https://github.com/ataola/coding

vscode

推薦插件

  • prettier: 代碼格式
  • eslint:語法格式
  • GitLens:git輔助
  • gi t-commit-plugin:規(guī)范git提交信息
  • Terminal:終端工具
  • Vetur:寫vue輔助工具
  • vscode-icons:編輯器主題
  • TODO Highlight 高亮要做的事

筆者以前也是個(gè)使用插件狂魔,總喜歡去試試倒騰這個(gè)插件那個(gè)插件好不好使好不好玩,再后來我那個(gè) 多年前買的window不堪重負(fù)萎靡不振,我就沒有這個(gè)想法了,插件只是個(gè)輔助工具,根據(jù)使用頻繁度和實(shí)用性去考量吧,老羅有句話說得好, 又不是不能用?

又不是不能用

示例講解

關(guān)于處理url參數(shù)轉(zhuǎn)成對(duì)象的格式,這個(gè)是前端開發(fā)面試的??碱},因?yàn)樗鼘?shí)用性強(qiáng),涉及基礎(chǔ)的數(shù)組字符串處理,答案還不唯一,所以這里筆者拋磚引玉,就以它為例子去講吧。

  • getQueryParameters

    如果對(duì)正則不熟悉的話,這里可以用字符串分割分割再分割來做,具體的如下

    /**
     *
     * @param {string} url
     * @returns {object}
     */

    function getQueryParameters(url{
      const paramStr = decodeURIComponent(url).split('?')[1];
      if (!paramStr) {
        return {};
      }
      const paramArr = paramStr.split('&');
      const res = {};
      paramArr.forEach((param) => {
        const [key, value] = param.split('=');
        res[key] = value;
      });
      return res;
    }

    相關(guān)測(cè)試

    import { expect } from 'chai';
    import { getQueryParameters } from '../lib/url';

    describe('lib: url test'function ({
      it('getQueryParameters: expect { name: "ataola", age: "24" } when call function with params "https://?name=ataola&age=24"'function ({
        expect(
          getQueryParameters('https://?name=ataola&age=24')
        ).to.deep.equals({ name'ataola'age'24' });
      });
      });
    });

最后

至此,筆者已經(jīng)向讀者們介紹了一個(gè)前端項(xiàng)目從有想法到去實(shí)踐再到總結(jié)分享的心路歷程。謝謝大家的賞臉閱讀,談起為什么寫這個(gè)項(xiàng)目,第一是項(xiàng)目做多了,自然而然就會(huì)有些想法,明人不說暗話我想偷點(diǎn)懶劃水,想早點(diǎn)下班哇,所以工作之余就勤快點(diǎn)把平時(shí)工作或者刷題常用到的總結(jié)整理下,打磨成一把瑞士軍刀,提高戰(zhàn)斗力;第二是像我們搞程序的,都挺單純的,有句話說得好”no BB, show me the code!“,可能不是很會(huì)表達(dá)自己吧,那就上代碼吧,希望面試官看了能夠加點(diǎn)印象分或者綜合得分,哈哈。

項(xiàng)目地址: https://github.com/ataola/utils

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    日本一区不卡在线观看| 中国一区二区三区人妻 | 国产精品一区二区三区激情| 日韩av亚洲一区二区三区| 亚洲国产一区精品一区二区三区色| 成人国产一区二区三区精品麻豆| 中文字幕人妻日本一区二区| 美女被后入福利在线观看| 中文字幕人妻一区二区免费| 色狠狠一区二区三区香蕉蜜桃| 国产精品夜色一区二区三区不卡| 国产又色又爽又黄又大| 亚洲视频在线观看免费中文字幕| 精品日韩视频在线观看| 精品熟女少妇av免费久久野外| 成人午夜激情在线免费观看| 国产成人午夜福利片片| 黄色美女日本的美女日人| 麻豆精品在线一区二区三区| 国产一区日韩二区欧美| 日韩精品一级一区二区| 久久国产精品亚州精品毛片 | 国产农村妇女成人精品| 国产情侣激情在线对白| 欧美日韩国产综合特黄| 深夜福利亚洲高清性感| 日本高清一区免费不卡| 国产又猛又大又长又粗| 视频一区二区 国产精品| 免费在线成人激情视频| 日韩精品小视频在线观看| 久久国产青偷人人妻潘金莲| 国产成人精品一区在线观看| 日本丰满大奶熟女一区二区| 欧美日韩综合免费视频| 国产精品成人一区二区三区夜夜夜| 欧美国产日本免费不卡| 大香蕉伊人精品在线观看| 欧美国产日本高清在线| 国内外激情免费在线视频| 五月天婷亚洲天婷综合网|