前端模塊化實踐

模塊化是一種處理複雜系統分解成爲更好的可管理模塊的方式,它能夠把系統代碼劃分爲一系列職責單一,高度解耦且可替換的模塊,系統中某一部分的變化將如何影響其它部分就會變得顯而易見,系統的可維護性更加簡單易得。javascript

前端開發領域(JavaScript、CSS、Template)並無爲開發者們提供以一種簡潔、有條理地的方式來管理模塊的方法。CommonJS(致力於設計、規劃並標準化 JavaScript API)的誕生開啓了「 JavaScript 模塊化的時代」。CommonJS 的模塊提案爲在服務器端的 JavaScript 模塊化作出了很大的貢獻,可是在瀏覽器下的 JavaScript 模塊應用頗有限。隨之而來又誕生了其它前端領域的模塊化方案,像 requireJS、SeaJS 等,然而這些模塊化方案並非十分適用 ,並無從根本上解決模塊化的問題。css

前端模塊化並不等於 JavaScript 模塊化

前端開發相對其餘語言來講比較特殊,由於咱們實現一個頁面功能老是須要 JavaScript、CSS 和 Template 三種語言相互組織才行,若是一個功能僅僅只有 JavaScript 實現了模塊化,CSS 和 Template 仍是處於原始狀態,那咱們調用這個功能的時候並不能徹底經過模塊化的方式,那麼這樣的模塊化方案並非完整的,因此咱們真正須要的是一種能夠將 JavaScript、CSS 和 Template 同時都考慮進去的模塊化方案,而非僅僅 JavaScript 模塊化方案。html

JavaScript 模塊化並不等於異步模塊化

主流的 JavaScript 模塊化方案都使用「異步模塊定義」的方式,這種方式給開發帶來了極大的不便,全部的同步代碼都須要修改成異步的方式,咱們是否能夠在前端開發中使用「 CommonJS 」的方式,開發者可使用天然、容易理解的模塊定義和調用方式,不須要關注模塊是否異步,不須要改變開發者的開發行爲。前端

前端模塊化帶來的性能問題

不少主流的模塊化解決方案經過 JavaScript 運行時來支持「匿名閉包」、「依賴分析」和「模塊加載」等功能,例如「依賴分析」須要在 JavaScript 運行時經過正則匹配到模塊的依賴關係,而後順着依賴鏈(也就是順着模塊聲明的依賴層層進入,直到沒有依賴爲止)把全部須要加載的模塊按順序一一加載完畢,當模塊不少、依賴關係複雜的狀況下會嚴重影響頁面性能。java

模塊化爲打包部署帶來的極大不便

傳統的模塊化方案更多的考慮是如何將代碼進行拆分,可是當咱們部署上線的時候須要將靜態資源進行合併(打包),這個時候會發現困難重重,每一個文件裏只能有一個模塊,由於模塊使用的是「匿名定義」,通過一番研究,咱們會發現一些解決方案,不管是「 combo 插件」仍是「 flush 插件」,都須要咱們修改模塊化調用的代碼,這無疑是雪上加霜,開發者不只僅須要在本地開發關注模塊化的拆分,在調用的時候還須要關注在一個請求裏面加載哪些模塊比較合適,模塊化的初衷是爲了提升開發效率、下降維護成本,但咱們發現這樣的模塊化方案實際上並無下降維護成本,某種程度上來講使得整個項目更加複雜了。node

一體化的前端模塊化實踐方案

寫到這裏,其實咱們的「前端工程之塊化」才正式開始,本文面向對前端模塊化開發有所實踐或有所研究的同窗,接下來咱們所介紹的前端模塊化解決方案, 有別於 JavaScript 模塊化方案或 CSS 模塊化方案,它是一種能夠綜合處理前端各類資源的模塊化方案;它能夠極大提高開發者的開發體驗,併爲性能優化提供良好的支持。下面讓咱們來進一步來了解什麼是「一體化」的模塊化實踐方案。jquery

首先咱們來看一下一個 web 項目是如何經過「一體化」的模塊化方案來劃分目錄結構:web

image1

  • 站點(site):通常指能獨立提供服務,具備單獨二級域名的產品線。如旅遊產品線或者特大站點的子站點(lv.baidu.com)。
  • 子系統(module):具備較清晰業務邏輯關係的功能業務集合,通常也叫系統子模塊,多個子系統構成一個站點。子系統(module)包括兩類: common 子系統, 爲其餘業務子系統提供規範、資源複用的通用模塊;業務子系統:,根據業務、URI 等將站點進行劃分的子系統站點。
  • 頁面(page): 具備獨立 URL 的輸出內容,多個頁面通常可組成子系統。
  • 模塊(widget):能獨立提供功能且可以複用的模塊化代碼,根據複用的方式不一樣分爲 Template 模塊、JS 模塊、CSS 模塊三種類型。
  • 靜態資源(static):非模塊化資源目錄,包括模板頁面引用的靜態資源和其餘靜態資源(favicon,crossdomain.xml 等)。

前端模塊(widget),是能獨立提供功能且可以複用的模塊化代碼,根據複用的方式不一樣分爲 Template 模塊、JS 模塊、CSS 模塊三種類型,CSS 組件,通常來講,CSS 模塊是最簡單的模塊,它只涉及 CSS 代碼與 HTML 代碼; JS 模塊,稍爲複雜,涉及 JS 代碼,CSS 代碼和 HTML 代碼。通常,JS 組件能夠封裝 CSS 組件的代碼; Template 模塊,涉及代碼最多,能夠綜合處理 HTML、JavaScript、CSS 等各類模塊化資源,通常狀況,Template 會將 JS 資源封裝成私有 JS 模塊、CSS 資源封裝成本身的私有 CSS 模塊。下面咱們來一一介紹這幾種模塊的模塊化方案。算法

模板模塊

咱們能夠將任何一段可複用的模板代碼放到一個 smarty 文件中,這樣就能夠定義一個模板模塊。在 widget 目錄下的 smarty 模板(本文僅以 Smarty 模板爲例)即爲模板模塊,例如 common 子系統的 widget/nav/ 目錄shell

├── nav.css
├── nav.js
└── nav.tpl

下 nav.tpl 內容以下:

<nav id="nav" class="navigation" role="navigation"> <ul> <%foreach $data as $doc%> <li class="active"> <a href="#section-{$doc@index}"> <i class="icon-{$doc.icon} icon-white"></i><span>{$doc.title}</span> </a> </li> <%/foreach%> </ul> </nav> 

而後,咱們只須要一行代碼就能夠調用這個包含 smarty、JS、CSS 資源的模板模塊,

// 調用模塊的路徑爲 子系統名稱:模板在 widget 目錄下的路勁
{widget name="common:widget/nav/nav.tpl" }

這個模板模塊(nav)目錄下有與模板同名的 JS、CSS 文件,在模板被執行渲染時這些資源會被自動加載。如上所示,定義 template 模塊的時候,只須要將 template 所依賴的 JS 模塊、CSS 模塊存放在同一目錄(默認 JavaScript 模塊、CSS 模塊與 Template 模塊同名)下便可,調用者調用 Template 模塊只須要寫一行代碼便可,不須要關注所調用的 template 模塊所依賴的靜態資源,模板模塊會幫助咱們自動處理依賴關係以及資源加載。

JavaScript 模塊

上面咱們介紹了一個模板模塊是如何定義、調用以及處理依賴的,接下來咱們來介紹一下模板模塊所依賴的 JavaScript 模塊是如何來處理模塊交互的。咱們能夠將任何一段可複用的 JavaScript 代碼放到一個 JS 文件中,這樣就能夠定義爲一個 JavaScript 類型的模塊,咱們無須關心「 define 」閉包的問題,咱們能夠得到「 CommonJS 」同樣的開發體驗,下面是 nav.js 中的源碼.

// common/widget/nav/nav.js var $ = require('common:widget/jquery/jquery.js'); exports.init = function() { ... }; 

咱們能夠經過 require、require.async 的方式在任何一個地方(包括 html、JavaScript 模塊內部)來調用咱們須要的 JavaScript 類型模塊,require 提供的是一種相似於後端語言的同步調用方式,調用的時候默認所須要的模塊都已經加載完成,解決方案會負責完成靜態資源的加載。require.async 提供的是一種異步加載方式,主要用來知足「按需加載」的場景,在 require.async 被執行的時候纔去加載所須要的模塊,當模塊加載回來會執行相應的回調函數,語法以下:

// 模塊名: 文件所在 widget 中路徑 require.async(["common:widget/menu/menu.js"], function( menu ) { menu.init(); }); 

通常 require 用於處理頁面首屏所須要的模塊,require.async 用於處理首屏外的按需模塊。

CSS 模塊

