Vue服務(wù)端渲染:Nuxt.js

官網(wǎng):https://zh.nuxtjs.org/
GitHub:https://github.com/nuxt/nuxt.js

Vue.js 是目前最火熱的前端框架之一歇盼,而Nuxt.js是針對 Vue.js 推出的服務(wù)端渲染框架弛饭,通過高度定制化的配置以及簡潔的API笨觅,開發(fā)者可以快速進(jìn)行服務(wù)端渲染項目的開發(fā)

服務(wù)端渲染

  • 服務(wù)端渲染(Server Side Render)并不是一個新的概念蝇狼,在單頁應(yīng)用(SPA)還沒有流行起來的時候,頁面就是通過服務(wù)端渲染好祸轮,并傳遞給瀏覽器的垒在。當(dāng)用戶需要訪問新的頁面時犬绒,需要再次請求服務(wù)器,返回新的頁面挂签。

  • 為了優(yōu)化體驗疤祭,開發(fā)者們開始選擇采用 JavaScript在前端完成渲染過程,用前后端分離的手段饵婆,使后端更專注于數(shù)據(jù)勺馆,而前端注重于處理展示,通過設(shè)計良好的API以及Ajax 技術(shù)完成前后端的交互侨核,jQuery草穆、React.jsVue.js搓译、Angular.js等框架應(yīng)運(yùn)而生悲柱。

  • 這些框架給開發(fā)者帶來了巨大的便利,但是對于一些論壇侥衬、資訊網(wǎng)站诗祸、或是企業(yè)的官方網(wǎng)站來說,他們對搜索引擎優(yōu)化(SEO)有強(qiáng)烈的要求轴总,而前端渲染技術(shù)是無法滿足他們的需求的直颅。如果無法通過搜索引擎的搜索輸出自身的內(nèi)容,那么網(wǎng)站的價值就會大大受影響怀樟,要解決這類問題功偿,還是要靠服務(wù)端渲染。

  • SSR: 服務(wù)端渲染(Server Side Render)往堡,即:網(wǎng)頁是通過服務(wù)端渲染生成后輸出給客戶端械荷。比如JSPPHP虑灰、JavaWeb等都是SSR架構(gòu)吨瞎,也就是服務(wù)端取出數(shù)據(jù)和模板組合生成 html 輸出給前端,前端發(fā)生請求時穆咐,重新向服務(wù)端請求 html 資源颤诀,路由也由服務(wù)端來控制字旭。

為什么要用Nuxt.js?

現(xiàn)在我們的項目大多數(shù)都是spa(單頁面應(yīng)用)崖叫,感覺單頁面應(yīng)用比之前的模板渲染要好很多遗淳,首先單頁面應(yīng)用是前后端分離,架構(gòu)清晰心傀,前端負(fù)責(zé)交互邏輯屈暗,后端負(fù)責(zé)數(shù)據(jù),前后端單獨(dú)開發(fā)脂男,獨(dú)立測試养叛。
但是,SPA不利于SEO(搜索引擎優(yōu)化)疆液。

那么為什么要做SEO一铅?做SEO有什么好處?簡單來說SEO是一種利用技術(shù)手段提升網(wǎng)站在搜索引擎之中的排名的方式堕油,讓搜索引擎更為信任網(wǎng)站潘飘,通過提升排名獲得更多網(wǎng)站流量。

目前大部分的Vue項目本質(zhì)是 SPA 應(yīng)用掉缺,React卜录、Angular也都是SPA應(yīng)用。SPA應(yīng)用廣泛用于對SEO要求不高的場景中眶明。
在我們開發(fā)的過程中艰毒,我們有 SEO 的需求,我們需要搜索引擎更多地抓取到我們的項目內(nèi)容搜囱,此時我們需要SSR丑瞧。SSR保證用戶盡快看到基本的內(nèi)容,也使得用戶體驗性更好蜀肘。

Nuxt.js 簡介

