Vue.js 是目前最火熱的前端框架之一,而 Nuxt.js 是針對 Vue.js 推出的服務端渲染框架,通過高度定製化的配置以及簡潔的 API,開發者可以快速進行服務端渲染專案的開發,本文將對 Nuxt.js 框架做一個簡要介紹。
服務端渲染
服務端渲染(Server Side Render)並不是一個新的概念,在單頁應用(SPA)還沒有流行起來的時候,頁面就是通過服務端渲染好,並傳遞給瀏覽器的。當使用者需要訪問新的頁面時,需要再次請求伺服器,返回新的頁面。
為了優化體驗,開發者們開始選擇採用 JavaScript 在前端完成渲染過程,用前後端分離的手段,使後端更專注於資料,而前端注重於處理展示,通過設計良好的 API 以及 Ajax 技術完成前後端的互動,jQuery、React.js、Vue.js、Angular.js 等框架應運而生。
這些框架給開發者帶來了巨大的便利,但是對於一些論壇、資訊網站、或是企業的官方網站來說,他們對搜尋引擎優化(SEO)有強烈的要求,而前端渲染技術是無法滿足他們的需求的。如果無法通過搜尋引擎的搜尋輸出自身的內容,那麼網站的價值就會大大受影響,要解決這類問題,還是要靠服務端渲染。
本文會介紹 Vue.js 的服務端渲染解決方案 Nuxt.js。Vue.js 推出後,其資料驅動和元件化思想,以及簡潔易上手的特性給開發者帶來了巨大的便利,Vue.js 官方提供的 vue-server-renderer
可以用來進行服務端渲染的工作,但是需要增加額外的工作量,開發體驗仍有待提高,而 Nuxt.js 推出後,這個問題被很好的解決了。
Nuxt.js 簡介
Nuxt.js 是一個基於 Vue.js 的通用應用框架,Nuxt.js 預設了利用 Vue.js 開發服務端渲染的應用所需要的各種配置,並且可以一鍵生成靜態站點。同時,Nuxt.js 的熱載入機制可以使開發者非常便捷的進行網站的開發。
Nuxt.js 於 2016 年 10 月 25 號釋出,上線還不足一年,但是已經受到了廣泛的好評,最新的穩定版本是 0.10.7,目前仍在進行 1.0 版本的內測,Nuxt.js 社群也在逐步完善中,官網已經支援了中文文件。
簡單上手
Vue.js 的 vue-cli
工具可以很方便的讓我們使用現成的模板初始化 Vue.js 專案,而 Nuxt.js 團隊已經為我們提供了初始化 Nuxt.js 專案的模板,安裝 vue-cli
後,只需在命令列中輸入
vue init nuxt/starter <projectName>複製程式碼
即可完成專案的建立工作,然後進入專案目錄中執行以下命令:
npm install
npm run dev複製程式碼
Nuxt.js 會使用 3000
埠執行服務,在瀏覽器中輸入 http://localhost:3000
就可以看到一個帶有 Nuxt.js 的 logo 的原始的頁面了。
專案目錄
完成了一個簡單的 Hello World 專案後,我們來進一步研究 Nuxt.js。進入 Nuxt.js 專案後,專案目錄如下:
下面簡要介紹一下各個目錄的作用:
-
.nuxt/
:用於存放 Nuxt.js 的核心庫檔案。例如,你可以在這個目錄下找到server.js
檔案,描述了 Nuxt.js 進行服務端渲染的邏輯(參見下一段 “Nuxt.js 的渲染流程”),router.js
檔案包含一張自動生成的路由表。 -
assets/
:用於存放靜態資源,該目錄下的資源使用 Webpack 構建。 -
components/
:存放專案中的各種元件。注意,只有在這個目錄下的檔案才能被稱為元件。 -
layouts/
:建立自定義的頁面佈局,可以在這個目錄下建立全域性頁面的統一佈局,或是錯誤頁佈局。如果需要在佈局中渲染pages
目錄中的路由頁面,需要在佈局檔案中加上<nuxt />
標籤。 -
middleware/
:放置自定義的中介軟體,會在載入元件之前呼叫。 -
pages/
:在這個目錄下,Nuxt.js 會根據目錄的結構生成vue-router
路由,詳見下文。 -
plugins/
:可以在這個目錄中放置自定義外掛,在根Vue
物件例項化之前執行。例如,可以將專案中的埋點邏輯封裝成一個外掛,放置在這個目錄中,並在nuxt.config.js
中載入。 -
static/
:不使用 Webpack 構建的靜態資源,會對映到根路徑下,如robots.txt
-
store/
:存放 Vuex 狀態樹。 -
nuxt.config.js
:Nuxt.js 的配置檔案,詳見下文。
Nuxt.js 的渲染流程
Nuxt.js 通過一系列構建於 Vue.js 之上的方法進行服務端渲染,具體流程如下:
-
呼叫
nuxtServerInit
方法當請求打入時,最先呼叫的即是
nuxtServerInit
方法,可以通過這個方法預先將伺服器的資料儲存,如已登入的使用者資訊等。另外,這個方法中也可以執行非同步操作,並等待資料解析後返回。 -
Middleware
層經過第一步後,請求會進入
Middleware
層,在該層中有三步操作:- 讀取
nuxt.config.js
中全域性middleware
欄位的配置,並呼叫相應的中介軟體方法 - 匹配並載入與請求相對應的
layout
- 呼叫
layout
和page
的中介軟體方法
- 讀取
-
呼叫
validate
方法在這一步可以對請求引數進行校驗,或是對第一步中伺服器下發的資料進行校驗,如果校驗失敗,將丟擲 404 頁面。
-
呼叫
fetch
及asyncData
方法這兩個方法都會在元件載入之前被呼叫,它們的職責各有不同,
asyncData
用來非同步的進行元件資料的初始化工作,而fetch
方法偏重於非同步獲取資料後修改 Vuex 中的狀態。
我們在 Nuxt.js 的原始碼 util.js
中可以看到以下方法:
export function applyAsyncData (Component, asyncData = {}) {
const ComponentData = Component.options.data || noopData
Component.options.data = function () {
const data = ComponentData.call(this)
return { ...data, ...asyncData }
}
if (Component._Ctor && Component._Ctor.options) {
Component._Ctor.options.data = Component.options.data
}
}複製程式碼
這個方法會在 asyncData
方法呼叫完畢後進行呼叫,可以看到,元件從 asyncData
方法中獲取的資料會和元件原生的 data
方法獲取的資料做一次合併,最終仍然會在 data
方法中返回,所以得出,asyncData
方法其實是原生 data
方法的擴充套件。
經過以上四步後,接下來就是渲染元件的工作了,整個過程可以用下圖表示:
(圖片來源:Nuxt.js 官網)
如上文所述,在 .nuxt
目錄下,你可以找到 server.js
檔案,這個檔案封裝了 Nuxt.js 在服務端渲染的邏輯,包括一個完整的 Promise
物件的鏈式呼叫,從而完成上面描述的整個服務端渲染的步驟。
Nuxt.js 的一些使用技巧
nuxt.config.js 的配置
nuxt.config.js
是 Nuxt.js 的配置檔案,可以通過針對一系列引數的設定來完成 Nuxt.js 專案的配置,可以在 Nuxt.js 官網 找到針對這個檔案的說明,下面舉例一些常用的配置:
-
head: 可以在這個配置項中配置全域性的
head
,如定義網站的標題、meta
,引入第三方的 CSS、JavaScript 檔案等:head: { title: `百姓店鋪`, meta: [ { charset: `utf-8` }, { name: `viewport`, content: `width=device-width, initial-scale=1` }, { name: `applicable-device`, content: `pc,mobile` }, ], link: [ { rel: `stylesheet`, type: `text/css`, href: `https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css`} ], script: [ {src: `https://code.jquery.com/jquery-3.1.1.min.js`}, {src: `https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js`} ] },複製程式碼
-
build: 這個配置項用來配置 Nuxt.js 專案的構建規則,即 Webpack 的構建配置,如通過 vendor 欄位引入第三方模組,通過 plugin 欄位配置 Webpack 外掛,通過 loaders 欄位自定義 Webpack 載入器等。通常我們會在 build 的 vendor 欄位中引入
axios
模組,從而在專案中進行 HTTP 請求(axios
也是 Vue.js 官方推薦的 HTTP 請求框架)。build: { vendor: [`core-js`, `axios`], loaders: [ { test: /.(scss|sass)$/, use: [{ loader: "style-loader" }, { loader: "css-loader" }, { loader: "sass-loader" }] }, { test: /.(png|jpe?g|gif|svg)$/, loader: `url-loader`, query: { limit: 1000, name: `img/[name].[hash:7].[ext]` } }, { test: /.(woff2?|eot|ttf|otf)(?.*)?$/, loader: `url-loader`, query: { limit: 1000, name: `fonts/[name].[hash:7].[ext]` } } ] }複製程式碼
-
css: 在這個配置項中,引入全域性的 CSS 檔案,之後每個頁面都會被引入。
-
router: 可以在此配置路由的基本規則,以及進行中介軟體的配置。例如,你可以建立一個用來獲取
User-Agent
的中介軟體,並在此載入。 -
loading: Nuxt.js 提供了一套頁面內載入進度指示元件,可以在此配置顏色,禁用,或是配置自定義的載入元件。
-
env: 可以在此配置用來在服務端和客戶端共享的全域性變數。
目錄即路由
Nuxt.js 在 vue-router
之上定義了一套自動化的生成規則,即依據 pages 的目錄結構生成。例如,我們有以下目錄結構:
這個目錄下含有一個基礎路由(無引數)以及兩個動態路由(帶引數),Nuxt.js 會生成如下的路由配置表(可以在 .nuxt
目錄下的 router.js
檔案中找到):
routes: [
{
path: "/",
component: _abe13a78,
name: "index"
},
{
path: "/article/:id?",
component: _48f202f2,
name: "article-id"
},
{
path: "/:page",
component: _5ccbb43a,
name: "page"
}
]複製程式碼
對於 article-id
這個路由,路徑中帶有 :id?
引數,表明這是一個可選的路由,如果要將其設為必選,則必須在 article
的目錄下新增 index.vue
檔案。
再看下面一個例子:
由於有同名檔案和資料夾的存在,Nuxt.js 會為我們生成巢狀路由,生成的路由結構如下,在使用時,需要增加 <nuxt-child />
標籤來顯示子檢視的內容。
routes: [
{
path: "/article",
component: _f930b330,
children: [
{
path: "",
component: _1430822a,
name: "article"
},
{
path: ":id",
component: _339e8013,
name: "article-id"
}
]
}
]複製程式碼
此外,Nuxt.js 還可以設定動態巢狀路由,具體可參見 Nuxt.js 的官方文件。
總結
Nuxt.js 儘管是一個非常年輕的框架,目前也有很多待改進的問題,但它的出現為 Vue.js 開發者搭建服務端渲染專案提供了巨大的便利,期待 Nuxt.js 1.0 版本釋出後,能給我們帶來更多實用的新功能。
作者:李韌
簡介:百姓網商業化運營中心技術團隊成員。本文僅為作者個人觀點,不代表百姓網立場。
本文在 “百姓網技術團隊” 微信公眾號首發,掃碼立即訂閱: