前端工程化發(fā)展歷史

畢業(yè)前對前端工程化一直沒有什么切身的體會,現(xiàn)在工作也有半年多了,體會也越來越深,npm,yarn,Webpack ,gulp,Babel,ESlint,TypeScript 最近準備一一去深入了解一下,看到一篇不錯的關于前端工程化的發(fā)展過程,就翻譯了一下,How it feels to learn JavaScript in 2016,
https://hackernoon.com/how-it-feels-to-learn-javascript-in-2016-d3a717dd577f
雖然說是 2016 年的文章,但現(xiàn)在看來依舊不過時,也側面說明了前端也漸漸趨于穩(wěn)定了。
以下是全文:
hi,我準備寫一個網(wǎng)頁項目,但是說實話我已經(jīng)很多年沒有碰過代碼了,聽說現(xiàn)在行業(yè)變化很大。你是我們這里最與時俱進的網(wǎng)頁開發(fā)者(
web dev)了吧。
對的,但更準確的說我是前端工程師(Front End engineer)。可視化、音樂播放器、足球游戲,凡是你能想到的都屬于前端開發(fā)。我剛剛從JS 大會(JsConf)和 React 大會(ReactConf)回來,因此我知道創(chuàng)造 Web apps 最新的技術。
太棒了!我現(xiàn)在需要寫一個展示用戶活動的頁面,我需要通過
RESTful接口獲取數(shù)據(jù),然后展示到可篩選的表格中。我是不是可以用jQuery去獲取數(shù)據(jù)和展示?
天哪,不不不,已經(jīng)沒有人再用 jQuery 了。你應該去學習 React,現(xiàn)在已經(jīng) 2016 年了!
啊,好吧,
React是什么呢?
它是由 Facebook 幾個大神創(chuàng)造的一個非常 cool 的框架,它能幫助你輕松的控制視圖,更好的管理項目,提升性能。
聽起來不錯,那我能使用
React去展示來自服務端的數(shù)據(jù)嗎?
可以的,但你首先得在你的頁面中引入 React 和 React Dom 這兩個庫。
啥?為啥是兩個庫?
React 是它的核心庫,而 React Dom 是用來操控 Dom 的,通常你需要用 JSX 去描述 DOM。
JSX?JSX又是啥?
JSX 是一種 JavaScript 的語法擴展,看起來更像 XML。它是描述 DOM 的一種新的方式,比 HTML 會更好。
HTML表示很無辜。
孩子,已經(jīng) 2016 年了,沒有人直接去寫 HTML 了。
好吧,如果我添加了這兩個庫,是不是就能使用
React了?
emmm,還不太行。你還需要添加 Babel 這個庫。
又一個庫?
Babel是啥
Babel 是一個可以幫助你把任意版本的 JavaScript 代碼轉換成你要的版本。但如果你堅持只使用 ES5 的語法,Babel 也可以不引入。但現(xiàn)實點吧,現(xiàn)在是 2016 年了,你應該向大家一樣,使用 ES2016+ 的語法了。
ES5?ES2016+?我暈了,它們是些什么。
ES5 代表 ECMAScript 5,它是使用人數(shù)最多的一個版本,幾乎所有瀏覽器都支持 ES5 的語法。
ECMAScript?
它是在 1999 年提出的一個語言規(guī)范,JavaScript 屬于其中的一種實現(xiàn)。JavaScript 是 1995 年提出的,之前還叫過 Livescript,僅僅運行在網(wǎng)景的瀏覽器中。之前這些非常混亂,現(xiàn)在由于有 ECMAScript 的 7 個版本,一切都變得很清晰了,
7 個版本?那
ES5和ES2016+屬于?
分別是第 5 個和第 7 個版本。
等等,第
6個版本哪去了?
你的意思是 ES6?由于每個版本相當于之前版本的超集,所以如果使用 ES2016+,之前版本 ES6、ES5 所有的特性你就都可以使用了。
好吧,那我可以用
ES6來編程嗎?
當然可以,但你不能使用一些最新的特性,比如 async 和 await。你只能通過 ES6 的生成器和協(xié)程來執(zhí)行「同步」的形式異步請求,感興趣的話可以看一下 co 框架。
完全聽不懂你在說什么了,這些名詞我都沒有聽說過。讓我理一理,我只想從服務器加載一段數(shù)據(jù),過去我是從
CDN中拿到jQuery,然后通過AJAX請求數(shù)據(jù)就可以了,現(xiàn)在怎么變得那么復雜了?
大哥,已經(jīng) 2016 年了,沒有人再使用 jQuery 了,它只會讓你寫出意大利面條式的代碼。
好吧,所以我需要引入
React、React Dom和Babel這三個庫來拉取數(shù)據(jù)和展示HTML表格嗎?
是的,但你還需要用一個模塊管理器把這三個庫打包成一個文件。
哦哦,那模塊管理器又是啥?
它的定義取決于語境,不過在 Web 中,只要支持 AMD 和 CommonJS 模塊的話就可以稱為模塊管理器了。
等等,
AMD和CommonJS是?
按照定義來說,他們是描述不同的 javaScript 的庫和類模塊如何相互作用的不同規(guī)范,也就是常說的模塊化。你聽過 exports 和 require 嗎?你可以通過 AMD 或者 CommonJS 編寫不同的 js 模塊,然后可以使用 Browserify 把這些文件打包起來。
聽起來很有道理,但是
Browserify是什么?
它是一個可以將我們工程依賴的、由 CommonJS 編寫的 js 模塊打包起來,使其可以運行在瀏覽器中的工具。之所以有這個工具,是因為我們所依賴的那些模塊往往被發(fā)布在 npm registry 中。
npm registry?
它是一個存放著世界各地的人們編寫的代碼模塊的倉庫。
就像是
CDN?
不太一樣。它更像一個中心倉庫,人們可以在上邊發(fā)布和下載模塊。你可以把模塊下載下來在本地使用,也可以把它們上傳至 CDN 上然后使用。
明白了,就像是
Bower!
是的,但現(xiàn)在是 2016 年了,沒有人再使用 Bower 了。
哦哦,明白了,那我用
npm下載所需要的庫文件就行了。
是的,如果你想使用 React,你只需要下載 React 模塊,然后 import 到你的代碼中就可以了。你幾乎可以使用 npm 下載現(xiàn)在所有流行的 javaScprit 庫。
Angular也在里邊吧?
是的,不過 Augular 是 2015 年的事情了。雖然 Augular 現(xiàn)在也還在用,但 2016 年有了 VueJS 或者 RxJS 這些新的庫,你要學一學嗎?
算了算了,還是用
React吧,畢竟我們已經(jīng)談了這么多了。所以我如果想使用React,只需要從npm下載相應的庫,然后用Browserify打包就可以了吧?
是的。
但這看起來很復雜,需要下載那么多庫,然后再它們打包起來。
對,所以你需要使用一個任務管理器來自動化的運行 Browserify,例如 Grunt、Gulp 或者 Broccoli ,甚至可以使用 Mimosa。
Grunt?Gulp?Broccoli?Mimosa?我要瘋了,這怎么一下這么多東西。
它們都是任務管理器,但現(xiàn)在看起來一點都不 cool 了。我們在 2015 年的時候使用它們,之后還用過 Makefiles ,但是現(xiàn)在我們通過 Webpack 把所有功能都集成在一起了。
Makefiles?這些一般用在C/C++工程中吧?
是的,但是你懂的,在 Web 領域,我們總是喜歡先把事情搞復雜,然后再回歸起點。這些年我們總是這樣,你等著吧,再過一兩年我們肯定就能在 web 上寫匯編代碼了。
唉,你剛剛講的
Webpack是什么呀?
它是另一種瀏覽器的模塊管理器,同時也是一種任務執(zhí)行器(task runner)。他更像是 Browserify 的升級版。
好吧,它是比
Browserify更好嗎?
也許吧,它可以幫你更好的管理模塊之間的依賴。Webpack 允許你使用不同的模塊管理器,除了 CommonJS 類型的模塊,最新的 ES6 的模塊也是支持的。
我完全被
CommonJS/ES6這些東西搞暈了。
大家都是這樣,但通過 SystemJS 的話你就不用關心它們了。
蒼天啊,又一個
js名詞,所以SystemJS是啥?
和 Browserify 以及 Webpack 1.x 不同,SystemJS 可以動態(tài)加載模塊,允許你將不同模塊打包成不同文件,而不是打包到一個大文件中。
等等,我認為我們就是應該把所有庫打包到一個大文件中,然后加載啊。
是的,但由于 HTTP/2 的時代要來臨了,它會支持請求多路復用。
等等,所以我們不能只是把
React依賴的庫放到本地??
也不是。我的意思是我們可以把依賴的庫作為外部的腳本從 CDN 中加載,但 Babel 庫仍然需要加到本地的。
唉,這聽起來是不是不太好。
對的,你需要引入整個 babel-core,對于線上環(huán)境來說效率很差。你需要做很多的前置動作才能讓項目準備好,壓縮資源、混淆代碼、內(nèi)聯(lián) css 、延遲加載 js,還有…
明白了,明白了。所以如果不用
CDN去加載庫的話,你會怎么做?
我會使用 Webpack + SystemJS + Babel 的組合從 TypeScript 轉化。
TypeScript?我一直以為是用javaScript寫代碼。
TypeScript 就是 javaScript,更準確的說是 javaScript 的超集,或者說更具體點,是 ES6 版本的 javaScript 的超集。
ES2016+不已經(jīng)是ES6的超集了,為什么我們還需要使用這個叫TypeScript的東西?
因為它允許我們寫 javaScript 的時候定義類型,從而減少運行時的錯誤。現(xiàn)在已經(jīng)是 2016 年了,是時候在 javaScript 代碼中添加類型了。
哈哈,就像它的名字一樣,
TypeScript。
雖然 TypeScript 是 javaScript 的超集,但它還需要編譯成 javaScript 才能在瀏覽器運行。而另一種工具 Flow 就僅僅做類型檢查,無需編譯。
等等,
Flow是啥?
它是 Facebook 的幾個人開發(fā)的一個靜態(tài)類型檢查器,他們使用 OCaml 語言去寫的,因為函數(shù)式編程看起來很酷。
OCaml?函數(shù)式編程?
這是如今那些 cool kids 使用的,函數(shù)式編程、高階函數(shù)、柯里化、純函數(shù)。
哎,我一個也沒聽過。
沒有人一開始就會的。你只需要知道函數(shù)式編程比面向對象更好,并且這是 2016 該采取的方式就可以了。
不對吧,我在大學學的是面向對象,這個會更好些吧?
就像 java 被 Oracle 收購前一樣好,哈哈,我意思是面向對象過去很輝煌,當然現(xiàn)在依舊很多人在使用。但是現(xiàn)在很多人都意識到修改對象狀態(tài)是一個太危險的事情了,所以大家都轉向了不可變對象和函數(shù)式編程。Haskell 語言已經(jīng)這么做很多年了,但不要和我提 Elm 那些人。幸運的是,原生 javaScript 也可以通過 Ramda 這樣的庫進行函數(shù)式編程。
你不要再羅列名詞了,
Ramnda是什么呀?
不,是 Ramda,和 Lambda 表達式類似,它是 David Chambers 創(chuàng)建的庫。
David?是誰啊?
David Chambers ,一個大神,喜歡玩 mean Coup game,是 Ramda 的貢獻者之一。如果你想更深入的了解函數(shù)式編程,你還需要知道 Erik Meijer。
Erik Meijer是?
另一個函數(shù)式編程的大神,他有很多演講抨擊過敏捷編程。當然感興趣的話你還可以去了解 Tj, Jash Kenas, Sindre Sorhus, Paul Irish, Addy Osmani--
等等,對不起打斷一下。目前這些對于我來說應該用不到,我只想拉取數(shù)據(jù)然后展示出來。讓我們回到
React,我怎么用React從服務器獲得數(shù)據(jù)?
emmm,你不是用 React 獲取數(shù)據(jù),你只是用它展示數(shù)據(jù)。
阿西吧,那你通常用什么
fetch the data?
你可以用 Fetch 去從服務器 fetch the data。
啥?用
Fetch去從服務器fetch the data?起這個名字的人真夠簡單粗暴。
Fetch 和 XMLHttpRequests 一樣是瀏覽器的原生實現(xiàn),是為了從服務器獲取數(shù)據(jù)。
那就是
AJAX吧?
AJAX 只是基于 XMLHttpRequests 的封裝,而 Fetch 可以讓你使用 Promise 風格去異步請求數(shù)據(jù),從而避免回調(diào)地獄。
回調(diào)地獄?
就是由于網(wǎng)絡請求是異步的,你需要在回調(diào)函數(shù)里邊去獲取數(shù)據(jù),如果此時又需要網(wǎng)絡請求,那就需要在回調(diào)函數(shù)里再調(diào)用網(wǎng)絡請求,然后再加回調(diào)函數(shù),如果再請求網(wǎng)絡…會變得越來越亂。
嗯嗯,我知道這個,所以
promise可以解決這個問題嗎?
是的,通過 promise 你可以更輕松的管理異步請求,寫出易于理解的代碼,同時調(diào)用多個網(wǎng)絡請求。
也就是用
Fetch去寫?
是的,但是你得保證你用戶的瀏覽器是最新的,否則你需要 Fetch 的 polyfill(兼容不能用 Fetch 的瀏覽器),或者使用 Request,Bluebird 或者 Axios。
蒼天啊,我到底需要知道多少庫,怎么還有啊。
這就是 javaScript,有成千上萬個庫去做同樣的事情,當然我們可以從中選出一個最好用的。
那你剛才說的那些庫是干什么的呀?
它們是基于 XMLHttpRequests 實現(xiàn)的 promise 風格的請求庫。
jQuery的AJAX方法不是也開始返回promise了嗎?
忘記 jQuery 吧,去用 Fetch + polyfill,或者 Request,Bluebird, Axios。我們可以通過它們在 async 函數(shù)中 await 異步請求,就像順序編程一樣。
這是你第三次提到
await了,但我完全不知道它是干啥的。
await 允許你阻塞異步請求,讓你更好的控制異步請求,然后處理數(shù)據(jù),大大增強了代碼的可讀性。這非常方便,但你記得要加 stage-3 preset 的 Babel,或者通過 transform-async-to-generator 插件使用 syntax-async-functions。
這也太麻煩了。
不不不,真正麻煩的地方在于首先要編譯 Typescript 代碼,然后再用 Babel 轉化才能讓 await 被瀏覽器認識。
啥,
Typescript不支持await嗎?
1.7 是不支持的,它只會被編譯成 ES6,預計下一個版本才會支持。所以你只能先把Typescript 編譯成 ES6,然后再通過 Babel 把它轉換成 ES5,以便兼容更多的瀏覽器。
我不知道我還能說什么。
其實挺簡單的。就是用 Typescript 寫代碼,所有模塊都用 Fetch 去請求,加上 Babel 的 stage-3 preset ,然后使用 SystemJS 去加載它們。為了讓 Fetch 兼容更多瀏覽器,記得加 polyfill,或者使用 Request,Bluebird 或者 Axios,并且使用 await 去等待所有的 promise。
我們對簡單的定義可能不太一樣,,,所以現(xiàn)在我拿到了數(shù)據(jù),我就可以用
React展示數(shù)據(jù)了吧?
你的應用要控制所有 state 的變化嗎?
我覺得不用,我只是需要展示數(shù)據(jù)。
那太好了,不然我還得向你解釋 Flux ,以及它的一些實現(xiàn),比如 Flummox, Alt, Fluxible。但說實話, Redux 會更好用些。
我不想再知道新的名字了,我只是想展示數(shù)據(jù)。
哦哦,如果只是展示數(shù)據(jù),你其實不需要 React,用一個模版引擎就好了。
你在逗我嗎?你覺得這很有趣嗎,唉,感情淡了。
我只是想告訴你你能用什么。
那請你不要說了。
其實如果用模版引擎的話,我還是推薦你繼續(xù)使用 Typescript + SystemJS + Babel 的組合。
那你有推薦的模版嗎?
有很多,你之前有用過什么嗎?
不太記得名字了,隔的時間太久了。
jTemplates? jQote? PURE?
沒有用過,還有嗎?
Transparency? JSRender? MarkupJS? KnockoutJS? 這一個支持雙向綁定。
還有嗎?
PlatesJS? jQuery-tmpl? Handlebars?這些還有些人在用。
有和最后一個比較像的嗎?
PlatesJS? jQuery-tmpl? Handlebars? 甚至 lodash 都有一個模版引擎,但這已經(jīng)是 2014 年的事情了。
那有沒有更新一些的?
Jade? DustJS?
沒聽說過。
DotJS? EJS?
沒聽說過。
Nunjucks? ECT?
沒聽說過。
對的,應該沒有人喜歡 Coffeescript 的語法了。那 Jade?
你不是說過
Jade了嗎?
我的意思是 Pug,也是 Jade。現(xiàn)在 Jade 叫 Pug 了。
額,我想不起來我用過啥了,你現(xiàn)在用什么模版引擎?
也許會用 ES6 支持的原生模版字符串。
那我捋捋。只有
ES6支持?
對的。
那我需要用
Babel來兼容更多的瀏覽器。
對的。
我需要從
npm加載它的核心庫?
對的。
我還需要
Browerify或者Webpack或者SystemJS來管理這些模塊?
對的。
除非直接用
Webpack,不然的話我還需要一個任務管理器。
對的。
由于我要用函數(shù)式編程以及強類型的語言,我還需要
Typescript或者Flow。
對的。
如果要用
await,Babel需要進行相應的配置。
對的。
這樣我就能使用
Fetch,Promise這些神奇的東西了。
對,記得不要忘記給 Fetch 加上 polyfill,有些瀏覽器目前還不支持這個特性。
好吧,我瘋了,今天到這里吧。我不要再碰
Web了,不要再和我提javsScript了。
問題不大,也許未來我們就會使用 Elm 或者 WebAssembly 了。
我還是去寫我的后端吧。我覺得我追不上這么多的變化,各種版本號,還有各種編譯器和轉換器。
javaScript社區(qū)真是太瘋狂了,它覺得每個人能跟上這么快的變化嗎。
哈哈,你應該去了解一下 Python 社區(qū)。
為什么?
聽過 Python 3 嗎?( python 3 沒有向前兼容 pyhon 2,差異巨大)
總結一下,前端之所以發(fā)生這么大的變化,我覺得一個很關鍵的點就是 Node.js 的出現(xiàn)。它使得 js 可以脫離瀏覽器去運行,還提供了讀寫文件的能力。從而可以在本地進行編譯、轉換 js 文件,將打包完成的文件運行在瀏覽器中。
我們可以不去考慮瀏覽器支持的語法,各種模塊化、ES 的新特性,放心大膽的用就可以了,大不了最后再轉換就可以了。
此外 node.js 也使得 javaScript 可以寫一些服務器端的應用,自己只用它寫過一些 Web 接口,其他的了解不多。