Nuxt.js 是一個基于 Vue.js 的通用應(yīng)用框架绊汹,Nuxt.js 預(yù)設(shè)了利用 Vue.js開發(fā)服務(wù)端渲染的應(yīng)用所需要的各種配置,并且可以一鍵生成靜態(tài)站點(diǎn)扮宠。同時西乖,Nuxt.js的熱加載機(jī)制可以使開發(fā)者非常便捷的進(jìn)行網(wǎng)站的開發(fā)。

Nuxt.js 于 2016 年 10 月 25 號發(fā)布坛增,上線還不足一年获雕,但是已經(jīng)受到了廣泛的好評,最新的穩(wěn)定版本是 0.10.7收捣,目前仍在進(jìn)行 1.0 版本的內(nèi)測届案,Nuxt.js社區(qū)也在逐步完善中,官網(wǎng)已經(jīng)支持了中文文檔罢艾。

簡單上手

Vue.jsvue-cli 工具可以很方便的讓我們使用現(xiàn)成的模板初始化Vue.js項目楣颠,而 Nuxt.js 團(tuán)隊已經(jīng)為我們提供了初始化 Nuxt.js項目的模板嫁乘,安裝 vue-cli 后,只需在命令行中輸入

vue init nuxt/starter <projectName>

即可完成項目的創(chuàng)建工作球碉,然后進(jìn)入項目目錄中執(zhí)行以下命令:

npm install
npm run dev

Nuxt.js 會使用 3000 端口運(yùn)行服務(wù),在瀏覽器中輸入 http://localhost:3000 就可以看到一個帶有 Nuxt.js 的 logo 的原始的頁面了仓蛆。

項目目錄

完成了一個簡單的 Hello World 項目后睁冬,我們來進(jìn)一步研究 Nuxt.js。進(jìn)入 Nuxt.js 項目后看疙,項目目錄如下:

下面簡要介紹一下各個目錄的作用:

  • .nuxt/:用于存放 Nuxt.js 的核心庫文件豆拨。例如,你可以在這個目錄下找到 server.js 文件能庆,描述了 Nuxt.js 進(jìn)行服務(wù)端渲染的邏輯(參見下一段 “Nuxt.js 的渲染流程”)施禾,router.js 文件包含一張自動生成的路由表。

  • assets/:用于存放靜態(tài)資源搁胆,該目錄下的資源使用 Webpack 構(gòu)建弥搞。

  • components/:存放項目中的各種組件。注意渠旁,只有在這個目錄下的文件才能被稱為組件攀例。

  • layouts/:創(chuàng)建自定義的頁面布局,可以在這個目錄下創(chuàng)建全局頁面的統(tǒng)一布局顾腊,或是錯誤頁布局粤铭。如果需要在布局中渲染 pages 目錄中的路由頁面,需要在布局文件中加上 <nuxt /> 標(biāo)簽杂靶。

  • middleware/:放置自定義的中間件梆惯,會在加載組件之前調(diào)用。

  • pages/:在這個目錄下吗垮,Nuxt.js 會根據(jù)目錄的結(jié)構(gòu)生成 vue-router 路由垛吗,詳見下文。

  • plugins/:可以在這個目錄中放置自定義插件抱既,在根 Vue 對象實例化之前運(yùn)行职烧。例如,可以將項目中的埋點(diǎn)邏輯封裝成一個插件防泵,放置在這個目錄中蚀之,并在 nuxt.config.js 中加載。

  • static/:不使用 Webpack 構(gòu)建的靜態(tài)資源捷泞,會映射到根路徑下足删,如 robots.txt

  • store/:存放 Vuex 狀態(tài)樹。

  • nuxt.config.js:Nuxt.js 的配置文件锁右,詳見下文失受。

Nuxt.js 的渲染流程

Nuxt.js 通過一系列構(gòu)建于 Vue.js之上的方法進(jìn)行服務(wù)端渲染

