前端工程的過去、現在與未來

Zet @ SITCON 2017

2017.03.18

About me

  • 周昱安(Zet)
    • 國立中央大學資工所 – Web 智慧與資料探勘實驗室
    • EXMA-Square 實習工程師
    • 熱衷於前端技術開發與學習
    • 願望是養一隻貓,當一個職業貓奴

前端的工程化

  • 早期的年代,前端不工程

    • 頁面互動複雜度低

    • 美術人員如果會一點基礎的 HTML、CSS 的話,與程式設計師配合就幾乎已經足以開發前端

    • 架構單純,沒有可維護性或可重用性等問題

  • 近年的前端工程化需求

    • Web Application 的普及,伴隨而來使用者介面的複雜性提高,需要有組織的架構與工作流程

    • 舊有的前端技術與標準難以應付日漸增強的工程化需要

Timeline

2007 ~ 2008:百廢待舉

  • Firefox 剛從 IE 大一統的天下瓜分掉大半領土,逼的微軟開始繼續關注瀏覽器開發與 Web 領域
  • Google Chrome 帶著 V8 Engine 橫空出世,打響新ㄧ波的瀏覽器大戰
  • Web 標準開始繼續在各家瀏覽器廠商的角力與爭執中推動
  • jQuery 開始普及,漸漸成為最熱門的 JavaScript 函式庫 
  • HTML5 第一份正式草案發佈

2009 ~ 2010:尋求方向

  • ECMAScript 5 發佈
  • 微軟發佈 世紀遺毒 IE 8
  • Node.js 問世,原本只能寄宿於前端瀏覽器的 JavaScript 開始能作為一個 Server-Side 語言使用
  • HTML 5 成為大多數人認可的 Web 未來主流技術,眾多特性開始被主流瀏覽器實作支援
  • 行動裝置訪問 Web 流量開始顯著成長

2011 ~ 2012:行動裝置的崛起

  • HTML 5 技術獲得重大發展以及廣泛地被應用,稱霸十餘載的 Flash 開始漸漸凋零
  • Web 標準開始穩定的由各家瀏覽器廠商角力與協商來慢慢的持續推進,最後經過共識而產生的標準,各家瀏覽器也絕大部分會遵守標準來實作
  • 行動裝置上的 Web 體驗開始被重視,RWD 概念廣泛被採用,相關的前端套件如雨後春筍般冒出
  • 前端的工程化開始被討論與推動
    • 社群自發推行各種模組機制
    • CoffeeScript 與 TypeScript 等 Transpiler 問世

2013 ~ 2014:工程化逐漸發展

  • HTML 5 正式定稿成為推薦標準
  • 各種 CSS 預處理器出現並被使用
  • PhoneGap 這種 Hybrid Mobile App 模式被廣泛應用
  • ECMAScript 6 漸漸受到矚目與發展,但還未被普遍用於開發
  • 第一代的 SPA 開發技術成熟,如 Angular / Backbone / Ember
  • 新時代的前端應用技術 ReactJS 剛問世,前端應用的組件化開發趨勢開始萌芽
  • Node.js 開始大量被採用於企業級應用

2015 ~ 2016:新時代的來臨

  • ES6 定稿,隨著 Babel Transpiler 的普及而開始極度大規模的被使用到實際開發中
  • npm 與 Webpack 脫穎而出,成為前端建構工具的主流
  • React 相關生態系大放異彩,全面的影響並主導前端技術與社群的趨勢走向
    • 受到 React 影響並借鑑之,Angular 2、Vue 等新一代前端解決方案到來,與 React 生態系互相競爭與推動進步
    • React Native 這種 JS Bridge Native App 解決方案問世,Weex、NativeScript 等接踵而至
    • Redux 問世,將 Functional Programing 在前端的趨勢大幅拉升

Past

HTML

HTML

  • HTML API 分成兩大部分
    • DOM(Document Object Model)
    • BOM(Browser Object Model)
  • W3C 曾經決定放棄 HTML,轉而推動其他標準
  • 瀏覽器廠商們不認同,搞小團體(WHATWG)以民間力量自行推動新一代 HTML 標準
  • 因為 WHATWG 的成員就是瀏覽器廠商,所以如果他們不願意實作的話,W3C 強行推動什麼標準也都是枉然
  • 最後 W3C 屈服了,接納 WHATWG 所推動的成果,重開 HTML 工作小組,最後與瀏覽器廠商們合力推出現在的 HTML 5 標準

HTML 5

  • Try it out on Internet Explorer
  • Did it works?
  • No?
  • It's HTML 5.

HTML 5

  • HTML 5 提供了大量的新特性,其中最重要的一類是提供瀏覽器原生的 RIA(Rich Internet Application)能力,而不再需要 Flash 等外部 Plugin

    • 影片播放

    • 音訊播放

    • 繪圖

    • 遊戲

    • 視訊

jQuery

jQuery

  • 早期各家瀏覽器對於標準的制定流程沒有共識,導致各瀏覽器的 DOM 操作或是 AJAX 等 API 都非常不一致

  • jQuery 帶來了在當時相當先進的思維與功能

    • 抽象化統一各家瀏覽器的 API 操作差異

    • 使用 CSS Selector 來選擇 DOM

    • 鏈結串式操作的習慣

    • ...etc

  • 首個取得巨大成功與高程度廣泛應用的 JS 函式庫

  • 現今已有點不敷使用於大型且複雜的前端應用程式開發,但仍然擁有承先啟後的重要歷史地位,在簡單的場景中也依然可以使用

Flash

Flash

  • Flash 在那個 HTML 原生不支援 RIA 功能的年代,提供了重要的替代方案,使得 Web 能夠更快速的流行於世界

  • 跟 jQuery 一樣,在 HTML 5 發達的這個年代已經逐漸被淘汰,但仍然在歷史中有重要地位,完成了承先啟後的歷史使命

Present

ECMAScript

  • ECMAScript 是 JavaScript 的語言標準規格,後者是前者的實作品

  • Node.js 是 ECMAScript 在伺服器端的實作品語言

  • ECMAScript 6 是 2015 年時正式發表的新一代版本標準,加入了許多重要的新語法與功能,令 JavaScript 往成為企業級語言邁進一大步

  • 後面還有 ES7(ES 2016)、ES8(ES 2017)在規劃與實作中,慣例將之統稱為 ES6+,代表新時代的 JavaScript 版本

前端開發所面臨的問題

  • 建構工具
  • 標準相容性
  • 模組化與套件管理
  • 非同步處理
  • 大型且複雜的前端應用開發

建構工具

(Building Tool)

Webpack

  • 能夠對前端程式碼或圖片、字形等檔案進行一些轉譯、打包、壓縮、額外加工處理
  • Webpack 取代 Gulp 與 Grunt 成為主流的最大原因
    • Gulp 或 Grunt 都是純粹的工作自動化工具,並不是專門為 Web 前端所設計
    •  Webpack 是只用於 Web 前端的建構處理,為其訂製了一套平台與介面,以達到有系統性的配置與建構
  • Webpack 的發展為前端 SPA 提供更進階的環境處理

標準相容性

ECMAScript 6+ 的問題

  • 各家瀏覽器的支援還不夠完美與普遍,目前仍有部分功能未被實作完成

  • 某些使用者可能永遠也不會更新到支援 ES6+ 的瀏覽器

  • 因此我們需要依賴工具將我們的 ES6+ 程式碼轉譯成 ES5 環境能運行的版本,讓我們能放心無虞的使用 ES6+ 語法或功能來開發

Babel

  • Babel 是目前最主流的 JavaScript Transpiler

  • 可以單獨運行,也可以配合 Webpack 這種前端打包工具一起使用

  • 早期原名 6 to 5,專門處理 ES6 to ES5 的程式碼轉換

  • 後來 Babel 決定平台化,除了可以使用官方維護的 ES6+ 與 React JSX 轉換功能之外,也提供 API 讓大家自行開發其他的擴充轉換功能

  • Babel 現今已經成為 ECMAScript 標準的重要推動力量

模組化與套件管理

為什麼需要模組機制?

  • 命名衝突

    • 全域命名空間下容易造成變數命名衝突,尤其是跟第三方套件衝突時更難解決

  • 程式碼間的順序與依賴性維護困難

    • 開發人員必須自行理解並解決不同 JS 檔案之間,以及與第三方套件的相互依賴關係

  • 在大型專案中各種資源難以管理,長期積累的問題導致程式碼庫混亂不堪

但是...

  • JavaScript 這個語言本身長時間以來都沒有設計這樣子的模組機制功能

  • 因此社群只好自行設計並推廣一些民間標準

    • AMD

    • CommonJS:Node.js 採用的模組規範

  • 直到 ES6 裡才制訂了原生的模組機制規範與語法

    • 融合了各家社群標準的優點,並更加先進易用

