前端工程化概述
什麼是工程化
定義
- 工程化即系統化、模組化、規範化的一個過程。
- 如果說電腦科學要解決的是系統的某個具體問題,或者更通俗點說是面向編碼的,那麼工程化要解決的是如何提高整個系統生產效率。
- 與其說軟體工程是一門科學,不如說它更偏向於管理學和方法論。
解決什麼問題
- 工程化解決的問題是,如何提高編碼、測試、維護階段的生產效率。
什麼是前端
維基百科
前端Front-end和後端back-end是描述程式開始和結束的通用詞彙。
前端作用於採集輸入資訊,後端進行處理。計算機程式的介面樣式,視覺呈現屬於前端。
百度百科
前端對於網站來說,通常是指,網站的前臺部分包括網站的表現層和結構層。
因此前端技術一般分為前端設計和前端開發,前端設計一般可以理解為網站的視覺設計,
前端開發則是網站的前臺程式碼實現,包括基本的HTML和CSS以及JavaScript/ajax,現在最新的高階版本HTML5、CSS3,以及SVG等。
前端發展史
1. 簡單明快的早期時代
適合小專案,不分前後端,頁面由JSP、PHP等在服務端生成,瀏覽器負責展現。
2. 後端為主的 MVC 時代
為了降低複雜度,以後端為出發點,有了Web Server層的架構升級,比如Structs、Spring MVC等。
前兩個階段存在的問題
- 前端開發重度依賴開發環境。
- 前後端職責依舊糾纏不清,可維護性越來越差。
3. Ajax 帶來的 SPA 時代
2005年Ajax正式提出,前端開發進入SPA(Single Page Application 單頁面應用)時代。
Ajax時代面臨的挑戰
- 前後端介面的約定。
- 前端開發的複雜度控制。SPA應用大多以功能互動型為主,大量 JS 程式碼的組織,與 View 層的繫結等,都不是容易的事情。
4. 前端為主的 MVC、MV* 時代
為了降低前端開發複雜度,Backbone、EmberJS、KnockoutJS、AngularJS、React、Vue等大量前端框架湧現。
5. Node 帶來的全棧時代
隨著Node.js的興起,為前端開發帶來一種新的開發模式。
業界比較出名的實踐是,阿里巴巴的中途島計劃。
後兩個步驟帶來的好處
- 前後端職責很清晰。
- 前端開發的複雜度可控,通過合理的分層,讓專案更可維護。
- 部署相對獨立,產品體驗可以快速改進。
前端工程化要解決什麼
1. 制定各項規範,讓工作有章可循
統一團隊成員的編碼規範,便於團隊協作和程式碼維護
- 目錄結構,檔案命名規範
- 編碼規範:eslint, stylelint
開發流程的規範
- 使用敏捷,增強開發進度管理和控制
- 應對各項風險,需求變更等
- code review 機制
- UAT 提升釋出的需求的質量
- 前後端介面規範,其他文件規範
2. 使用版本控制工具,高效安全的管理原始碼
- 使用 git 版本控制工具
- Git分支管理
- Commit描述規範,例如:task-number + task 描述
- 建立 merge request,code review 完畢之後方可合併程式碼
3. 使用合適的前端技術和框架,提高生產效率,降低維護難度
目標: 職責分離、降低耦合,增強程式碼的可讀性、維護性和測試性。
採用模組化的方式組織程式碼
- JS 模組化:AMD、CommonJS、UMD、ES6 Module
- CSS 模組化:less、sass、stylus、postCSS、css module
採用元件化的程式設計思想,處理 UI 層
- react、vue、angular
將資料層分離管理
- redux、mbox
- 使用物件導向或者函式程式設計的方式組織架構
4. 提高程式碼的可測試性,引入單元測試,提高程式碼質量
5. 通過使用各種自動化的工程工具,提升整個開發、部署效率
JavaScript 對模組化的現實需要
- js設計之初,主要用於處理簡單的頁面效果和邏輯驗證之類的簡單工作。
- 被過於隨意的設計,缺乏模組化一直是其缺陷之一。
- 隨著單頁應用與富客戶端的流行,不斷增長的程式碼庫也急需合理的程式碼分割與依賴管理的解決方案,這就是我們在軟體工程領域所熟悉的模組化。
- 模組化主要解決的問題:解決程式碼分割、增強維護性、提高程式碼重用、作用域隔離、模組之間的依賴管理、釋出的自動化打包與處理等多個方面。
主要的模組化方案
- 直接宣告依賴(Directly Defined Dependences)
- 名稱空間(Namespace Pattern)
- 模組模式(Module Pattern)
- 依賴分離定義(Detached Dependency Definitions)
- 沙盒(Sandbox)
- 依賴注入(Dependency Injection)
- 標籤化模組(Labeled Modules)
- CommonJS、AMD、UMD、ES 2015 Modules
1. 直接宣告依賴
除了備註描述,什麼問題都沒解決
// file app.js
var helloInLang = {
en: 'Hello world!'
};
// file hello.js
/* helloInLang defined in app.js */
function writeHello(lang) {
document.write(helloInLang[lang]);
};複製程式碼
2. 名稱空間
名稱空間模式始於2002年,使用特殊的約定命名,用於避免命名衝突和全域性作用域汙染。
缺點:大型專案可維護性較差,沒有解決模組間依賴管理的問題。
// file app.js
var app = {};
// file greeting.js
app.helloInLang = {
en: 'Hello world!'
};
// file hello.js
app.writeHello = function (lang) {
document.write(app.helloInLang[lang]);
};複製程式碼
3. 模組模型
封裝了變數和function,和全域性的namaspace不接觸,鬆耦合
只暴露可用public的方法,其它私有方法全部隱藏
// file app.js
var app = {};
// file greeting.js
app = (function (app) {
var _app = app || {};
_app.helloInLang = {
en: 'Hello world!'
};
return _app;
} (app));
// file hello.js
app = (function (app) {
var _app = app || {};
_app.writeHello = function (lang) {
document.write(app.helloInLang[lang]);
};
return _app;
} (app));複製程式碼
4. 依賴注入
2009年 Angular 引入 Java 世界的依賴注入思想。
核心思想:某個模組不需要手動初始化某個依賴物件,只需要宣告該依賴,並由外部框架自動例項化該物件,並傳遞到模組內。
// file greeting.js
angular.module('greeter', [])
.value('greeting', {
helloInLang: {
en: 'Hello world!'
},
ayHello: function(lang) {
return this.helloInLang[lang];
}
});
// file app.js
angular.module('app', ['greeter'])
.controller('GreetingController', ['$scope', 'greeting', function($scope, greeting) {
$scope.phrase = greeting.sayHello('en');
}]);複製程式碼
5. CommonJS
伺服器端 javascript 模組化解決方案,適用於同步模組載入。
// file greeting.js
var helloInLang = {
en: 'Hello world!'
};
var sayHello = function (lang) {
return helloInLang[lang];
}
module.exports.sayHello = sayHello;
// file hello.js
var sayHello = require('./lib/greeting').sayHello;
var phrase = sayHello('en');
console.log(phrase);複製程式碼
6. AMD
瀏覽器端 javascript 模組化解決方案,適用於非同步模組載入。
// file lib/greeting.js
define(function() {
var helloInLang = {
en: 'Hello world!'
};
return {
sayHello: function (lang) {
return helloInLang[lang];
}
};
});
// file hello.js
define(['./lib/greeting'], function(greeting) {
var phrase = greeting.sayHello('en');
document.write(phrase);
});複製程式碼
7. UMD
UMD 允許在環境中同時使用 AMD 與 CommonJS 規範。
(function(define) {
define(function () {
var helloInLang = {
en: 'Hello world!'
};
return {
sayHello: function (lang) {
return helloInLang[lang];
}
};
});
}(
typeof module === 'object' && module.exports && typeof define !== 'function' ?
function (factory) { module.exports = factory(); } :
define
));複製程式碼
8. ES2015 Modules
ES2015 Modules 作為 JavaScript 官方標準,日漸成為了開發者的主流選擇。
// file lib/greeting.js
const helloInLang = {
en: 'Hello world!'
};
export const greeting = {
sayHello: function (lang) {
return helloInLang[lang];
}
};
// file hello.js
import { greeting } from "./lib/greeting";
const phrase = greeting.sayHello("en");
document.write(phrase);複製程式碼
增強可測試性
採用tdd的程式設計思想,引入單元測試
- karma + mocha + chai、jest、ava
使用各種除錯工具
- web devtools、finddle
自動化工程工具的使用
使用前端構建工具
- gulp、grunt、Broccoli
javascript 編譯工具
- Babel、Browserify、Webpack
開發輔助工具
- 資料 mock、livereload
使用CI整合工具
- jenkins、Travis CI
使用腳手架工具
- yeoman、create-app
客如雲前端工程化實踐
統一公司前端技術棧,根據職責建立不同專案。
- kryfe-boilerplate 腳手架專案
- kryfe-tools 通用工具庫
- kryfe-lib 通用類庫
- kryfe-component 公共元件庫
- eslint-config-kryfe eslint規範
- stylelint-config-kryfe stylelint規範
- kryfe-docs 各種規範文件
- kryfe-style PC端樣式庫