很重要,因此要普及。css
SEO: 搜索引擎優化(Search Engine Optimization),它是指經過站內優化,如:網站結構調整、網站內容建設、網站代碼優化以及站外優化等方法,來進行搜索引擎優化。html
簡單說: 經過各類技術(手段)來確保,你的Web內容被搜素引擎最大化收錄,最大化提升權重,帶來更多流量。前端
**常見關鍵詞:**白帽、黑帽、SEM、Backlink、Linkbait、PageRank、Keyword Stuffing...,總之都圍繞着一個核心:SEO;流量是變現的快車道,SEO 是低成本獲取流量的最佳方法。vue
目前大部分的搜索引擎僅能抓取URI直接輸出的數據資源,對於 Ajax 類的異步請求的數據沒法抓取;Google 除外,Google 有本身的Google’s Webmaster AJAX Crawling Guidelines.技術支持。node
**SPA:**單頁 Web 應用(single page web application,SPA),就是隻有一張 Web 頁面的應用,是加載單個 HTML 頁面並在用戶與應用程序交互時動態更新該頁面的 Web 應用程序。webpack
簡單說: Web 再也不是一張張頁面,而是一個總體的應用,一個由路由系統、數據系統、頁面(組件)系統...組成的應用程序,其中路由系統是非必須的。git
大部分的 Vue 項目,本質是 SPA 應用,Angular.js、Angular、Vue、React...還有最先的"Pjax"均如此。github
SPA 時代,主要是在Web端使用了history
或hash
(主要是爲了低版本瀏覽器的兼容)API,在首次請求經服務端路由輸出整個應用程序後,接下來的路由都由前端掌控了,前端經過路由做爲中心樞紐控制一系列頁面(組件)的渲染加載和數據交互。web
而上面所述的各種框架則是將以:路由、數據、視圖爲基本結構進行的規範化的封裝。ajax
最先的 SPA 應用,由 Gmail、Google Docs、Twitter 等大廠產品實踐佈道,普遍用於對SEO要求不高的場景中。
SSR: 服務端渲染(Server Side Render),即:網頁是經過服務端渲染生成後輸出給客戶端。
在 SPA 以前的時代,咱們的Web架構大都是 SSR,如:Wordpress(PHP)、JSP技術、JavaWeb...或者 DEDECMS、Discuz! 等這些程序都是傳統典型的 SSR 架構, 即:服務端取出數據和模板組合生成 html 輸出給前端,前端發生請求時,從新向服務端請求 html 資源,路由也由服務端來控制。
其次,有個概念叫預渲染(Prerendering)。
若是你只是用服務端渲染來改善一個少數的營銷頁面(如 首頁,關於,聯繫 等等)的 SEO,那你能夠用預渲染來實現。 預渲染不像服務器渲染那樣即時編譯 HTML,它只在構建時爲了特定的路由生成特定的幾個靜態頁面,等於咱們能夠經過 Webpack 插件將一些特定頁面組件 build 時就編譯爲 html 文件,直接以靜態資源的形式輸出給搜索引擎。
但實際的商業應用中,大部分時候咱們須要的是即時渲染,這也是咱們今天討論的主題。
爲何要SSR,爲了體驗,還有SEO。
首先,用戶可能在網絡比較慢的狀況下從遠處訪問網站 - 或者經過比較差的帶寬。 這些狀況下,儘可能減小頁面請求數量,來保證用戶儘快看到基本的內容。 能夠用Webpack的代碼拆分避免強制用戶下載整個單頁面應用,可是,這樣也遠沒有下載個單獨的預先渲染過的 HTML 文件性能高。
對於世界上的一些地區人,可能只能用1998年產的電腦訪問互聯網的方式使用計算機。 而 Vue 只能運行在 IE9 以上的瀏覽器,你可能也想爲那些老式瀏覽器提供基礎內容 - 或者是在命令行中使用 Lynx 的時髦的黑客。
在大部分的商業應用中,咱們有 SEO 的需求,咱們須要搜索引擎更多地抓取到咱們的內容,更詳細地認識到咱們的網頁結構,而不是僅對首頁或特定靜態頁進行索引,這是 SSR 最重要的意義。
簡單說就是,咱們須要搜素引擎看到這樣的代碼:
而不是這樣的代碼:
且,咱們還須要在 SSR 的基礎上實現 SPA,即:首屏渲染。
基本流程是:
在瀏覽器第一次訪問某個 URI 資源的時候(首屏),Web 服務器根據路由拿到對應數據渲染並輸出,且輸出的數據中包含兩部分:
在客戶端首屏渲染完成以後,此時咱們看到的其實已是一個和以前的 SPA 相差無幾的應用程序了,接下來咱們進行的任何操做都只是客戶端的應用進行交互, 頁面/組件由Web端渲染,路由也由瀏覽器控制,用戶只須要和當前瀏覽器內的應用打交道就能夠了。
以前在各大 SPA 框架還未正式官方支持 SSR 時,有一些第三方的解決方案,如:prerender.io, 它們作的事情就是創建HTTP一箇中間層,在判斷到訪問來源是蜘蛛時,輸出已緩存好的html數據,此數據若不存在,則調用第三方服務對 html 進行緩存,往復進行。
另外一方法是自行構建蜘蛛渲染邏輯,當識別 UA 爲搜索引擎時,拿服務端已準備好的模板和數據進行渲染輸出 html 數據,反之,則輸出 SPA 應用代碼;
我當時也考慮過此方法,但有不少弊端,如:
因此,最好的方法是 SPA 能和服務端使用同一套模板,且使用同一個服務端邏輯分支,再簡單說:最好 Vue、Ng2... 能直接在服務端跑起來。
因而,陸續誕生了基於 React 的Next.js、基於 Vue 的Nuxt.js、Ng2 誕生之日便支持。
沒錯,Nuxt.js 就是今天的主角。
Nuxt.js 是一個基於 Vue 的通用應用框架。
經過對客戶端/服務端基礎架構的抽象組織,Nuxt.js 主要關注的是應用的 UI渲染。
咱們的目標是建立一個靈活的應用框架,你能夠基於它初始化新項目的基礎結構代碼,或者在已有 Node.js 項目中使用 Nuxt.js。
Nuxt.js 預設了利用 Vue 開發服務端渲染的應用所須要的各類配置。
除此以外,咱們還提供了一種命令叫:nuxt generate
,爲基於 Vue 的應用提供生成對應的靜態站點的功能。
咱們相信這個命令所提供的功能,是向開發集成各類微服務(miscroservices)的 Web 應用邁開的新一步。
做爲框架,Nuxt.js 爲 客戶端/服務端 這種典型的應用架構模式提供了許多有用的特性,例如異步數據加載、中間件支持、佈局支持等。
Nuxt.js是使用 Webpack 和 Node.js 進行封裝的基於Vue的SSR框架,使用它,你能夠不須要本身搭建一套 SSR 程序,而是經過其約定好的文件結構和API就能夠實現一個首屏渲染的 Web 應用。
之因此叫 Nuxt.js 也是由於受到了 Next.js 的啓發。
做者是法國的兄弟倆,EvenYou 在微博屢次提到,也在歐洲見過哥倆。
在此以前,國內有一些對 Vue SSR 的整合嘗試,但都沒有成功,主要在於 Webpack 和 Node 的結合上沒有實踐出最佳方案, 當我看到 Nuxt.js 以約束文件夾和配置文件nuxt.config.js
的方式來管理多個程序組件之間的關係時,就以爲,很酷!
接下來,我不會提供具體更多的學習資料,由於官方文檔已經很是全面和成熟,已經 0.10.5 了(如今是 RC-11),只講下其架構和原理,和一些生產環境會遇到的問題。
首先,Nuxt.js 是一個 Node 程序,就像上面說的,咱們是要把 Vue 跑在服務端,因此必須使用 Node 環境。
咱們對 Nuxt.js 應用的訪問,其實是在訪問這個 Node.js 程序的路由,程序輸出首屏渲染內容 + 用以從新渲染的 SPA 的腳本代碼,而路由是由 Nuxt.js 約定好的 pages 文件夾生成的。
因此,總體上,Nuxt.js 經過各個文件夾和配置文件的約束來管理咱們的程序,而又不失擴展性,其有本身的插件機制。
按照目前的版本,Nuxt.js 的程序的文件結構大概分爲如下部分:
nuxt.config.js
對程序的擴展管理可大概分爲如下類:
lru-cache
的配置對象,有默認值,可選關閉require
語句webpack.config.js
相關文件中的變量語句generate
命令執行時的行爲作一些定製vue-meta
插件的全局配置,vue-meta
用於VUE/SSR程序的文檔元信息的管理plugins
文件夾中的插件vue-router
的擴展和定製,其中還包括了中間件的配置,但並不完美(後面說)chokidar
和 Webpack 的相關配置項同時,Nuxt.js 支持以generate
命令將程序直接構建爲靜態 html ,就像上面說的,能夠做爲靜態資源直接輸出。
特殊的異步需求
這是生產環境最多見的問題,沒有之一。
拿個人博客右側 Sidebar 爲例,在組件結構中,其屬於宿主 layout 下的子組件,不屬於頁面組件,沒法使用頁面組件中的fetch
方法, 官方的解釋是子組件沒法使用阻塞異步請求,即:子組件獲得的異步數據沒法用於服務端渲染,這對於程序是合理的,避免異常阻塞,簡化業務模型;
但實際需求中,我須要這些異步數據加強站內內鏈 SEO;因而,咱們能夠巧妙地使用內置 vuex 中的nuxtServerInit
這個 API,這個 API 是在 Nuxt.js 程序實例化以後第一次執行的方法, 其內部返回一個promise
,咱們能夠在這裏完成咱們站內的全部子組件異步請求,隨後將數據映射至對應子組件便可,這裏有實踐代碼。
內存問題
在阿里雲低配機上出現內存膨脹的問題,一個 Blog 程序 Run 起的內存高達 100M+,固然也因爲 Node.js 的特殊單線程異步機制,暫不關心。
但在通過一段時間的訪問以後,特別是瞬間高併發訪問,會致使內存膨脹爆表宕機,經分析,是因爲組件緩存引發的,將組件緩存減小至10,問題有所改觀,但不明顯;
更深緣由是,每次用戶訪問,程序均會從新渲染組件輸出,組件數據即在一段時間內駐存在內存中,直到 V8GC 回收。
最終的解決方案是:
使用官方推薦的"使用編碼中的 Nuxt.js "方法,自定義Node.js程序的入口,對程序進行一些優化; 若是你對業務和程序都須要有深度掌控的話,我很推薦此方法,它可使你以管理 Node.js 程序的方式管理應用。
具體的優化方法是使用了一個叫idle-gc
的垃圾回收模塊來優化內存管理,
idle-gc
是在node早期版本中被廢除的功能,主要負責空閒時的堆內存回收,而後早期被認爲有 BUG,常常會致使 CPU 滿載,因而從 Node.js 中移除了,此項目做者修復了這個 BUG,併發布了模塊。
另外,若是機器配置足夠,建議開啓緩存,即cache
選項,且適當往大的配置,cache 的意義在於使用內存常駐來減輕 CPU 的計算壓力,這對於單線程的 Node.js 是很好的業務實踐。
最新更新:已再也不使用此模塊,最終靠 [ 優化業務邏輯 ] + [ 優化頁面結構和抽象粒度 ] + [ 升級硬件 ] 來解決了問題。
這是 PM2 監控進程的平常數據之一:
移動版本適配問題
幾乎全部的搜索引擎對於 PC 和移動端業務都是分開的,因此咱們能夠巧妙地使用layouts
佈局模塊來實現咱們移動端和 PC 端業務的分離; 在個人博客項目裏,因爲業務邏輯和頁面均不夠複雜,故使用了 CSS3 媒體查詢 + 組件內判斷的形式實現了移動端的適配。
Route自定義meta問題
目前 API 中對 router 的支持不夠全面,如自定義的配置都還沒法實現,不過能夠經過宿主組件對應週期的hook
來實現對實例化後的 router 對象進行修改和管理,儘管這不夠優雅。
Window問題
因爲 Vue 的底層使用 Virtual DOM,因此 Nuxt.js 在 Node.js 環境中的編譯其實是對象計算爲字符串的過程,並無依賴 Window/Dom,或者說任何基於 Vue 的 SSR 程序均如此。
咱們在實際生產時可能用到一些須要依賴 DOM 的插件/擴展,正確的方法是根據官方文檔 - 只在瀏覽器裏使用的插件推薦的方法,經過變量判斷插件/擴展的應用環境, 這裏有實踐代碼,或者使用SSR版本的組件,如:vue-awesome-swiper, 或自行封裝directive
類型的插件,而非component
, 切記不要使用jsdom
等相似 Node.js 中的 DOM 庫,這類庫自己是爲爬蟲或測試誕生的,且自己會佔據大量的內存,這不是真正的解決方案!
有關更多經常使用使用問題,能夠參考官方解答。
最後:這是個人博客,也是一個完整的 Nuxt.js 程序,源碼在這裏。
如有差池,期待指正
完