基於 Nuxt 的 Vue.js 服務端渲染實踐

Vue.js 是目前最火熱的前端框架之一,而 Nuxt.js 是針對 Vue.js 推出的服務端渲染框架,經過高度定製化的配置以及簡潔的 API,開發者能夠快速進行服務端渲染項目的開發,本文將對 Nuxt.js 框架作一個簡要介紹。css

服務端渲染

服務端渲染(Server Side Render)並非一個新的概念,在單頁應用(SPA)尚未流行起來的時候,頁面就是經過服務端渲染好,並傳遞給瀏覽器的。當用戶須要訪問新的頁面時,須要再次請求服務器,返回新的頁面。前端

爲了優化體驗,開發者們開始選擇採用 JavaScript 在前端完成渲染過程,用先後端分離的手段,使後端更專一於數據,而前端注重於處理展現,經過設計良好的 API 以及 Ajax 技術完成先後端的交互,jQuery、React.js、Vue.js、Angular.js 等框架應運而生。vue

這些框架給開發者帶來了巨大的便利,可是對於一些論壇、資訊網站、或是企業的官方網站來講,他們對搜索引擎優化(SEO)有強烈的要求,而前端渲染技術是沒法知足他們的需求的。若是沒法經過搜索引擎的搜索輸出自身的內容,那麼網站的價值就會大大受影響,要解決這類問題,仍是要靠服務端渲染。jquery

本文會介紹 Vue.js 的服務端渲染解決方案 Nuxt.js。Vue.js 推出後,其數據驅動和組件化思想,以及簡潔易上手的特性給開發者帶來了巨大的便利,Vue.js 官方提供的 vue-server-renderer 能夠用來進行服務端渲染的工做,可是須要增長額外的工做量,開發體驗仍有待提升,而 Nuxt.js 推出後,這個問題被很好的解決了。ios

Nuxt.js 簡介

Nuxt.js 是一個基於 Vue.js 的通用應用框架,Nuxt.js 預設了利用 Vue.js 開發服務端渲染的應用所須要的各類配置,而且能夠一鍵生成靜態站點。同時,Nuxt.js 的熱加載機制可使開發者很是便捷的進行網站的開發。vue-router

Nuxt.js 於 2016 年 10 月 25 號發佈,上線還不足一年,可是已經受到了普遍的好評,最新的穩定版本是 0.10.7,目前仍在進行 1.0 版本的內測,Nuxt.js 社區也在逐步完善中,官網已經支持了中文文檔。vue-cli

簡單上手

Vue.js 的 vue-cli 工具能夠很方便的讓咱們使用現成的模板初始化 Vue.js 項目,而 Nuxt.js 團隊已經爲咱們提供了初始化 Nuxt.js 項目的模板,安裝 vue-cli 後,只需在命令行中輸入npm

vue init nuxt/starter <projectName>複製代碼

便可完成項目的建立工做,而後進入項目目錄中執行如下命令:bootstrap

npm install
npm run dev複製代碼

Nuxt.js 會使用 3000 端口運行服務,在瀏覽器中輸入 http://localhost:3000 就能夠看到一個帶有 Nuxt.js 的 logo 的原始的頁面了。axios

項目目錄

完成了一個簡單的 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 之上的方法進行服務端渲染,具體流程以下:

  1. 調用 nuxtServerInit 方法

    當請求打入時,最早調用的便是 nuxtServerInit 方法,能夠經過這個方法預先將服務器的數據保存,如已登陸的用戶信息等。另外,這個方法中也能夠執行異步操做,並等待數據解析後返回。

  2. Middleware

    通過第一步後,請求會進入 Middleware 層,在該層中有三步操做:

    • 讀取 nuxt.config.js 中全局 middleware 字段的配置,並調用相應的中間件方法
    • 匹配並加載與請求相對應的 layout
    • 調用 layoutpage 的中間件方法
  3. 調用 validate 方法

    在這一步能夠對請求參數進行校驗,或是對第一步中服務器下發的數據進行校驗,若是校驗失敗,將拋出 404 頁面。

  4. 調用 fetchasyncData 方法

    這兩個方法都會在組件加載以前被調用,它們的職責各有不一樣,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 版本發佈後,能給咱們帶來更多實用的新功能。


做者:李韌
簡介:百姓網商業化運營中心技術團隊成員。

本文僅爲做者我的觀點,不表明百姓網立場。


本文在 「百姓網技術團隊」 微信公衆號首發,掃碼當即訂閱:

相關文章
相關標籤/搜索