現況

  • ES6 Module 標準本身已經定案,但瀏覽器對於如何支援與配套仍然未有定論,因此前端至今仍無法原生支援模組系統

  • 可以使用 Webpack 來做打包處理,以達到前端環境中模擬模組機制的效果

npm ( Node Module Manager )

  • npm 本身是 Node.js(後端)的套件管理系統

  • 因為 Node.js 的逐漸崛起以及 npm 的普及,前端的 JS 或 CSS 套件也被放上了 npm,漸漸也成為了前端的套件管理系統主流,通吃前後端

  • Bower 等純前端套件的管理系統逐漸式微

  • 配合 Webpack 的模組機制模擬能力,可以讓一些本來只能在 Node 上使用的套件也能在前端中使用

非同步處理

Callback Hell

  • 在 JavaScript 中做非同步流程處理,傳統的方法是使用 Callback Function

  • 當連續性的非同步 Callback 一多的時候,就像是...

Promise

  • Promise 是一種非同步程式設計的解決方案,比傳統使用 Callback Function 的方式要更合理與強大
  • Promise 是一個容器,裡面保存了某個未來才會結束的事件
  • 透過原生的 Promise API 來操作這些非同步事件的流程與資料傳遞
const timeout = (delay) => new Promise((resolve, reject) => {
  if (typeof delay == 'number') {
    setTimeout(() => {
      resolve(`${delay}ms passed away.`)
    }, delay);
  } else {
    reject('input is a non-number value.');
  }
});
timeout(3000)
.then(value => {
  console.log(value);
}).catch(error => {
  console.error(error);
});
// "3000ms passed away."
timeout('abc')
.then(value => {
  console.log(value);
}).catch(error => {
  console.error(error);
});
// "input is a non-number value."

Promise

  • 以下是搭配 jQuery Ajax 的範例情境
const getArticleList = () => new Promise((resolve, reject) => {
  $.ajax({
    url: '/api/article/list',
    dataType: 'json',
    success: (result) => resolve(result)
  });
});

const getArticle = (id) => new Promise((resolve, reject) => {
  $.ajax({
    url: `/api/article/detail/${id}`,
    dataType: 'json',
    success: (result) => resolve(result)
  });
});

const getAuthor = (id) => new Promise((resolve, reject) => {
  $.ajax({
    url: `/api/author/${id}`,
    dataType: 'json',
    success: (result) => resolve(result)
  });
});

getArticleList()
.then(articles => getArticle(articles[0].id))
.then(article => getAuthor(article.authorId))
.then(author => console.log(author))
.catch(error => console.error(error));

asnyc / await

  • async function 是基於 Promise 的擴充語法
  • 能夠讓 Promise 非同步操作更接近同步的語意
    •  async 關鍵字
      • 表示這是一個 asnyc function,該 function 會自動變成一個 會 return promise 的 function
    •  await 關鍵字
      • 表示在此處等待這個 promise 的 resolve 或 reject 結果
const getAuthorByArticle = async() => {
  try {
    const articles = await getArticleList();
    const article = await getArticle(articles[0].id);
    const author = await getAuthor(article.authorId);
    console.log(author);
  } catch (error) {
    console.error(error);
  }
}

Fetch API

  • Fetch 是目標取代 XHR 的新 AJAX 技術標準,已經被一些主流瀏覽器實作

  • 是一個 HTML BOM 的 API,並非來自 ECMAScript 標準

  • Fetch 原生基於 Promise 實現,因此也可以直接搭配 async / await 使用

const getArticleList = async() => {
  const response = await fetch('/api/article/list');
  return await response.json();
} 

const getArticle = async(id) => {
  const response = await fetch(`/api/article/detail/${id}`);
  return await response.json();
} 

const getAuthor = async(id) => {
  const response = await fetch(`/api/author/${id}`);
  return await response.json();
}

try {
  const articles = await getArticleList();
  const article = await getArticle(articles[0].id);
  const author = await getAuthor(article.authorId);
  console.log(author);
} catch (error) {
  console.error(error);
}

前端應用開發

主要趨勢

  • 組件化開發

  • Virtual DOM

  • Ony-way Dataflow vs Two-way Binding

組件化

  • 將 HTML 程式碼分拆為一個一個的組件模板

  • 方便進行抽象化以及重用

  • React、Vue、Angular 2 等技術都有實現自己的組件機制,而 HTML 標準本身也在發展原生的組件系統

class ProductItem extends React.Component {
  handleButtonClick = () => {
    alert(this.props.price);
  }
  