在模板模塊中以及 JS 模塊中對應同名的 CSS 模塊會自動與模板模塊、JS 模塊添加依賴關係,進行加載管理,用戶不須要顯示進行調用加載。那麼如何在一個 CSS 模塊中聲明對另外一個 CSS 模塊的依賴關係呢,咱們能夠經過在註釋中的@require 字段標記的依賴關係,這些分析處理對 html 的 style 標籤內容一樣有效,

/** * demo.css * @require reset.css */ 

非模塊化資源

在實際開發過程當中可能存在一些不適合作模塊化的靜態資源,那麼咱們依然能夠經過聲明依賴關係來託管給靜態資源管理系統來統一管理和加載,

{require name="home:static/index/index.css" }

若是經過如上語法能夠在頁面聲明對一個非模塊化資源的依賴,在頁面運行時能夠自動加載相關資源。

項目實例

下面咱們來看一下在一個實際項目中,若是在經過頁面來調用各類類型的 widget,首先是目錄結構:

├── common
│   ├── fis-conf.js
│   ├── page
│   ├── plugin
│   ├── static
│   └── widget
└── photo
    ├── fis-conf.js
    ├── output
    ├── page
    ├── static
    ├── test └── widget 

咱們有兩個子系統,一個 common 子系統(用做通用),一個業務子系統,page 目錄用來存放頁面,widget 目錄用來存放各類類型的模塊,static 用於存放非模塊化的靜態資源,首先咱們來看一下 photo/page/index.tpl 頁面的源碼,

{extends file="common/page/layout/layout.tpl"}
{block name="main"}
    {require name="photo:static/index/index.css"}
    {require name="photo:static/index/index.js"}
    <h3>demo 1</h3> <button id="btn">Button</button> {script type="text/javascript"} // 同步調用 jquery var $ = require('common:widget/jquery/jquery.js'); $('#btn').click(function() { // 異步調用 respClick 模塊 require.async(['/widget/ui/respClick/respClick.js'], function() { respClick.hello(); }); }); {/script} // 調用 renderBox 模塊 {widget name="photo:widget/renderBox/renderBox.tpl"} {/block} 

第一處代碼是對非模塊化資源的調用方式;第二處是用 require 的方式調用一個 JavaScript 模塊;第三處是經過 require.async 經過異步的方式來調用一個 JavaScript 模塊;最後一處是經過 widget 語法來調用一個模板模塊。 respclick 模塊的源碼以下:

exports.hello = function() { alert('hello world'); }; 

renderBox 模板模塊的目錄結構以下:

└── widget
    └── renderBox
        ├── renderBox.css
        ├── renderBox.js
        ├── renderBox.tpl
        └── shell.jpeg

雖然 renderBox 下面包括 renderBox.js、renderBox.js、renderBox.tpl 等多種模塊,咱們再調用的時候只須要一行代碼就能夠了,並不須要關注內部的依賴,以及各類模塊的初始化問題。

模塊化基礎架構

整體架構

爲了實現一種天然、便捷、高性能、一體化的模塊化方案,咱們須要解決如下一些問題,

  • 模塊靜態資源管理,通常模塊總會包含 JavaScript、CSS 等其餘靜態資源,須要記錄與管理這些靜態資源
  • 模塊依賴關係處理,模塊間存在各類依賴關係,在加載模塊的時候須要處理好這些依賴關係
  • 模塊加載,在模塊初始化以前須要將模塊的靜態資源以及所依賴的模塊加載並準備好
  • 模塊沙箱(模塊閉包),在 JavaScript 模塊中咱們須要自動對模塊添加閉包用於解決做用域問題

** 使用編譯工具來管理模塊 **

咱們能夠經過編譯工具(自動化工具) 對模塊進行編譯處理,包括對靜態資源進行預處理(對 JavaScript 模塊添加閉包、對 CSS 進行 LESS 預處理等)、記錄每一個靜態資源的部署路徑以及依賴關係並生成資源表(resource map)。咱們能夠經過編譯工具來託管全部的靜態資源,這樣能夠幫咱們解決模塊靜態資源管理、模塊依賴關係、模塊沙箱問題。

** 使用靜態資源加載框架來加載模塊 **

