前段時間在知乎上看到一篇提問,說的是爲何如今又開始流行服務器端渲染html了。整理了網上一些評論,結合本身的想法,整理出了一段前端發展史。html
早在1989年,HTML的誕生是一個物理學家爲了方便學術文檔的分享而創造,這個也是前端起始的時間。後來,CSS和Javascript加入前端行列,用來渲染頁面樣式和處理頁面動效邏輯,前端三劍客成立。剛開始的前端程序員,其實就是作切圖寫樣式(CSS)和作頁面特效(JS)等一切基礎的工做,處於程序員鄙視鏈的底層。
隨着互聯網發展與技術進步,靜態頁面已經遠不能知足產品需求,頁面上要根據邏輯產生動態的數據,這時,便迎來PHP,JSP等爲表明的web1.0時代。此時的服務器渲染,是以「文檔」爲核心思想。服務器端的邏輯是把HTML,CSS和JS當作一個靜態文件,對「文檔」而言不存在「指令」和「數據」的區別,一切都是數據。因此咱們能夠看到服務器渲染,GET就是請求一個文件,而web 1.0時代的諸多服務端框架最基礎的組件之一就是文檔模版,好比asp, JSP之類,核心設計理念就是HTML文件裏放佔位符而後由服務端邏輯替換成實際數據後一股腦返回。不少中小型項目,不分前端後端,你們都是web開發工程師,按如今的說法叫全棧工程師。而在如今來看,這樣的模式是存在不少問題的,拿jsp舉例,動態資源和靜態資源徹底耦合,服務器壓力大,並且一旦出現情況,先後臺一塊兒玩完,用戶體驗極差;jsp必需要在支持java的web服務器裏運行,性能提不上來;若是jsp中內容不少,頁面響應會很慢……
1998年,IE5.0引入XMLHttpRequest技術,實現了異步調用服務器的功能,2005年,Google在它著名的交互應用程序中使用了ajax異步通信,web前端引來2.0革命。以後W3C發佈XMLHttpRequest標準,爲以後的ajax爆發提供技術基礎。
2006年,JQuery工具庫發佈,一經出世憑藉其簡單易容的特性和解決瀏覽器兼容性的能力風靡全球。
2010年,Backbone誕生,RequireJS第一個版本發佈,前端的模塊化開發時代正式來臨了。然後,隨着前端MVC的興起,SPA(Single Page Application 單頁面應用)開始變成一種項目開發的潮流,先後端分工很是清晰。前端工做在瀏覽器端,後端工做在服務端。清晰的分工,可讓開發並行,測試數據的模擬不難,前端能夠本地開發。此時先後端分離的運動在各大公司間興起,前端自立門戶,獨立發展。前端程序員們翻身的機會來了。
然而此時,不少本不應被作成SPA的也被作成了SPA。可是,SPA應用存在種種問題,好比SEO,好比首屏加載速度,這讓前端開發人員優化愁白了頭。
隨着Node.js的興起,Javascript開始有能力運行在服務器端,這意味這有一種新的研發模式:Front-end UI layer 處理瀏覽器層的展示邏輯,Back-end UI layer 處理路由、模板、數據獲取、cookie 等。經過 Node,Web Server 層也是 JavaScript 代碼,這意味着部分代碼可先後複用,須要 SEO 的場景能夠在服務端同步渲染,因爲異步請求太多致使的性能問題也能夠經過服務端來緩解。前一種模式的不足,經過這種模式幾乎都能完美解決掉。
Web 2.0時代最大的思想革命本質不是先後端分離,而是把網頁看成獨立的應用程序(app)。先後端分離只是實現這一新架構的必然結果。對程序而言指令和數據是分離的。HTTP GET拿到的不是渲染後的網頁,而是一個由html和Javascript組成的app, 這個app以瀏覽器爲虛擬機。裝載和顯示數據是app啓動以後的運行邏輯。傳統上app叫什麼?叫Client,也就是前端。因而先後端就這麼分離了,瀏覽器變成了app的運行環境,後端蛻化成了單純的業務邏輯和數據接口。寫Javascript再也不是給網頁添特效的小伎倆,而是正經的和寫桌面應用程序同樣的工程。因而咱們看到了前端工程化,編譯(轉譯),各類MVC/MVVM框架,依賴工具,等等。前端
使用服務器端渲染,最主要的問題,其實就是爲了解決SEO的問題。若是SPA應用也有良好的SEO,就不用服務器端渲染這麼麻煩了。固然服務器端渲染能解決的首屏加載速度的問題也是緣由之一。那麼,SEO是什麼呢?
SEO(Search Engine Optimization),搜索引擎優化。好比谷歌、百度須要抓取你所發佈的網站信息來進行天然排序,是經過爬蟲進行的。
來看兩段代碼:
vue
上面是以前很早前寫過的兩段掘金文章的爬蟲代碼(寫的有點low),大概思路就是使用superagent發送http請求,把整個頁面(文檔對象)爬下來,包括head, body等,而後用cheerio進行解析,而後抓取頁面節點元素以及關鍵信息。可能你以爲,這個簡單,我頁面上信息都是經過ajax請求到而後插入到dom元素中的。注意,爬蟲爬到的頁面並無發送ajax請求,就是一個初始化的純靜態頁面,若是你用的是spa應用,那可能body中除了一個id爲app的節點,什麼都沒有。因此,咱們須要讓頁面在服務器端就已經被渲染完成,傳給客戶端的時候已是一個具備數據信息的靜態html文檔。固然,如今也有針對SPA應用進行的SEO優化方案,這個不在本文討論範圍以內。
如下總的列舉服務器渲染的一些優缺點:java
通用(也稱同構)的JavaScript已經成爲JavaScript社區很經常使用的一個術語。通用的JavaScript用來形容能夠在客戶端執行,也可在服務端執行的Javascript代碼。 在VUE的官方文檔上是這麼描述的:webpack
Vue.js 是構建客戶端應用程序的框架。默認狀況下,能夠在瀏覽器中輸出 Vue 組件,進行生成 DOM 和操做 DOM。然而,也能夠將同一個組件渲染爲服務器端的 HTML 字符串,將它們直接發送到瀏覽器,最後將靜態標記"混合"爲客戶端上徹底交互的應用程序。ios
前半句好理解,就是說你能夠在服務器(後端)環境中,使用vue.js來構建組件和頁面,而後將渲染好的靜態html字符串傳給客戶端展現。後半句感受句子不太通順,英文版是這樣的:git
「Finally "hydrate" the static markup into a fully interactive app on the client.」程序員
大概意思就是說,把應用傳給客戶端之後,因爲一些靜態標記,客戶端也會具有一樣的交互(就是MVVM雙向數據綁定)。github
構建服務端渲染的JavaScript程序多少有些無趣,在開始編碼以前,須要大量的基礎配置。所以,解決vue.js服務端渲染問題的Nuxt.js產生了。 Nuxt.js 是一個基於 Vue.js 的通用應用框架。預設了服務器端渲染所需的各類配置,如異步數據,中間件,路由,只要遵循其中的規則就能輕鬆實現SSR。。它比如是 Angular Universal 之於 Angular, Next.js 之於 React。 經過對客戶端/服務端基礎架構的抽象組織,Nuxt.js 主要關注的是應用的 UI渲染。web
在安裝vue-cli的狀況下,快速生成一個nuxt項目的命令以下:
$ vue init nuxt-community/starter-template <project-name>
複製代碼
進入項目目錄後
$ npm install
複製代碼
而後啓動項目
$ npm run dev
複製代碼
這樣項目就能正常運行在http://localhost:3000
了
這裏就不詳細介紹nuxt.js的一些用法和API了,能夠直接看官網的教程:zh.nuxtjs.org/guide 。
我本身作了一個nuxt.js的簡單demo(極其簡單),Github地址,這裏就我本身的的一些體驗,對比spa應用,來聊聊這個框架。
nuxt是採用vue-cli來建立的模板,相比常規的vue模板,他們具有很是重要的一點:方便。nuxt.js一樣已經將各類項目所需的webpack配置替咱們打理好了,開箱即用,基本不須要做什麼改動。並且即便須要自定義一些配置,修改起來也很是簡單。咱們來把它的目錄結構和SPA應用做一個對比。
pages/
--| _slug/
-----| comments.vue
-----| index.vue
--| users/
-----| _id.vue
--| index.vue
複製代碼
Nuxt.js 生成對應的路由配置表爲:
router: {
routes: [
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'users-id',
path: '/users/:id?',
component: 'pages/users/_id.vue'
},
{
name: 'slug',
path: '/:slug',
component: 'pages/_slug/index.vue'
},
{
name: 'slug-comments',
path: '/:slug/comments',
component: 'pages/_slug/comments.vue'
}
]
}
複製代碼
index.js
,而後對外暴露一個Vuex.Store實例便可。可是,通過踩坑,這裏的狀態樹和SPA裏有些不同,這個等會說。actions
中的nuxtServerInit函數,這個咱們等會再說。middleware
裏的中間件函數,此時,尚未進行數據獲取和頁面渲染,因此咱們能夠在中間件函數中執行一些進入路由前的邏輯,好比用戶權限判斷。this
。head
部分能夠自定義當前頁面的頭部信息,好比title, meta之類的。固然,若是須要定義全局head能夠在nuxt.config.js
中配置。layout
部分能夠自定義頁面佈局,不少頁面公用的靜態頭、尾部分能夠統必定義按需引用。scrollToTop
用於頁面跳轉時將頁面滾動置頂。transition
用於頁面間跳轉的過渡動畫。整個demo作下來,目前讓我印象最深的就是狀態樹,它和SPA應用仍是有必定區別的。
當時我須要完成的需求是,保存用戶信息,並在任何頁面可使用它,若是非登陸頁沒有獲取到用戶信息,跳轉回登陸頁。
起初,個人設計思路是,在用戶登陸成功後,調用後臺接口獲取該用戶全部信息,而且存在store中。流程圖以下:
nuxtServerInit
。Nuxt.js 調用它的時候會將頁面的上下文對象做爲第2個參數傳給它,上下文對象能夠拿到
req
請求對象,那麼就存在這麼一種邏輯。我能夠將用戶信息存儲在服務器session中,而後經過
req.session.user
來訪問當前登陸的用戶。將用戶登陸信息傳給客戶端的狀態樹,代碼以下:
actions: {
nuxtServerInit ({ commit }, { req }) {
if (req.session.user) {
commit('user', req.session.user)
}
}
}
複製代碼
這樣在配合middleware中間件,就能夠完成用戶信息獲取和會話控制,流程以下:
其它還涉及的一些內容,其實看看官網教程,看看官網示例都能搞定,教程仍是很是易懂的。
使用Vue,React等服務器渲染,並非走之前模板式渲染的老路。它已經跨越歷史,朝着更優秀的方面發展。 而Nuxt.js,仍是一個很是年輕的框架(如今官網纔是0.10.7版本),目前也有不少待改進的問題,但它的出現爲 Vue.js 開發者搭建服務端渲染項目提供了巨大的便利。據說Nuxt.js 2.0 即未來臨,期待版本發佈後,能給咱們帶來更多實用的新功能。