Link Search Menu Expand Document

本章內容未完成。Rails 前端打包工具,近年來變化較大,詳見 Blog文章(2022版) 說明。

現代前端工程開發

Atwood’s Law: any application that can be written in JavaScript, will eventually be written in JavaScript. - https://blog.codinghorror.com/the-principle-of-least-power/

現代前端工程開發包括了一系列以 Node.js 工具鍊的前端開發方式,包括 npmWebpack,透過 Webpack 就可以編譯 BabelReactVue.jsAngular 等等。

而 Rails 在 5.1 終於正式支援 YarnWebpack 了,詳情請見 webpacker gem,這在 Rails 4.2+ 也可以安裝。

自 2022 年起,Rails 官方已棄用了 webpacker gem,請改用 JavaScript Bundling for Rails

以下介紹近年來的前端工程演進。

JavaScript 歷史

  • JavaScript 是 1995年由網景公司的 Brendan Eich 為 Netscape Navigator 2.0瀏覽器開發的程式語言,本來叫做 LiveScript,後來跟風 Java 所以臨時改名為 JavaScript,日後這成為大眾對這門語言有諸多誤解的原因之一,兩者的關係跟張三跟張三豐差不多。
  • 第一次瀏覽器大戰時,網景將 JavaScript 提交給 ECMA 成為網路標準,學名叫做 ECMAScript
  • ES3: IE6,7,8
  • ES4: Flash, ActionScript 採用,後來被放棄
  • ES5: 2009/12 目前最廣為支援的版本
  • ES6: 2015/6 目前的熱門話題,現代瀏覽器努力增加支援中,支援度詳見 compatibility table

為了最大相容於瀏覽器,ES6 可以透過 Babel 編譯技術,將 ES6 程式碼編譯回 ES5。

以下介紹幾點 JavaScript 常考的特別之處:

global 變數

JavaScript 的變數,如果沒有宣告 var 的話,會變成 global variable。

  • https://jsbin.com/monoliqoyo/edit?js,console

建議都加上 'use strict';嚴格模式 提早發現問題。

Week Typing 弱型別

盡量用 === 而不要用 ==

123 == "123"; // true
1 == true; // true

123 === "123"; // false
1 === true;    // false

this 之謎

JavaScript 的 this 設計,跟 Ruby, Java, Swift 等等物件導向語言不一樣。JavaScript 的 this 比較殘有坑…

  • https://jsbin.com/wivilo/edit?html,console,output
    • 解法: 用 closure 把 this 先存下來
  • https://jsbin.com/wujuzod/edit?html,console,output
    • 解法一: 多包一個 function 用 closure
    • 解法二: 用 bind 方法

bind 很像可以修改 this 的方法還有 callapply,差別在於這兩個會直接呼叫,而 callapply 的差別只在參數接受不同而已,apply 第二個參數吃陣列。

Hoisting 變數抬升

JavaScript 會將變數和函數的宣告,搬到所屬 function 的最上面(也就是被抬升到該作用域的最高處)。但是卻不會先 assign 變數值,而暫時是 undefined。這個叫做 Hoisting 特性。

  • https://jsbin.com/qiwijakuko/edit?js,console

Immediately-Invoked Function Expression (IIFE)

這個小技巧還蠻常見的,用這種形式 (function(){ /* code */ }()); 執行程式碼來限制裡面的 Variable Scope 不會影響到外面的變數。

Prototype

ES5 的物件導向並沒有大家熟悉的 Class 類別語法,而是用比較原始的 Prototype 設計。

若想完全了解,推薦課程 Udacity: Object-Oriented JavaScript

MV* 設計模式和 JavaScript Template: EJS

這節我們使用 MV* 設計模式和 JavaScript Template: EJS 來實作一個 SPA (Single-page Application) 應用,透過這個練習,你可以更了解 JavaScript 物件用法。

MV* 設計模式

後端框架大多使用 MVC 架構,因此一開始 SPA 也希望套用這樣的設計模式,將程式碼拆分成 Model 和 Controller 進行組織,並搭配 JavaScript Template 實作 View 的部分。

練習一:票選貓咪 App

可能需要複習一下 jQuery

練習二:Todo App

打造例如 TodoMVC 這樣的應用

  • ejs https://ejs.co/
  • ejs gem https://github.com/sstephenson/ruby-ejs/

