前端開發規範 從制定到實施

SmallW發表於2019-04-28

在我們開始這個題目的時候,我們應該思考下面幾個問題:

  1. 前端開發為什麼需要 開發規範?
  2. 前端開發規範是什麼?
  3. 什麼時候需要這個規範?
  4. 如何制定這個規範?
  5. 如何落實這個規範?

[TOC]

一、前端開發為什麼需要 開發規範?

why?

前端還在 刀耕火種的時代的時候,前端是沒有 工程 這個概念的。更多是切圖仔這個概念,(將設計師設計出來的 web 、app、h5 的 UI 通過 PS 切圖 然後再通過 HTML、CSS 實現出來)的這麼一個工種。那麼隨著 網際網路興起到後來的移動網際網路發展,To C 產品需求 精細化, 使用者對於 C 端產品越來越挑剔也促使著 前端工程化越來越規範化了。 漸漸的前端工程形成,那麼隨之而來的就是 工程化 帶來的 規範化

回到 why 的問題上來,我們先舉一個簡單的例子來說,

可能 工程化 這個名詞在很多的後端語言中早早的就已經形成了,但前端 這麼一門到現在大學課程都沒開課的工種,全靠大學畢業後工作中自學積累而來,那麼我們是否可以說,現階段前端搞的好的人,Ta 的自學能力一定不會差。

二、前端開發規範是什麼?

what?

什麼是前端開發規範?

HTML\CSS\Javascript\TypeScript 的程式碼編寫規範,這裡我們著重講一下 JS 的 編碼規範

1、Types

javascript 的資料型別

1.1 基本資料型別

  • string
  • number
  • boolean
  • null
  • undefined
  • symbol
const foo = 1;
let bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9
複製程式碼

1.2 引用資料型別

  • object
  • array
  • function
const foo = [1, 2];
const bar = foo;

bar[0] = 9;

console.log(foo[0], bar[0]); // => 9, 9
複製程式碼

以上則 是 基礎資料 在 coding 的時候的基本規範。

2、References

變數、常量、定義規範

  • 2.1 eslint: prefer-const, no-const-assign
// bad
var a = 1;
var b = 2;

// good
const a = 1;
const b = 2;
複製程式碼
建議使用 const 定義常量,可以阻止一些 重複定義導致的 bug
複製程式碼
  • 2.2 eslint: no-var
// bad
var count = 1;
if (true) {
  count += 1;
}

// good, use the let.
let count = 1;
if (true) {
  count += 1;
}
複製程式碼
推薦使用 let 來定義變數,形成塊級作用域,減少因為變數提升導致的bug
複製程式碼

3、Objects

物件 定義規範

  • 3.1 eslint: no-new-object
// bad
const item = new Object();

// good
const item = {};
複製程式碼
推薦使用 物件字面量來定義空物件,而不是通過 new 例項化進行操作
複製程式碼
  • 3.2 動態屬性名 使用 計算屬性
// bad
const obj = {
  id: 5,
  name: 'San Francisco',
};
obj[getKey('enabled')] = true;

// good
const obj = {
  id: 5,
  name: 'San Francisco',
  [getKey('enabled')]: true,
};
複製程式碼
  • 3.3 eslint: object-shorthand
// bad
const atom = {
  value: 1,

  addValue: function (value) {
    return atom.value + value;
  },
};

// good
const atom = {
  value: 1,

  addValue(value) {
    return atom.value + value;
  },
};
複製程式碼
推薦 在給物件新增方法的時候,使用 簡化符號
複製程式碼
  • 3.4 eslint: object-shorthand
const lukeSkywalker = 'Luke Skywalker';

// bad
const obj = {
  lukeSkywalker: lukeSkywalker,
};

// good
const obj = {
  lukeSkywalker,
};
複製程式碼
方法名如果和物件的屬性名稱相同的時候,推薦使用簡化符號編寫
複製程式碼
  • 3.5 在使用 object-shorthand 的時候,推薦先寫出簡化符號的屬性或者方法
const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';

// bad
const obj = {
  episodeOne: 1,
  lukeSkywalker,
  anakinSkywalker,
};

// good
const obj = {
  lukeSkywalker,
  anakinSkywalker,
  episodeOne: 1,
};
複製程式碼
  • 3.6 eslint: quote-props: as-needed
// bad
const bad = {
  'foo': 3,
  'bar': 4,
  'data-blah': 5,
};

// good
const good = {
  foo: 3,
  bar: 4,
  'data-blah': 5,
};
複製程式碼
推薦在 給物件屬性不要輕易加引號,除非必要的情況下,比如屬性的key帶有 符號等
複製程式碼
  • 3.7 eslint: no-prototype-builtins 不使用 prototype 的內建命令
// bad
console.log(object.hasOwnProperty(key));

// good
console.log(Object.prototype.hasOwnProperty.call(object, key));