  render() {
    return (
      <div className="item">
        <div className="title">{this.props.title}</div>
        <div className="price">{this.props.price}</div>
        <button onClick={this.handleButtonClick}>購買</button>
      </div>
    );
  }
}

Virtual DOM

  • 在框架與瀏覽器 DOM 之間實作一套模擬的 DOM 夾層

  • 當畫面需要改變時

    • 根據最新的資料重繪出新的 VDOM Tree

    • 與改變前的舊 VDOM Tree 進行全面式的比較與計算

    • 其中新舊差異的地方,才真的會在實際的 DOM 上發生操作改變,藉此來減少不必要的實體 DOM 操作以節省效能

One-way Dataflow

& Two-way Binding

  • One-way Dataflow

    • 資料是 UI 發生改變的唯一變因,只有資料改變時才會導致 UI 改變,並且 UI 不能直接改變資料

  • Two-way Binding

    • UI 擁有直接改變特定資料的能力,自動與指定的資料做雙向綁定

主流方案

React Vue Angular 2
類型 專注 UI 專注 UI 全能型框架
主導者 Facebook 個人項目 Google
組件化
Virtual DOM v2 開始有
Dataflow 單向 單向 / 雙向 單向 / 雙向
View 結構定義 JSX template / JSX template
學習門檻

Future

HTTP / 2

  • 新版的 HTTP 傳輸協定

  • 能夠支援更好的平行加載資源

    • 現今將多個資源打包成少數檔案的優化處理,未來可能不再是最佳實踐

  • 主流的瀏覽器都已經支援

PWA(Progressive Web App)

  • Google 推廣的一種 Web Mobile App 技術,目的是希望提高手機版網頁應用的體驗

    • 安裝性:可以瞬間添加到主畫面並且全螢幕運行,不用包成真的的 App 到 Store 裡下載安裝

    • 離線使用:安裝時會將應用的基本架構暫存在本地端,以達到在斷網或網路訊號弱的時候依然能秒開的體驗

    • 推播:能夠主動發起推播訊息

JS Bridge Native App

  • 使用 JavaScript 來開發原生的行動裝置 App(Android、iOS)

  • 原理是框架包含了 JS 與原生程式的橋樑,以及 JS 程式碼翻譯引擎,以達到寫 JS 程式碼產原生組件的效果,並且兩大平台的應用能共用大部分程式碼

  • 與 Web 三大前端應用方案有密切關係

    • React:React Native

    • Vue:Weex

    • Angular 2:NativeScript

WebAssembly

  • 各大瀏覽器廠商合作發展的一項技術,目的是能夠將其他程式語言經過編譯之後在瀏覽器環境中執行

  • 目前主要的用途導向是遊戲(C++)

  • 還在初期階段,到正式廣泛應用可能還要 5 ~ 8 年的時間

  • 發展順利並成熟的話,我們可能可以看到用多個語言皆可撰寫前端程式的一天

展望 2017

2017 前端冥燈大預測

  • 模組系統可能會在瀏覽器上原生實現

  • Babel 繼續擔任 ECMAScript 的重要推動力量

  • React 依然稱霸,核心重寫之後的新版會再一次掀起前端方案的效能與思想之爭

  • Vue 會迎來高峰,力壓 Angular 2 的地位,緊逼 React

  • Redux 依然在 State 管理的主流競爭者當中

  • HTTP / 2 普及

  • HTML 原生的 Web Component 依然受到冷落,但伺機而動

  • 更多前端技術與開發廠商放棄支援 IE 8,IE 9 準備上刑場

大前端時代

大前端時代

  • 前端工程由於使用者體驗的需求提高、UI 複雜度大幅增加而重要性提高

  • 各種行動裝置、平台更讓前端的需求廣泛

  • HTML 5 的發展、Hybrid App、PWA、JS Bridge Native App 讓 Web 前端工程師能有效的跨足於行動裝置平台的開發

  • 前端技術發展熱絡,工程化技術不斷在推翻與進步

  • 對前端工程師來說,學習的能力非常重要

學習管道

  • 實體書籍

  • 網路資源:文章、影片課程、線上社團、線上讀書會

  • 社群活動:Conf、小型分享會、工作坊

  • 實習、接案

  • 認識並跟其他人交流、溝通、合作

Thanks!

SITCON 2017 - 前端工程的過去、現在與未來

By tz5514

SITCON 2017 - 前端工程的過去、現在與未來

  • 2,874