Example Code:

  • https://github.com/ihower/rails-exercise-ac8/blob/spa/app/views/todos/v1.html.erb
  • https://github.com/ihower/rails-exercise-ac10/blob/master/app/views/welcome/v1.html.erb (無架構單純 jQuery 版本)
  • https://github.com/ihower/rails-exercise-ac10/blob/master/app/views/welcome/v2.html.erb (自幹 MVC 版本)

其他推薦練習課程

https://www.udacity.com/course/javascript-design-patterns–ud989

其他 JavaScript Template

ejs 因為跟 erb 很像,所以對 Rails 工程師來說相對親切。不過不熟 Rails 的 F2E 沒感覺,而會選擇以下方案:

  • http://handlebarsjs.com/
  • http://mustache.github.io/
  • http://jade-lang.com/

知名的 MVC javascript framework

  • http://backbonejs.org/
  • http://emberjs.com/

這些 framework 還包括處理 Routing 路由。

歷史演進

JavaScript 的 MV* 設計模式+ JavaScript Template 的架構,基本上仍是模仿後端 MVC framework 的設計,從 2010 年 Backbone.js 開始這個風潮,而 Ember.js 集大成延續這個設計。這堂課並沒有直接學習現成的框架,而是透過模仿學習 MV* 設計模式來練習 JavaScript 技能。

另一方面,這套 MVC 架構在 2012 年已被 Angular.js 的 MVVM 架構超越,在 2014 年 Angular.js 又被 React.js 的 Component 元件化架構超越,在 2016 年 React.js 又被 Vue.js…… (現在進行式,還說不準)

這些新的框架,都是為了解決直接去修改 DOM 造成的 Single Source of Truth 問題:希望只需要修改 Model 的值,所有畫面上相關的元件都會自動變化好。而不是用 jQuery 直接去處理 DOM 元素和事件綁定,因為實在太瑣碎了。

初探 Vue.js

Vue.js 剛開始學跟 Angular.js 很類似是一套 MVVM 架構,但是較了解之後卻像 React.js 一樣是元件化。算是一個融合雙方優點,而設計上又更為輕巧容易入門的前端框架。

簡易安裝方式

相比 React.js 或 Angular 需要編譯,Vue.js 如果沒有用到單組件功能,可以不需要 Webpack 編譯,可用以下方式安裝進 Asset Pipeline。

下載 Vue.js 程式,放在 /vendor/javascripts/ 下,然後在 app/assets/javascripts/application.js 載入即可。

Vue.js 有提供 Developmemt 和 Production 版本,前者有額外的開發錯誤提示,建議可以兩個版本都下載放在 ` /vendor/assets/javascripts/ 下,然後將 application.js 改成 application.js.erb,透過判斷 Rails.env` 來決定載入哪一個版本,請參考 設定範例

另外還可以安裝 Chrome 外掛 Vue.js devtools

練習

將上一節的 MVC 題目,改成用 Vue.js 實作。

  • Cat Clicker Example
    • https://github.com/ihower/rails-exercise-ac12/blob/master/app/views/cats/v2.html.erb
  • Todo App Example Code
    • https://github.com/ihower/rails-exercise-ac8/blob/spa/app/views/todos/v2.html.erb (Vue 1.0)
    • https://github.com/ihower/rails-exercise-ac10/blob/master/app/views/welcome/v3.html.erb (Vue 2.0)

初探 Node.js

Node.js 使用了 Chrome 的高效 JavaScript V8 引擎,讓 JavaScript 可以單獨跑在 server 上,無須瀏覽器環境。這讓 JavaScript 如同 Ruby/PHP/Python 一樣可以成為後端的程式語言。

  • 開發機用 brew install node 就可以安裝使用
  • npm 套件管理工具 https://www.npmjs.com/
    • npm init 初始當前目錄成為 Node.js 專案(會產生一個 package.json 檔案)
    • npm install XXXX --save 可以安裝套件到這個專案
    • npm install 根據 package.json 安裝套件
    • 使用 git 的話,將 node_modules 這個目錄加入 .gitignore
  • CommonJS 載入模組 http://webpack.github.io/docs/commonjs.html
  • 不過因為 npm 跑太慢,Facebook 受不了在前一陣子新出了 YARN 來取代 npm,詳見 Yarn 官網 和指令對照 NPM vs Yarn Cheat Sheet。開發中的 Rails 5.1 也會使用 Yarn 這個工具來安裝 JavaScript 套件。

    • brew install yarn 即可安裝

Node.js 作為前端開發的打包工具

等同於 Rails 的 Asset Pipeline,在 Node.js 也有一樣的工具可用於打包和預處理 JavaScript、CSS 等靜態檔案。

  • 知名的有:
    • Webpack https://webpack.github.io/
    • Browserify http://browserify.org/
  • 瀏覽器不支援 Node.js 的 CommonJS 語法,而上述的打包工具會做編譯處理好讓瀏覽器可以載入
  • 上述的打包工具當然也會做編譯預處理,例如
    • ES6 透過 Babel
    • React.js 的 JSX 語法也需要編譯預處理才能給瀏覽器使用
  • 前後端分離的架構,前端可以單獨佈署至 CDN。
  • 順道一提,Rails 的 Asset Pipeline 並沒有 CommonJS 和 ES6 的編譯功能。(據說之後 Sprockets 4 會支援 ES6,但是目前的 Rails 4 和 Rails 5 用的 Sprockets 3 並沒有支援)。也因為如此,有激進 F2E 的 Rails 團隊,會改用 webpack 來作打包工具,弱化甚至拆掉 Asset Pipeline)

以下示範用 webpack 建立一個簡單的專案:

Example project: https://github.com/ihower/basic-front-end-ac8

新增專案

mkdir your_app
cd your_app

yarn init
yarn add webpack --dev
yarn add jquery
yarn global add webpack-dev-server

用 Git 的話,請把 node_modules 這個目錄加到 .gitignore 裡面

新增 webpack.config.jsindex.htmlentry.js 檔案

啟動開發伺服器

webpack-dev-server --progress --colors

打開瀏覽器前往 http://localhost:8080

React 和 Vue.js

上述 webpack 拿來開發 React 或 Vue.js 還需要安裝很多套件,React 和 Vue.js 官方都有包好的套件可以直接拿來使用,請參考:

這兩個都採用 ES6 語法

Node.js 用於後端開發

Node.js 採用 event-driven 架構和 non-blocking asynchronous I/O,對於 I/O intensive 的應用有非常好的性能表現,特別適合即時通訊和網頁遊戲的應用。但是也由於隨處都是非同步 callback 的撰寫方式,造成程式碼 Callback Hell 的缺點。

  • Node 入門:用 Node.js 實作一個 Hello World 的 HTTP server
  • Node.js 的後端框架們
    • http://expressjs.com/ (Sinatra-like MVC)
    • http://hapijs.com/ (Sinatra-like MVC)
    • http://koajs.com/ (Sinatra-like MVC)
    • http://socket.io/ (WebSocket only)
    • http://sailsjs.org/ (Rails-like MVC, integrated with socket.io )
    • https://www.meteor.com/ (Full-stack, including websocket)
    • https://strongloop.com/node-js/loopback-framework/ (REST API Only)
  • Isomorphic/Universal JavaScript 前後端通吃的野心
  • Electron 用 Web 技術做桌面 App

初探 React.js

https://facebook.github.io/react/

React 是一套強調組件化的 View library,並且採用了 JSX 語法將 HTML template 融合進 JavaScript 語法裡面。不過這也導致了它一定需要如 webpack 的打包工具進行編譯,才能佈署上瀏覽器。

比起當時的 Angular.js,輕量可組合、效能好很多、學習曲線更平滑,而且不像 Google 這是 Facebook prodcution 就在用的東西,品質可靠。

Example Code:

要在 Rails 裡面用 React 的話,安裝 react-rails 是最簡便的方式,但缺點是沒有 CommonJS 支援。

https://github.com/ihower/rails-exercise-ac8/blob/spa/app/views/todos/v3.html.erb

典範轉移

React.js 帶來的組件化 Component 概念影響了所有 JavaScript Library/Framework 後進者,包括 Vue.js、Angular 2Polymer,以及 Web components 標準。

而其 Virtual DOM 的內部實作,讓 React 不只可以運作在瀏覽器的 DOM 環境,也可以在後端 Node.js 執行,也就是 server-side rending,也可以做跨平台的 React Native

另外,也因為 React 需要編譯的關係,因此順便用 ES6 一起編譯也是順理成章了。

大型應用

無論是 React.js 或 Vue.js,都只有包含 View 組件功能。而在大型應用中,多個組件的狀態管理和資料流會變得複雜,因為狀態分散在許多組件內,而這些狀態又需要透過 Ajax 需伺服器溝通。另外,也會考量實作路由 Route 修改網址,可作為瀏覽時的進入點。

Facebook 因此延伸出 Flux 架構,以單向資料流的概念實作出一個框架。近來最有名的 Flux 實作是 Redux

Vue.js 的部分請參考 構建大型應用

參考資料

學習資源


Copyright © 2010-2022 Wen-Tien Chang All Rights Reserved.