那麼如何解決模塊加載問題,咱們能夠經過靜態資源加載框架來解決,主要包含前端模塊加載框架,用於 JavaScript 模塊化支持,控制資源的異步加載。後端模塊化框架,用於解決 JavaScript 同步加載、CSS 和模板等模塊資源的加載,靜態資源加載框架能夠用於對頁面進行持續的自適應的前端性能優化,自動對頁面的不一樣狀況投遞不一樣的資源加載方案,幫助開發者管理靜態資源,抹平本地開發到部署上線的性能溝壑。 編譯工具和靜態資源加載框架的流程圖以下:

image2

編譯工具

自動化工具會掃描目錄下的模塊進行編譯處理並輸出產出文件:

靜態資源,通過編譯處理過的 JavaScript、CSS、Image 等文件,部署在 CDN 服務器自動添加閉包,咱們但願工程師在開發 JavaScript 模塊的時候不須要關心」 define 」閉包的事情,因此採用工具自動幫工程師添加閉包支持,例如如上定義的 nav.js 模塊在通過自動化工具處理後變成以下,

define('common:widget/nav/nav.js', function( require, exports, module ) { // common/widget/nav/nav.js var $ = require('common:widget/jquery/jquery.js'); exports.init = function() { ... }; }); 

模板文件,通過編譯處理過的 smarty 文件,自動部署在模板服務器

資源表,記錄每一個靜態資源的部署路徑以及依賴關係,用於靜態資源加載框架 靜態資源加載框架(SR Management System)會加載 source maps 拿到頁面所須要的全部模塊以及靜態資源的 url,而後組織資源輸出最終頁面。

靜態資源加載框架

下面咱們會詳細講解如何加載模塊,以下所示,

image3

在流程開始前咱們須要準備兩個數據結構:

  • uris = [],數組,順序存放要輸出資源的 uri
  • has = {},hash 表,存放已收集的靜態資源,防止重複加載
  1. 加載資源表(resource map):

    javascript { "res": { "A/A.tpl": { "uri": "/templates/A.tpl", "deps": ["A/A.css"] }, "A/A.css": { "uri": "/static/css/A_7defa41.css" }, "B/B.tpl": { "uri": "/templates/B.tpl", "deps": ["B/B.css"] }, "B/B.css": { "uri": "/static/css/B_33c5143.css" }, "C/C.tpl": { "uri": "/templates/C.tpl", "deps": ["C/C.css"] }, "C/C.css": { "uri": "/static/css/C_6a59c31.css" } } }

  2. 執行 {widget name=」A」}
    • 在表中查找 id 爲 A/A.tpl 的資源,取得它的資源路徑 /template/A.tpl,記爲 tpl_path,加載並渲染 tpl_path 所指向的模板文件,即 /template/A.tpl,並輸出它的 html 內容
    • 查看 A/A.tpl 資源的 deps 屬性,發現它依賴資源 A/A.css,在表中查找 id 爲 A/A.css 的資源,取得它的資源路徑爲 /static/css/A7defa41.css_,存入 uris 數組 中,並在 has 表 裏標記已加載 A/A.css 資源,咱們獲得:

    ```javascript urls = [ ‘/static/css/A_7defa41.css’ ];

    has = { 「A/A.css」: true } ```

  3. 依次執行 {widget name=」B」}、{widget name=」c」},步驟與上述步驟 3 相同,獲得,

    ```javascript urls = [ ‘/static/css/A_7defa41.css’, ‘/static/css/B_33c5143.css’, ‘/static/css/C_6a59c31.css’ ];

    has = { 「A/A.css」: true, 「B/B.css」: true, 「C/C.css」: true }

    ```

  4. 在要輸出的 html 前面,咱們讀取 uris 數組的數據,生成靜態資源外鏈,咱們獲得最終的 html 結果:

    ```html

    html of A
    html of B
    html of C

    ``` 上面講的是對模板和 CSS 資源的加載,用於描述靜態資源加載的流程,下面咱們再來詳細講解下對於 JavaScript 模塊的處理,要想在前端實現相似「 commonJS 」同樣的模塊化開發體驗須要前端模塊化框架和後端模塊化框架一塊兒做用來實現,

前端模塊化框架,原理上你們能夠選擇使用 requireJS 或 SeaJS 來做爲模塊化支持,可是咱們並不建議這麼作,咱們建議你們使用一個 mininal AMD API,例如 requireJS 的 almond 版本或者其餘的精簡版本,requireJS 完整版有 2000 餘行,而精簡版模塊化框架只須要 100 行代碼左右就能夠實現,只須要實現如下功能:

  • 模塊定義,只須要實現以下接口 define (id, factory),由於 define 閉包是工具生成,因此咱們不須要考慮匿名閉包的實現,同時也不須要考慮「依賴前置」的支持,咱們只須要支持一種最簡單直接的模塊化定義便可
  • 模塊同步調用,require (id),靜態資源管理系統會保證所需的模塊都已預先加載,所以 require 能夠當即返回該模塊
  • 模塊異步調用,考慮到有些模塊無需再啓動時載入,所以咱們須要提供一個能夠在運行時加載模塊的接口 require.async (names, callback),names 能夠是一個 id,或者是數組形式的 id 列表。當全部都加載都完成時,callback 被調用,names 對應的模塊實例將依次傳入。
  • 模塊自執行,即 AMD 規範的提早執行,之所選擇這樣作的緣由是考慮到 Template 模塊的特殊性,通常 Template 模塊都會依賴 JavaScript 模塊來作初始化工做,選擇模塊自執行的方式咱們就不須要顯式的在 Template 頁面上書寫 require 依賴,靜態資源系統會自動加載 Template 模塊的依賴,當模塊並行加載結束後會一次自執行。你們可能會認爲若是頁面存在一些用不到的模塊那都自執行豈不會浪費資源,這裏你們能夠不用擔憂,靜態資源系統投放到前端的模塊都是頁面初始化所須要的,不存在浪費資源的狀況。
  • Resource map 前端支持,主要用於爲異步模塊調用提供 uri 支持,resourceMap 爲靜態資源管理系統自動生成,無需人工調用,用於查詢一個異步模塊的真正 url,用於自動處理異步模塊的 CDN、資源打包合併、強緩存問題,格式以下,

    javascript require.resourceMap({ "res": { "common:widget/sidebar/sidebar.async.js": { "url": "/static/common/widget/sidebar/sidebar.async_449e169.js" } } });

  • 處理循環引用,參照 nodeJS 處理循環引用的方式,在形成循環依賴的 require 以前把須要的東西 exports 出去,例如

    ```javascript // a.js console.log(‘a string’); exports.done = false; var b = require(‘./b.js’); console.log(‘in a, b.done = ‘ + b.done); exorts.done = true; console.log(‘b done’);

    // b.js console.log(‘b starting’); exports.done = false;

    var a = require(‘./a.js’); console.log(‘in b, a.done = ‘ + a.done); exports.done = true; console.log(‘b done’);

    // main.js console.log(‘main starting’); var a = require(‘./a.js’); var b = require(‘./b.js’); console.log(‘in main. a.done = ‘ + a.done + ‘, b.done = ‘ + b.done); ```

    若是在加載 a 的過程當中,有其餘的代碼(假設爲 b)require a.js 的話,那麼 b 能夠從 cache 中直接取到 a 的 module,從而不會引發重複加載的死循環。但帶來的代價就是在 load 過程當中,b 看到的是不完整的 a。

後端模塊加載框架,主要用於處理模塊的依賴並生成模塊靜態資源外鏈,下面咱們將以實例講解靜態資源管理系統是如何對 JavaScript 模塊進行加載的,以下咱們有一個 sidebar 模塊,目錄下有以下資源

├── sidebar.async.js
├── sidebar.css
├── sidebar.js
└── sidebar.tpl

sidebar.tpl 中的內容以下,

<a id="btn-navbar" class="btn-navbar"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </a> {script} $('a.btn-navbar').click(function() { require.async('./sidebar.async.js', function( sidebar ) { sidebar.run(); }); }); {/script} 

對項目編譯後,自動化工具會分析模塊的依賴關係,並生成 map.json,以下

"common:widget/sidebar/sidebar.tpl": { "uri": "common/widget/sidebsr/sidebar.tpl", "type": "tpl", "extras": { "async": [ "common:widget/sidebar/sidebar.async.js" ] }, "deps": [ "common:widget/sidebar/sidebar.js", "common:widget/sidebar/sidebar.css" ] } 

在 sidebar 模塊被調用後,靜態資源管理系統經過查詢 map.json 能夠得知,當前 sidebar 模塊同步依賴 sidebar.js、sidebar.css,異步依賴 sdebar.async.js,在要輸出的 html 前面,咱們讀取 uris 數組的數據,生成靜態資源外鏈,咱們獲得最終的 html

<script type="text/javascript"> require.resourceMap({ "res": { "common:widget/sidebar/sidebar.async.js": { "url": "/satic/common/widget/sidebar/sidebar.async_449e169.js" } } }); </script> <script type="text/javascript" src="/static/common/widget/sidebar/sidebar_$12cd4.js"></script> 

如上可見,後端模塊化框架將同步模塊的 script url 統一輩子成到頁面底部,將 css url 統一輩子成在 head 中,對於異步模塊(require.async)註冊 resourceMap 代碼,框架會經過{script}標籤收集到頁面全部 script,統一管理並按順序輸出 script 到相應位置。

自適應的性能優化

如今,當咱們想對模塊進行打包,該如何處理呢,咱們首先使用一個 pack 配置項(下面是 fis 的打包配置項),對網站的靜態資源進行打包,配置文件大體爲,

fis.config.merge({ pack: { 'pkg/aio.css': '**.css' } }); 

咱們編譯項目看一下產出的 map.json(resource map),有何變化,

{ "res": { "A/A.tpl": { "uri": "/template/A.tpl", "deps": ["A/A.css"] }, "A/A.css": { "uri": "/static/csss/A_7defa41.css", "pkg": "p0" }, "B/B.tpl": { "uri": "/template/B.tpl", "deps": ["B/B.css"] }, "B/B.css": { "uri": "/static/csss/B_33c5143.css", "pkg": "p0" }, "C/C.tpl": { "uri": "/template/C.tpl", "deps": ["C/C.css"] }, "C/C.css": { "uri": "/static/csss/C_ba59c31.css", "pkg": "p0" }, }, "pkg": { "p0": { "uri": "/static/pkg/aio_0cb4a19.css", "has": ["A/A.css", "B/B.css", "C/C.css"] } } } 

你們注意到了麼,表裏多了一張 pkg 表,全部被打包的資源會有一個 pkg 屬性 指向該表中的資源,而這個資源,正是咱們配置的打包策略。這樣靜態資源管理系統在表中查找 id 爲 A/A.css 的資源,咱們發現該資源有 pkg 屬性,代表它被備份在了一個打包文件中。

咱們使用它的 pkg 屬性值 p0 做爲 key,在 pkg 表裏讀取信息,取的這個包的資源路徑爲 /static/pkg/aio0cb4a19.css_ 存入 uris 數組 中將 p0 包的 has 屬性所聲明的資源加入到 has 表,在要輸出的 html 前面,咱們讀取 uris 數組 的數據,生成靜態資源外鏈,咱們獲得最終的 html 結果:

<html> <link href="/static/pkg/aio_0cb4a19.css"> <div>html of A</div> <div>html of B</div> <div>html of C</div> </html> 

靜態資源管理系統能夠十分靈活的適應各類性能優化場景,咱們還能夠統計 {widget} 插件的調用狀況,而後自動生成最優的打包配置,讓網站能夠自適應優化,這樣工程師不用關心資源在哪,怎麼來的,怎麼沒的,全部資源定位的事情,都交給靜態資源管理系統就行了。靜態資源路徑都帶 md5 戳,這個值只跟內容有關,靜態資源服務器今後能夠放心開啓強緩存了!還能實現靜態資源的分級發佈,輕鬆回滾!咱們還能夠繼續研究,好比根據國際化、皮膚,終端等信息約定一種資源路徑規範,當後端適配到特定地區、特定機型的訪問時,靜態資源管理系統幫你送達不一樣的資源給不一樣的用戶。說到這裏,你們應該比較清楚整個「一體化」的模塊化解決方案了,有人可能會問,這樣作豈不是增長了後端性能開銷?對於這個問題,咱們實踐過的經驗是,這很是值得!其實這個後端開銷不多,算法很是簡單直白,但他所換來的前端工程化水平提升很是大!

總結

本文是 fis 前端工程系列文章中的一部分,其實在前端開發工程管理領域還有不少細節值得探索和挖掘,提高前端團隊生產力水平並非一句空話,它須要咱們能對前端開發及代碼運行有更深入的認識,對性能優化原則有更細緻的分析與研究。fis 團隊一直致力於從架構而非經驗的角度實現性能優化原則,解決前端工程師開發、調試、部署中遇到的工程問題,提供組件化框架,提升代碼複用率,提供開發工具集,提高工程師的開發效率。在前端工業化開發的全部環節均有可節省的人力成本,這些成本很是可觀,相信如今不少大型互聯網公司也都有了這樣的共識。

相關文章
相關標籤/搜索