具體流程如下:

  1. 調(diào)用 nuxtServerInit 方法

    當(dāng)請求打入時讶泰,最先調(diào)用的即是 nuxtServerInit 方法,可以通過這個方法預(yù)先將服務(wù)器的數(shù)據(jù)保存拂到,如已登錄的用戶信息等痪署。另外,這個方法中也可以執(zhí)行異步操作兄旬,并等待數(shù)據(jù)解析后返回狼犯。

  2. Middleware

    經(jīng)過第一步后,請求會進(jìn)入 Middleware 層领铐,在該層中有三步操作:

    • 讀取 nuxt.config.js 中全局 middleware 字段的配置悯森,并調(diào)用相應(yīng)的中間件方法
    • 匹配并加載與請求相對應(yīng)的 layout
    • 調(diào)用 layoutpage 的中間件方法
  3. 調(diào)用 validate 方法

    在這一步可以對請求參數(shù)進(jìn)行校驗,或是對第一步中服務(wù)器下發(fā)的數(shù)據(jù)進(jìn)行校驗绪撵,如果校驗失敗瓢姻,將拋出 404 頁面。

  4. 調(diào)用 fetchasyncData 方法

    這兩個方法都會在組件加載之前被調(diào)用音诈,它們的職責(zé)各有不同幻碱,asyncData 用來異步的進(jìn)行組件數(shù)據(jù)的初始化工作,而 fetch 方法偏重于異步獲取數(shù)據(jù)后修改 Vuex 中的狀態(tài)改艇。

我們在 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 方法調(diào)用完畢后進(jìn)行調(diào)用收班,可以看到,組件從 asyncData 方法中獲取的數(shù)據(jù)會和組件原生的 data 方法獲取的數(shù)據(jù)做一次合并谒兄,最終仍然會在 data 方法中返回摔桦,所以得出,asyncData 方法其實是原生 data 方法的擴(kuò)展承疲。

經(jīng)過以上四步后邻耕,接下來就是渲染組件的工作了,整個過程可以用下圖表示:

如上文所述燕鸽,在 .nuxt 目錄下兄世,你可以找到 server.js 文件,這個文件封裝了 Nuxt.js 在服務(wù)端渲染的邏輯啊研,包括一個完整的 Promise 對象的鏈?zhǔn)秸{(diào)用御滩,從而完成上面描述的整個服務(wù)端渲染的步驟。

Nuxt.js 的一些使用技巧

nuxt.config.js 的配置

nuxt.config.jsNuxt.js的配置文件党远,可以通過針對一系列參數(shù)的設(shè)置來完成 Nuxt.js 項目的配置削解,可以在 Nuxt.js 官網(wǎng) 找到針對這個文件的說明,下面舉例一些常用的配置:

  • head: 可以在這個配置項中配置全局的 head沟娱,如定義網(wǎng)站的標(biāo)題氛驮、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 項目的構(gòu)建規(guī)則矫废,即 Webpack 的構(gòu)建配置盏缤,如通過 vendor 字段引入第三方模塊,通過 plugin 字段配置 Webpack 插件蓖扑,通過 loaders 字段自定義 Webpack 加載器等唉铜。通常我們會在 build 的 vendor 字段中引入 axios 模塊,從而在項目中進(jìn)行 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: 可以在此配置路由的基本規(guī)則,以及進(jìn)行中間件的配置碰声。例如诡蜓,你可以創(chuàng)建一個用來獲取 User-Agent 的中間件,并在此加載胰挑。

  • loading: Nuxt.js 提供了一套頁面內(nèi)加載進(jìn)度指示組件蔓罚,可以在此配置顏色,禁用瞻颂,或是配置自定義的加載組件豺谈。

  • env: 可以在此配置用來在服務(wù)端和客戶端共享的全局變量。

目錄即路由

Nuxt.js 在 vue-router 之上定義了一套自動化的生成規(guī)則贡这,即依據(jù) pages 的目錄結(jié)構(gòu)生成茬末。例如,我們有以下目錄結(jié)構(gòu):

這個目錄下含有一個基礎(chǔ)路由(無參數(shù))以及兩個動態(tài)路由(帶參數(shù))盖矫,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? 參數(shù),表明這是一個可選的路由辈双,如果要將其設(shè)為必選责掏,則必須在 article 的目錄下添加 index.vue 文件。

再看下面一個例子:

由于有同名文件和文件夾的存在湃望,Nuxt.js 會為我們生成嵌套路由换衬,生成的路由結(jié)構(gòu)如下,在使用時证芭,需要增加 <nuxt-child /> 標(biāo)簽來顯示子視圖的內(nèi)容瞳浦。

routes: [
  {
    path: "/article",
    component: _f930b330,
    children: [
      {
        path: "",
        component: _1430822a,
        name: "article"
      },
      {
        path: ":id",
        component: _339e8013,
        name: "article-id"
      }
    ]
  }
]

此外,Nuxt.js 還可以設(shè)置動態(tài)嵌套路由檩帐,具體可參見 Nuxt.js 的官方文檔术幔。

總結(jié)

Nuxt.js 盡管是一個非常年輕的框架,目前也有很多待改進(jìn)的問題湃密,但它的出現(xiàn)為 Vue.js 開發(fā)者搭建服務(wù)端渲染項目提供了巨大的便利诅挑,期待新版本發(fā)布后四敞,能給我們帶來更多實用的新功能

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拔妥,隨后出現(xiàn)的幾起案子忿危,更是在濱河造成了極大的恐慌,老刑警劉巖没龙,帶你破解...
    沈念sama閱讀 212,222評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铺厨,死亡現(xiàn)場離奇詭異,居然都是意外死亡硬纤,警方通過查閱死者的電腦和手機(jī)解滓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來筝家,“玉大人洼裤,你說我怎么就攤上這事∠酰” “怎么了腮鞍?”我有些...
    開封第一講書人閱讀 157,720評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長莹菱。 經(jīng)常有香客問我移国,道長,這世上最難降的妖魔是什么道伟? 我笑而不...
    開封第一講書人閱讀 56,568評論 1 284
  • 正文 為了忘掉前任迹缀,我火速辦了婚禮,結(jié)果婚禮上蜜徽,老公的妹妹穿的比我還像新娘裹芝。我一直安慰自己,他們只是感情好娜汁,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,696評論 6 386
  • 文/花漫 我一把揭開白布嫂易。 她就那樣靜靜地躺著,像睡著了一般掐禁。 火紅的嫁衣襯著肌膚如雪怜械。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,879評論 1 290
  • 那天傅事,我揣著相機(jī)與錄音缕允,去河邊找鬼。 笑死蹭越,一個胖子當(dāng)著我的面吹牛障本,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 39,028評論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼驾霜,長吁一口氣:“原來是場噩夢啊……” “哼案训!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起粪糙,我...
    開封第一講書人閱讀 37,773評論 0 268
  • 序言:老撾萬榮一對情侶失蹤强霎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蓉冈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體城舞,經(jīng)...
    沈念sama閱讀 44,220評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,550評論 2 327
  • 正文 我和宋清朗相戀三年寞酿,在試婚紗的時候發(fā)現(xiàn)自己被綠了家夺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,697評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡伐弹,死狀恐怖秦踪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情掸茅,我是刑警寧澤,帶...
    沈念sama閱讀 34,360評論 4 332
  • 正文 年R本政府宣布柠逞,位于F島的核電站昧狮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏板壮。R本人自食惡果不足惜逗鸣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,002評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绰精。 院中可真熱鬧撒璧,春花似錦、人聲如沸笨使。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽硫椰。三九已至繁调,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間靶草,已是汗流浹背蹄胰。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留奕翔,地道東北人裕寨。 一個月前我還...
    沈念sama閱讀 46,433評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親宾袜。 傳聞我的和親對象是個殘疾皇子捻艳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,587評論 2 350

推薦閱讀更多精彩內(nèi)容