【每日一題NO.80】說說你對前端工程化的理解


目錄:
什么是工程化?
前端,是一種 GUI 軟件
前端工程化需要考慮哪些因素
模塊化
組件化
性能優(yōu)化
規(guī)范化
自動化
典型的前端工作流程分為 5 個步驟
開發(fā)階段
測試階段
構(gòu)建階段
部署階段
監(jiān)控階段
總結(jié)
什么是工程化?
前端工程本質(zhì)上是軟件工程的一種。軟件工程化關注的是性能、穩(wěn)定性、可用性、可維護性等方面,注重基本的開發(fā)效率、運行效率的同時,思考維護效率。一切以這些為目標的工作都是前端工程化。
工程是一種思想而不是某種技術。
舉一個通俗的例子:要蓋一棟大樓,假如我們不進行工程化的考量那就是一上來掂起瓦刀磚塊就開干,直到把大樓壘起來,這樣做往往意味著中間會出現(xiàn)錯誤,要推到重來或蓋好后結(jié)構(gòu)有問題但又不知道出現(xiàn)在哪里誰的責任甚至會在某一天轟然倒塌,那我們?nèi)绻霉こ袒乃枷肴プ龅?/span>話,就會先畫圖紙、確定結(jié)構(gòu)、確定用料和預算以及工期,另外需要用到什么工種多少人等等,我們會先打地基在建框架再填充墻體這樣最后建立起來的高樓才是穩(wěn)固合規(guī)的,什么地方出了問題我們也可以快速找到源頭和負責人。
前端,是一種 GUI 軟件
我們知道前端技術的主要應用場景并非知識高大上的基礎庫、框架,狂拽炫酷的宣傳頁面或者吊炸天的小游戲等這些一兩個文件的小項目,更具有商業(yè)價值的則是復雜的 Web 應用,它們功能完善、界面繁多,為用戶提供了完整的產(chǎn)品體驗。
從本質(zhì)上來講,所有 web 應用,都是一種運行在網(wǎng)頁瀏覽器中的軟件,這些軟件的圖形用戶界面即為前端。如此復雜的 Web 應用,動輒幾十上百人共同開發(fā)維護,其前端界面通常也頗具規(guī)模,工程量不亞于一般的傳統(tǒng) GUI 軟件。
前端工程化需要考慮哪些因素
模塊化
簡單來說,模塊化就是將一個大文件拆分成相互依賴的小文件,在進行統(tǒng)一的拼裝和加載,方便多人協(xié)作。分而治之是軟件工程中的重要思想,是復雜系統(tǒng)開發(fā)和維護的基石,這點放在前端開發(fā)中同樣適用。模塊化是目前前端最流行的分治手段。不管你將來是否要復用某段代碼,你都有充分的理由將其分治為一個模塊。
JS 模塊化方案:
AMD、CommonJS、UMD、ES6 Modules 等等
CommonJS
的核心思想就是把一個文件當作一個模塊,要在哪里使用這個模塊,就在哪里 require 這個模塊,然后 require 這個方法開始加載這個模塊并且執(zhí)行其中的代碼,最后返回你指定的 export 對象。
CommonJS 加載模塊是同步的,所以只有加載完成才能執(zhí)行后面的操作,不能非阻塞的并行加載多個模塊。
AMD
異步模塊加載定義,Asynchronous Module Definition,特別是可以實現(xiàn)異步加載模塊,等所有模塊都加載并且解釋執(zhí)行完成之后,才會執(zhí)行接下來的代碼。
//?通過AMD引入模塊
define(
????module_id,?//?可選
????[dependencies],?//?可選
????definition?function,?//?回調(diào)?用來初始化模塊或?qū)ο蟮暮瘮?shù)
)
//?使用
define(['myModule','myOtherModule'],function(myModule,myOtherModule){
????console.log(myModule.say());
????//?會并行加載所有的模塊,這里是a、b模塊,并執(zhí)行其中模塊的代碼后,再逐步執(zhí)行下面的console
????require("a");
????console.log('a?required');
????require("b");
????console.log('b?required');
????console.log('all?modules?have?been?required');
})
UMD
在一些同時需要 AMD 和 CommonJS 功能的項目中,你需要使用另一種規(guī)范:Universal Module Definition(通用模塊定義規(guī)范)。
UMD 創(chuàng)造了一種同時使用兩種規(guī)范的方法,并且也支持全局變量定義。所以 UMD 的模塊可以同時在客戶端和服務端使用。
ES Modules
幸運的是在 JS 的最新規(guī)范 ECMAScript6 中,引入了模塊功能。
ES6 的模塊功能汲取了 CommonJS 和 AMD 的優(yōu)點,擁有簡潔的語法并支持異步加載,并且還有其他諸多更好的支持---導入是動態(tài)只讀的,CommonJS 只是相當于把導出的代碼復制過來。
css模塊化方案
預處理器
在less、sass、stylus等預處理器的import/mixin特性支持下實現(xiàn) css modules。
雖然Sass、Less、Stylus等預處理器實現(xiàn)css的文件拆分,但沒有解決css模塊化的一個重要問題---選擇器的全局污染問題
css in JS
css in JS是徹底拋棄css,使用js或json來寫樣式。這種方法很激進,不能利用現(xiàn)有的css技術,而且處理偽類等問題比較困難
css Modules
css Modules原理:使用JS來管理樣式模塊,它能夠最大化結(jié)合css生態(tài)和js模塊化能力,通過在每個class名后帶一個獨一無二hash值,這樣就不有存在全局命名沖突問題
組件化
前端作為一種 GUI 軟件,光有 JS/CSS 的模塊化還不夠,對于 UI 組件的分支也有著同樣迫切的需求,分治的確是非常重要的工程優(yōu)化手段。
由于系統(tǒng)功能被分治到獨立的模塊或組件中,粒度比較精細,組織形式松散,開發(fā)者之間不會產(chǎn)生開發(fā)時的依賴,大幅度提升并行的開發(fā)效率,理論上允許隨時加入新成員認領組件開發(fā)或者維護工作,也更容易支持多個團隊共同維護一個大型站點的開發(fā)。
性能優(yōu)化
模塊化/組件化開發(fā)之后,我們最終解決的是:模塊化或組件加載的技術問題。
然而前端與客戶端 CUI 軟件有一個很大的不同:前端是一種遠程部署,運行時增量下載的 GUI 軟件。
如果用戶第一次訪問頁面就強制其加載全站靜態(tài)資源在展示,相信很多用戶因此會失去耐心而導致的流失。
根據(jù)增量的原則,我們應該精心規(guī)劃每個頁面的資源加載策略,使得用戶無論訪問哪個頁面都能按需加載頁面所需資源,沒訪問過的無需加載;訪問過的可以緩存復用,最終帶來流暢的應用體驗。
這正是 Web 應用免安裝的魅力所在。
由增量原則引申出的前端優(yōu)化技巧幾乎成為了性能優(yōu)化的核心。
有加載相關的按需加載、延遲加載、預加載、請求合并等策略。
有緩存相關的瀏覽器緩存利用、緩存更新、緩存共享、非覆蓋式發(fā)布等方案
還有復雜的 BigRender、BigPipe、Quickling、PageCache 等技術
這些優(yōu)化方案無不圍繞著如何將增量原則做到極致而展開。
一種靜態(tài)網(wǎng)頁資源管理和優(yōu)化技術
靜態(tài)資源管理=資源表+資源加載框架
資源表是一份數(shù)據(jù)文件(例如 json 文件),是項目中所有靜態(tài)資源(主要是 css 和 js)的構(gòu)建信息記錄,通過構(gòu)建工具掃描項目源碼生成,是一種 k-v 結(jié)構(gòu)的數(shù)據(jù),以每個資源的 id 為 key,記錄了資源的類別、部署路徑、依賴關系、打包合并等內(nèi)容。
{
??"res":?{
????"widget/a/a.css":?"/widget/a/a_1688c82.css",
????"widget/a/a.js":?"/widget/a/a_ac3123s.js",
????"widget/b/b.css":?"/widget/b/b_52923ed.css",
????"widget/b/b.js":?"/widget/b/b_a5cd123.js",
????"widget/c/c.css":?"/widget/c/c_03cab13.css",
????"widget/c/c.js":?"/widget/c/c_bf0ae3f.js",
????"jquery.js":?"/jquery_9151577.js"
??},
??"pkg":?{
????"p0":?{
??????"url":?"/pkg/lib_cef213d.js",
??????"has":?["jquery.js"]
????},
????"p1":?{
??????"url":?"/pkg/widgets_22feac1.js",
??????"has":?["widget/a/a.js",?"widget/b/b.js",?"widget/c/c.js"]
????},
????"p2":?{
??????"url":?"/pkg/widgets_af23ce5.css",
??????"has":?["widget/a/a.css",?"widget/b/b.css",?"widget/c/c.css"]
????}
??}
}
在查表的時候,如果一個靜態(tài)資源有 pkg 字段(用來記錄 web 應用中一個頁面加載過的靜態(tài)資源,當下個頁面用到這個資源就無需加載了,有效利用緩存),那么就去加載 pkg 字段所指向的打包文件,否則加載資源本身。
規(guī)范化
規(guī)范化其實是工程化很重要的一個部分,項目初期規(guī)范制定的好壞會直接影響到后期的開發(fā)質(zhì)量。
目錄結(jié)構(gòu)的制定 編碼規(guī)范 前后端接口規(guī)范 文檔規(guī)范 組件管理 Git 分支管理 Commit 描述規(guī)范 定期 CodeReview 視覺圖標規(guī)范 …
自動化
任何簡單機械的重復勞動都應讓機器去完成。
圖標合并 持續(xù)集成 自動化構(gòu)建 自動化部署 自動化測試
典型的前端工作流程分為 5 個步驟
開發(fā)階段
開發(fā)階段的首要任務是創(chuàng)建樣板項目(一并選擇前端框架、類庫),接著開始修改-驗證的主循環(huán),主要設計這些工程化設施:
腳手架:創(chuàng)建前端應用的目錄結(jié)構(gòu),并生成樣板代碼
公共庫:維護著可復用的 UI 組件、工具模塊等公共資源
包管理器:引入第三方庫/組件,并跟蹤管理這些依賴項
編輯器:提供語法高亮、智能提示、引用跳轉(zhuǎn)等功能,提升開發(fā)體驗
構(gòu)建工具:提供語法校驗、編譯、打包、DevServer 等功能,簡化工作流程
調(diào)試套件:提供預覽、DevTools、Mock、性能分析診斷等調(diào)試功能,加速修改-驗證的主循環(huán)
測試階段
開發(fā)完成,進入測試階段,先要對整體功能進行充分自測,在移交給專業(yè)的測試人員驗證,過程中需要用到工程化設施有:
單元測試框架:提供針對組件、邏輯的測試支持
靜態(tài)掃描工具:從代碼質(zhì)量、構(gòu)建產(chǎn)物質(zhì)量、最佳實踐/開發(fā)規(guī)約等多個維度做靜態(tài)檢查
自動化測試工具:針對 UI 效果和業(yè)務流程,提供測試支持
性能測試工具:監(jiān)測并統(tǒng)計出相對準確的性能數(shù)據(jù)
構(gòu)建階段
不同開發(fā)階段,在構(gòu)建階段要做更多的極限優(yōu)化和流程聯(lián)動,涉及:
打包腳本:在語法校驗、編譯、打包的基礎上,進行合并、壓縮、代碼拆分、圖片處理、ssr 等極限優(yōu)化
構(gòu)建服務:支持多任務并行打包、通知
部署階段
最后將經(jīng)過充分測試的前端應用程序部署到生產(chǎn)環(huán)境,需要這些工程化工具:
發(fā)布平臺:將前端資源上傳到 CDN 或 SSR 渲染服務,或者以離線包的形式集成到移動客戶端
迭代管理平臺:提供 CI/CD 支持
監(jiān)控階段
前端應用程序上線之后,還需要持續(xù)關注線上的實際效果和異常情況,依賴這些工程設施:
埋點平臺:統(tǒng)計、分析業(yè)務數(shù)據(jù),跟蹤性能指標
監(jiān)控平臺:觀察線上的異常信息,包括報錯、白屏、流量異常等等
總結(jié)
最理想的,前端工程不僅要持續(xù)優(yōu)化協(xié)作模式、提升開發(fā)效率、還應該保障開箱即用的上手體驗、一氣呵成的銜接體驗、無縫切換的升級體驗。
從面向過程的角度來看,前端工程是貫穿前端應用生命周期的一系列工程設施,用來保障前端應用的開發(fā)體驗、質(zhì)量和交付速度。
具體的,前端工程圍繞開發(fā)、構(gòu)建、發(fā)布 3 條主線展開,以工程化、自動化等手段解決各個環(huán)節(jié)所遇到的問題。
一方面控制前端開發(fā)的復雜度,提高前端生產(chǎn)效率;另一方面降低架構(gòu)升級,協(xié)作模式變化等帶來的遷移,適配成本、提升開發(fā)體驗。
所有《每日一題》的 知識大綱索引腦圖 整理在此:https://www.yuque.com/dfe_evernote/interview/everyday
你也可以點擊文末的 “閱讀原文” 快速跳轉(zhuǎn)