// best
const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
/* or */
import has from 'has'; // https://www.npmjs.com/package/has
// ...
console.log(has.call(object, key));
複製程式碼
推薦理由是:這些方法可能被有關物件上的屬性所遮蔽
複製程式碼
  • 3.8 物件擴充套件符 比使用 Object.assign
// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
delete copy.a; // so does this

// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }

// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }

const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
複製程式碼
推薦原因就是, 物件擴充套件符 比 Object.assign 看著舒服10倍吧
複製程式碼

4、Arrays

  • 4.1 eslint: no-array-constructor
/*推薦使用通過字面量建立物件、陣列*/
// bad
const items = new Array();
// good
const items = [];
複製程式碼
  • 4.2 Use Array#push
/*推薦使用 push 來進行 stack add */
// bad
someArr[someArr.length] = 'xxxxsssswwww'
// good
someArr.push('xxxxsssswwww')
複製程式碼
  • 4.3 Use array spreads ... to copy arrays
/*推薦使用 `...` 進行陣列 複製 */
// bad
for(i=0; i<arr.length; i++) { newArr[i] = arr[i] }
// good
let newArr = [...arr]
複製程式碼
  • 4.4 use spreads ... instead of Array.from
/*推薦使用 `...` 將可迭代物件轉換為陣列 */
// bad
const foo = document.querySelectorAll('.foo'); nodes = Array.from(foo)	// array[]
// good
let nodes = [...foo]
複製程式碼
  • 4.5 Use Array.from for converting an array-like object to an array
/*推薦使用 `Array.from` 將 array-like[類陣列] 轉換為物件 */
const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 };
// bad
const arr = Array.prototype.slice.call(arrLike);
// good
const arr = Array.from(arrLike);
複製程式碼
  • 4.6 Use Array.from instead of spread ... for mapping over iterables
/*推薦使用 `Array.from` 實現可迭代陣列方法而不是通過 ... */
// bad
const baz = [...foo].map(bar);
// good
const baz = Array.from(foo, fn);
複製程式碼
  • 4.7 eslint: array-callback-return
/*推薦使用 `Array.from` 實現可迭代陣列方法而不是通過 ... */
// good
[1, 2, 3].map(x => x + 1);
// 優化寫法、程式碼簡潔易懂
複製程式碼
  • 4.8 Use line breaks after open and before close array brackets
/* 陣列換行格式 優化 */
// bad
const arr = [
  [0, 1], [2, 3], [4, 5],
];

// good
const arr = [[0, 1], [2, 3], [4, 5]];
複製程式碼

5、Destructuring - 解構

  • 5.1 eslint: prefer-destructuring 物件結構
/* 物件結構 帶來的更加簡潔的程式碼 */
// bad
function getFullName(user) {
  const firstName = user.firstName;
  const lastName = user.lastName;

  return `${firstName} ${lastName}`;
}
// good
function getFullName(user) {
  const { firstName, lastName } = user;
  return `${firstName} ${lastName}`;
}
複製程式碼
  • 5.2 eslint: prefer-destructuring 函式引數結構
// bad
function getFullName(user) {
  const firstName = user.firstName;
  const lastName = user.lastName;

  return `${firstName} ${lastName}`;
}

// best
function getFullName({ firstName, lastName }) {
  return `${firstName} ${lastName}`;
}
複製程式碼
  • 5.3 eslint: prefer-destructuring 陣列結構
const arr = [1, 2, 3, 4];

// bad
const first = arr[0];
const second = arr[1];

// good
const [first, second] = arr;
複製程式碼

6、 String

...

7、 function

...

8、Classes & Constructors

這裡的核心就是減少建構函式的使用、多使用 通過 class 來進行 類的建立、constructor、extends 實現繼承、建構函式等 原始的方法。
複製程式碼
// bad
function Queue(contents = []) {
  this.queue = [...contents];
}
Queue.prototype.pop = function () {
  const value = this.queue[0];
  this.queue.splice(0, 1);
  return value;
};

// good
class Queue {
  constructor(contents = []) {
    this.queue = [...contents];
  }
  pop() {
    const value = this.queue[0];
    this.queue.splice(0, 1);
    return value;
  }
}
複製程式碼

9、Modules

模組化的 匯入、匯出。
複製程式碼
// bad
const AirbnbStyleGuide = require('./AirbnbStyleGuide');
module.exports = AirbnbStyleGuide.es6;

// ok
import AirbnbStyleGuide from './AirbnbStyleGuide';
export default AirbnbStyleGuide.es6;

// best
import { es6 } from './AirbnbStyleGuide';
export default es6;
複製程式碼

10、space

...

由於篇幅有限,這裡就不做過多的描述了,詳情可以檢視 Airbnb eslint 規則

三、什麼時候需要這個規範?

我覺得任何時候都需要這個規範!!!

無論是一個人,還是 前端小組,甚至全公司的 大前端開發團隊 都是需要的!!!

四、如何制定這個規範?

如何定製這個規範

1、CODE 程式碼層面實現

藉助ESLint的autofix功能,在儲存程式碼的時候,自動將丟擲error的地方進行fix。因為我們專案是在webpack中引入eslint-loader來啟動eslint的,所以我們只要稍微修改webpack的配置,就能在啟動webpack-dev-server的時候,每次儲存程式碼同時自動對程式碼進行格式化。


// webpack.config.base.js  or webpack.config.dev.js

const path = require('path')
module.exports = {
  module: {
    rules: [
      {
        test: /\.(js|vue|jsx)$/,
        loader: 'eslint-loader',
        enforce: 'pre',
        include: [path.join(__dirname, 'src')],
        options: {
          fix: true
        }
      }
    ]
}
複製程式碼

2、lint lint 規則層面:

秉承著 一個原則, 漸進式 規則完善,從最基本的 規範到 逐步 健全的規範落實,結合 code review 逐漸完善。

五、如何落實這個規範?

對了,關鍵點就是 如何落實這個規範!!!
複製程式碼

1、IDE 的選擇

前端IDE開發的選擇,從大學階段的 DW(Adobe Dreamweaver)、Notepad++ 等等,再到後面的 SublimeWebstorm 再到後面的 AtomVisual Studio Code (VScode)

IDE 不斷的變化過程中也給了我們 更加高效程式設計的選擇

2、IDE 的 本地設定檔案 setting.json

在 vscode 中的設定中配置(新舊不同版本的 vscode setting.json 的展現形式是不一樣的)
複製程式碼

前端開發規範 從制定到實施

但是這個 格式化 往往只是最最進本的格式化,在前端如此多的 語言中很顯然是不夠用的,下面,我們就主要介紹下 `Prettier`
複製程式碼

3、Prettier - Code formatter 格式化外掛的使用

在 vscode 的應用商店進行 搜尋(Prettier - Code formatter )下載安裝 

在專案的根目錄建立 Prettier 的配置檔案 `.prettierrc`

Prettier 格式化的配置檔案文件地址: https://prettier.io/docs/en/options.html

基本的配置檔案格式如下:
複製程式碼
{
  "singleQuote": true,
  "trailingComma": "es5",
  "printWidth": 140,
  "semi": true,
  "bracketSpacing": true,
  "overrides": [
    {
      "files": ".prettierrc",
      "options": { "parser": "json" }
    }
  ]
}
複製程式碼

那麼,我們來看下 Prettier 做了哪些事情

前端開發規範 從制定到實施

前端開發規範 從制定到實施

能支援jsx

前端開發規範 從制定到實施

也能支援css

前端開發規範 從制定到實施

4、ESLint 與 Prettier配合使用

首先肯定是需要安裝prettier,並且你的專案中已經使用了ESLint,有eslintrc.js配置檔案。

4.1 配合ESLint檢測程式碼風格

eslint-plugin-prettier外掛會呼叫prettier對你的程式碼風格進行檢查,其原理是先使用prettier對你的程式碼進行格式化,然後與格式化之前的程式碼進行對比,如果過出現了不一致,這個地方就會被prettier進行標記。

//.eslintrc
{
  "plugins": ["prettier"],
  "rules": {
    "prettier/prettier": "error"
  }
}
複製程式碼

這樣就 可以通過 eslint 來 extend prettier 的規範,最後結合 webpack 的 module 中 對於 js、vue、jsx 檔案的 loader 處理,來實現 實時的 lint 。

5、專案架構中 應該具備的 配置檔案

那麼 迴歸到最後,我們去架構這個專案的時候,從 前端編碼規範層面去考慮的話,我們的專案 最少需要的幾個 配置檔案是這樣子的:
複製程式碼
5.1 、webpack.config.js

webpack 是 構建根本,結合各類外掛使用

5.2 、prettierrc

結合 vscode 終極格式化 我們的程式碼,一鍵化操作帶你飛~

5.3 、eslintrc

eslint 結合 各類 eslint 的規則。 進行 強/弱 型別提示 (0、1、2)

5.4 、babelrc
{
  "presets": ["es2015", "stage-1", "react"],
  "plugins": ["transform-runtime", "transform-decorators-legacy"],
  "env": {}
}
複製程式碼

結合 babel 的各類 loader 進行 ES 的語法預編譯處理,這裡由於時間關係就不仔細去闡述了。

六 、總結

一套好的規範,可以解決不想遇到的意外的bug、可以規範自己的編碼習慣、可以讓 code Review 更加簡單。
好處多多,有待不斷摸索,前期自然回遇到一些困難,但結果是值得期待的~
複製程式碼

GitHub 地址:(歡迎 star 、歡迎推薦 : )

前端開發規範 從制定到實施

相關文章