
根據(jù) React 官方網(wǎng)站 的說(shuō)明:React 是一個(gè)專(zhuān)注于 UI(View)的 JavaScript 函式庫(kù)(Library)。自從 Facebook 于 2013 年開(kāi)源 React 這個(gè)函式庫(kù)后,相關(guān)的生態(tài)系開(kāi)始蓬勃發(fā)展。事實(shí)上,透過(guò)學(xué)習(xí) React 生態(tài)系(ecosystem)的過(guò)程中,可以讓我們順便學(xué)習(xí)現(xiàn)代化 Web 開(kāi)發(fā)的重要觀念(例如:模組化、ES6+、Webpack、Babel、ESLint、函數(shù)式程式設(shè)計(jì)等),成為更好的開(kāi)發(fā)者。
ReactJS
ReactJS 是 Facebook 推出的 JavaScript 函式庫(kù),若以 MVC 框架來(lái)看,React 定位是在 View 的范疇。在 ReactJS 0.14 版之后,ReactJS 更把原先處理 DOM 的部分獨(dú)立出去(react-dom),讓 ReactJS 核心更單純,也更符合 React 所倡導(dǎo)的 Learn once, write everywhere 的理念。事實(shí)上,ReactJS 本身的 API 相對(duì)單純,但由于整個(gè)生態(tài)系非常龐大,因此學(xué)習(xí) React 卻是一條漫長(zhǎng)的道路。此外,當(dāng)你想把 React 應(yīng)用在你的應(yīng)用程式時(shí),你通常必須學(xué)習(xí)整個(gè) React Stack 才能充分發(fā)揮 React 的最大優(yōu)勢(shì)。
JSX
事實(shí)上,JSX 并非一種全新的語(yǔ)言,而是一種語(yǔ)法糖(Syntatic Sugar),一種語(yǔ)法類(lèi)似 XML 的 ECMAScript 語(yǔ)法擴(kuò)充。在 JSX 中 HTML 和組建這些元素標(biāo)簽的程式碼有緊密的關(guān)系,這和過(guò)去我們強(qiáng)調(diào) HTML、JavaScript 分離的觀念有很大不同。當(dāng)然,你可以選擇不要在 React 使用 JSX,不過(guò)相信我,當(dāng)你真正開(kāi)始撰寫(xiě) React 組件(Component)時(shí),你會(huì)很慶幸有 JSX 真好。
NPM
NPM(Node Package Manager)是 Node.js 下的主流套件管理工具。在 NPM 上有非常多的套件,可以讓你不用再重造輪子,更可以讓你可以輕松用指令管理不同的套件。由于 NPM 主要是基于 CommonJS 的規(guī)范,通常必須搭配 Browserify 這樣的工具才能在前端使用 NPM 的模組。然而因 NPM 是基于 Nested Dependency Tree,不同的套件有可能會(huì)在引入依賴(lài)時(shí)會(huì)引入相同但不同版本的套件,造成檔案大小過(guò)大的情形。這和另一個(gè)套件管理工具 Bower 專(zhuān)注在前端套件且使用 Flat Dependency Tree(讓使用者決定相依的套件版本)是比較不同的地方。
ES6+
ES6+ 系指 ES6(ES2015)和 ES7 的聯(lián)集,在 ES6+ 新的標(biāo)準(zhǔn)當(dāng)中引入許多新的特性和功能,彌補(bǔ)了過(guò)去 JavaScript 被詬病的一些特性。由于未來(lái) React 將以支援 ES6+ 為主,因此直接學(xué)習(xí) ES6+ 用法是相對(duì)好的選擇,本書(shū)的所有范例也將會(huì)以 ES6+ 撰寫(xiě)。
Babel
由于并非所有瀏覽器都支援 ES6+ 語(yǔ)法,所以透過(guò) Babel 這個(gè) JavaScript 編譯器(可以想成是翻譯機(jī)或是翻譯蒟篛)可以讓你的 ES6+ 、JSX 等程式碼轉(zhuǎn)換成瀏覽器可以看得懂的語(yǔ)法。通常會(huì)在資料夾的 root 位置加入 .babelrc 進(jìn)行轉(zhuǎn)譯規(guī)則 preset 和引用外掛(plugin)的設(shè)定。
JavaScript 模組化開(kāi)發(fā)
隨著 Web 應(yīng)用程式的復(fù)雜性提高,JavaScript 模組化開(kāi)發(fā)已經(jīng)成為必然的趨勢(shì),以下簡(jiǎn)單介紹 JavaScript 模組化的相關(guān)規(guī)范。事實(shí)上,在一開(kāi)始沒(méi)有官方定義的標(biāo)準(zhǔn)時(shí)出現(xiàn)了各種社群自行定義的規(guī)范和實(shí)踐。
-
CDN-Based
也就是最傳統(tǒng)的
<script>引入方式,然而使用這種方式雖然簡(jiǎn)單方便,但在開(kāi)發(fā)實(shí)際中大型應(yīng)用程式時(shí)會(huì)產(chǎn)生許多弊端:- 全域作用域容易造成變數(shù)污染和沖突
- 文件只能依照
<script>順序載入,不具彈性 - 在大型專(zhuān)案中各種資源和版本難以維護(hù)
- 必須由開(kāi)發(fā)者自行判斷模組和函式庫(kù)之間的依賴(lài)關(guān)系
-
AMD
Asynchronous Module Definition 簡(jiǎn)稱(chēng) AMD,為非同步載入模組的規(guī)范,其在宣告時(shí)模組時(shí)即需定義依賴(lài)的模組。AMD 常用于瀏覽器端,其最著名的實(shí)踐為 RequireJS
基本格式:
define(id?, dependencies?, factory); -
CommonJS
CommonJS 規(guī)范是一種同步模組載入的規(guī)范。以 Node.js 其遵守 CommonJS 規(guī)范,使用
require進(jìn)行模組同步載入,并透過(guò)exports、module.exports來(lái)輸出模組。主要實(shí)現(xiàn)為 Node.js 伺服器端的同步載入和瀏覽器端的 Browserify。 -
CMD
CMD 全稱(chēng)為 Common Module Definition,其規(guī)范和 AMD 類(lèi)似,但相對(duì)簡(jiǎn)潔,卻又保持和 CommonJS 的兼容性。其最大特色為:依賴(lài)就近,延遲執(zhí)行。主要實(shí)現(xiàn)為:Sea.js。
-
UMD
Universal Module Definition 是為了要兼容 CommonJS 和 AMD 所設(shè)計(jì)的規(guī)范,希望讓模組能跨平臺(tái)執(zhí)行。
-
ES6 Module
ECMAScript6 的標(biāo)準(zhǔn)中定義了 JavaScript 的模組化方式,讓 JavaScript 在開(kāi)發(fā)大型復(fù)雜應(yīng)用程式時(shí)上更為方便且易于管理,亦可以取代過(guò)去 AMD、CommonJS 等規(guī)范,成為通用于瀏覽器端和伺服器端的模組化解決方案。但目前瀏覽器和 Node 在 ES6 模組支援度還不完整,大部分情況需要透過(guò) Babel 轉(zhuǎn)譯器進(jìn)行轉(zhuǎn)譯。
Webpack/Browserify + Gulp
隨著網(wǎng)頁(yè)應(yīng)用程式開(kāi)發(fā)的復(fù)雜性提升,現(xiàn)在的網(wǎng)頁(yè)往往不單只是單純的網(wǎng)頁(yè),而是一個(gè)網(wǎng)頁(yè)應(yīng)用程式(WebApp)。為了管理復(fù)雜的應(yīng)用程式開(kāi)發(fā),此時(shí)模組化開(kāi)發(fā)方法便顯得日益重要,而理想上的模組化開(kāi)發(fā)工具一直是前端工程的很大的議題。Webpack 和 Browserify + Gulp 則是進(jìn)行 React 應(yīng)用程式開(kāi)發(fā)常用的開(kāi)發(fā)工具,可以協(xié)助進(jìn)行自動(dòng)化程式碼打包、轉(zhuǎn)譯等重復(fù)性工作,提升開(kāi)發(fā)效率。本書(shū)范例主要會(huì)搭配 Webpack 進(jìn)行開(kāi)發(fā)。
-
Webpack
Webpack 是一個(gè)模組打包工具(module bundler),以下列出 Webpack 的幾項(xiàng)主要功能:
- 將 CSS、圖片與其他資源打包
- 打包之前預(yù)處理(Less、CoffeeScript、JSX、ES6 等)的檔案
- 依 entry 文件不同,把 .js 分拆為多個(gè) .js 檔案
- 整合豐富的 Loader 可以使用(Webpack 本身僅能處理 JavaScript 模組,其余檔案如:CSS、Image 需要載入不同 Loader 進(jìn)行處理)
-
Browserify
如同官網(wǎng)上說(shuō)明的:
Browserify lets you require('modules') in the browser by bundling up all of your dependencies.,Browserify 是一個(gè)可以讓你在瀏覽器端也能使用像 Node 用的 CommonJS 規(guī)范一樣,用輸出(export)和引用(require)來(lái)管理模組。此外,也能讓前端使用許多在 NPM 中的模組。 -
Gulp
Gulp是一個(gè)前端任務(wù)工具自動(dòng)化管理工具(Task Runner)。隨著前端工程的發(fā)展,我們?cè)陂_(kāi)發(fā)前端應(yīng)用程式時(shí)有許多工作是必須重復(fù)進(jìn)行,例如:打包文件、uglify、將 LESS 轉(zhuǎn)譯成一般的 CSS 的檔案,轉(zhuǎn)譯 ES6 語(yǔ)法等工作。若是使用一般手動(dòng)的方式,往往會(huì)造成效率的低下,所以透過(guò)像是 Grunt、Gulp 這類(lèi)的 Task Runner 不但可以提升效率,也可以更方便管理這些任務(wù)。由于 Gulp 是透過(guò) pipeline 方式來(lái)處理檔案,在使用上比起 Grunt 的方式直觀許多,所以這邊我們主要討論的是 Gulp。
ESLint
ESLint 是一個(gè)提供 JavaScript 和 JSX 的程式碼檢查工具,可以確保團(tuán)隊(duì)的程式碼品質(zhì)。其支援可插拔的特性,可以根據(jù)需求在 .eslintrc 設(shè)定檢查規(guī)則。目前主流的檢查規(guī)則會(huì)使用 Airbnb 所釋出的 Airbnb React/JSX Style Guide,在使用上需先安裝 eslint-config-airbnb 等套件。
React Router
React Router 是 React 中主流使用的 Routing 函式庫(kù),透過(guò) URL 的變化來(lái)管理對(duì)應(yīng)的狀態(tài)和組件。若開(kāi)發(fā)不刷頁(yè)的單頁(yè)式(single page application)的 React 應(yīng)用程式通常都會(huì)需要用到。
Flux/Redux
Flux 是一個(gè)實(shí)現(xiàn)單向流的應(yīng)用程式資料架構(gòu)(architecture),同樣是由 Facebook 推出,并和 React 專(zhuān)注于 View 的部份形成互補(bǔ)。而由 Dan Abramov 所開(kāi)發(fā)的 Redux 被 React 開(kāi)發(fā)社群認(rèn)為是 Flux-like 更優(yōu)雅的作法,也是目前主流搭配 React 的狀態(tài)(State)管理工具。讓你在開(kāi)發(fā)復(fù)雜的應(yīng)用程式時(shí)可以更方便管理你的狀態(tài)(state)。
ImmutableJS
ImmutableJS,是一個(gè)能讓開(kāi)發(fā)者建立不可變資料結(jié)構(gòu)的函式庫(kù)。建立不可變(immutable)資料結(jié)構(gòu)不僅可以讓狀態(tài)可預(yù)測(cè)性更高,也可以提升程式的效能。
Isomorphic JavaScript
Isomorphic JavaScript 是指前后端(Client/Server)共用相同部分的程式碼,讓 JavaScript 應(yīng)用可以同時(shí)執(zhí)行在瀏覽器端和伺服器端,在 React 中可以透過(guò)伺服器端渲染(server side rendering)靜態(tài) HTML 的方式達(dá)到 Isomorphic JavaScript 效果,讓 SEO 和執(zhí)行效能更加提升并讓前后端共用程式碼。而另一個(gè)常一起出現(xiàn)的 Universal JavaScript 一般定義更為廣泛,系指可以運(yùn)行在不同環(huán)境下的 JavaScript Code,并不局限于瀏覽器和伺服器端。但要留意的是在 Github 和許多技術(shù)文章的分享上會(huì)把兩者定義為同一件事情。
React 測(cè)試
Facebook 本身有提供 Test Utilities,但由于不夠好用,所以目前主流開(kāi)發(fā)社群比較傾向使用 Airbnb 團(tuán)隊(duì)開(kāi)發(fā)的 enzyme,其可以與市面上常見(jiàn)的測(cè)試工具(Mocha、Karma、Jest 等)搭配使用。其中 Jest 是 Facebook 所開(kāi)發(fā)的單元測(cè)試工具,其主要基于 Jasmine 所建立的測(cè)試框架。Jest 除了支援 JSDOM 外,也可以自動(dòng)模擬 (mock) 透過(guò) require() 進(jìn)來(lái)的模組,讓開(kāi)發(fā)者可以更專(zhuān)注在目前被測(cè)試的模組中。
React Native
React Native和過(guò)去的 Apache Cordova 等基于 WebView 的解決方案比較不同,它讓開(kāi)發(fā)者可以使用 React 和 JavaScript 開(kāi)發(fā)原生應(yīng)用程式(Native App),讓 Learn once, write anywhere 理想變得可能。
GraphQL/Relay
GraphQL 是 Facebook 所開(kāi)發(fā)的資料查詢(xún)語(yǔ)言(Data Query Language),主要是想解決傳統(tǒng) RESTful API 所遇到的一些問(wèn)題,并提供前端更有彈性的 API 設(shè)計(jì)方式。Relay 則是 Facebook 提出搭配 GraphQL 用于 React 的一個(gè)宣告式數(shù)據(jù)框架,可以降低 Ajax 的請(qǐng)求數(shù)量(類(lèi)似的框架還有 Netflix 推出的 Falcor)。但由于目前主流的后端 API 仍以傳統(tǒng) RESTful API 設(shè)計(jì)為主,所以在使用 GraphQL 上通常會(huì)需要比較大架構(gòu)設(shè)計(jì)的變動(dòng)。因此本書(shū)則是把 GraphQL/Relay 介紹放到附錄的部份,讓有興趣的讀者可以自行參考體驗(yàn)一下。
總結(jié)
以上就是讀者在 React 生態(tài)系游走時(shí)會(huì)遇到的各種關(guān)卡,也許有些初學(xué)者會(huì)對(duì)于這樣龐大的體系所嚇到,放棄學(xué)習(xí) React 這項(xiàng)革新性技術(shù)的機(jī)會(huì)。不過(guò)別擔(dān)心,接下來(lái)筆者將帶領(lǐng)讀者按圖索驥,依序介紹整個(gè) React 生態(tài)系的各種技術(shù),一步步帶領(lǐng)大家用 React 實(shí)作出生活中會(huì)用到的應(yīng)用程式。