使用Nuxt.js框架開發(SSR)服務端渲染項目

(SSR)服務端渲染的優缺點

優勢:

1.前端耗時少,首屏加載速度快。由於後端拼接完了html,瀏覽器只須要直接渲染出來。html

2.有利於SEO。由於在後端有完整的html頁面,因此爬蟲更容易爬取得到信息,更有利於seo。前端

3.無需佔用客戶端資源。即解析模板的工做徹底交由後端來作,客戶端只要解析標準的html頁面便可,這樣對於客戶端的資源佔用更少,尤爲是移動端,也能夠更省電。vue

4.後端生成靜態化文件。即生成緩存片斷,這樣就能夠減小數據庫查詢浪費的時間了,且對於數據變化不大的頁面很是高效 。node

缺點:

1.不利於先後端分離,開發效率低。(無框架前)webpack

2.佔用服務器端資源。ios

即服務器端完成html模板的解析,若是請求較多,會對服務器形成必定的訪問壓力。而若是使用前端渲染,就是把這些解析的壓力分攤了前端,而這裏確實徹底交給了一個服務器。git

# Nuxt.js起源

2016 年 10 月 25 日, zeit.co 背後的團隊對外發布了 Next.js ,一個 React 的服務端渲染應用框架。幾小時後,與 Next.js 殊途同歸,一個基於 Vue.js 的服務端渲染應用框架應運而生,咱們稱之爲:Nuxt.js。github

Nuxt 是服務器呈現的簡約應用程序的框架,經過對客戶端和服務端基礎架構的抽象,Nuxt.js 可讓開發者更專一於頁面的UI渲染。做用就是在 node.js 上進一步封裝,而後省去咱們搭建服務端環境的步驟,只須要遵循這個庫的一些規則就能輕鬆實現 SSR。web

做用及特性

  • 經過對客戶端/服務端基礎架構的抽象組織,Nuxt.js 主要關注的是應用的 UI 渲染
  • Nuxt.js 預設了利用 Vue.js 開發服務端渲染的應用所須要的各類配置。
  • 支持 Vue.js 應用的靜態化,經過 nuxt generate 命令實現。
  • 基於 Vue.js
  • 自動代碼分層
  • 服務端渲染
  • 強大的路由功能,支持異步數據
  • 靜態文件服務
  • ES2015+ 語法支持
  • 打包和壓縮 JS 和 CSS
  • HTML 頭部標籤管理
  • 本地開發支持熱加載
  • 集成 ESLint
  • 支持各類樣式預處理器:SASS、LESS、Stylus 等等
  • 支持 HTTP/2 推送

核心原理

圖片

Nuxt.js 集成了如下組件/框架,用於開發完整而強大的 Web 應用:vue-router

壓縮並 gzip 後,總代碼大小爲:57kb (若是使用了 Vuex 特性的話爲 60kb)。

另外,Nuxt.js 使用 Webpack 和 vue-loader 、 babel-loader 來處理代碼的自動化構建工做(如打包、代碼分層、壓縮等等)。

work flow:

圖片

安裝(略)

詳見 zh.nuxtjs.org/guide/insta…

目錄結構

├── assets           //用於組織未編譯的靜態資源如 LESS、SASS 或 JavaScript
│   └── README.md
├── components       //用於組織應用的 Vue.js 組件。Nuxt.js 不會擴展加強該目錄下 Vue.js 組件,即這些組件不會像頁面組件那樣有 asyncData 方法的特性
├── layouts    //佈局目錄 layouts 用於組織應用的佈局組件。若無額外配置,該目錄不能被重命名。
│   ├── README.md
│   └── default.vue
├── middleware    //目錄用於存放應用的中間件
│   └── README.md
├── nuxt.config.js  //nuxt 配置文件
├── pages           //放page頁面,自動生產路由
│   ├── README.md
│   ├── index.vue
│ 
├── plugins    //用於組織那些須要在 根vue.js應用 實例化以前須要運行的 插件
│   ├── README.md
│   └── axios.js
├── server                
│   └── index.js           //服務配置
├── static           
│   ├── README.md     //存放靜態文件,不被編譯
│   ├── favicon.ico
│   ├── icon.png
│   └── sw.js
├── store                 //vuex狀態
│   ├── README.md
│   ├── index.js
│   └── webLogin.js
複製代碼

經常使用 API

生命週期

Nuxt擴展了Vue的生命週期

export default {
  middleware (ctx) {}, //服務端
  validate (ctx) {}, // 服務端
  asyncData (ctx) {}, //服務端
  fetch (ctx) {}, // store數據加載
  beforeCreate () {  // 服務端和客戶端都會執行},
  created () { // 服務端和客戶端都會執行 },
  beforeMount () {}, 
  mounted () {} // 客戶端
}
複製代碼

context 對象

context 的可用屬性一覽:

屬性字段 類型 可用 描述
app Vue 根實例 客戶端 & 服務端 包含全部插件的 Vue 根實例。例如:在使用 axios 的時候,你想獲取 axios 能夠直接經過 context.app.axios 來獲取
isClient Boolean 客戶端 & 服務端 是否來自客戶端渲染(廢棄。請使用 process.client )
isServer Boolean 客戶端 & 服務端 是否來自服務端渲染(廢棄。請使用 process.server )
isStatic Boolean 客戶端 & 服務端 是否來自 nuxt generate 靜態化(預渲染)(廢棄。請使用 process.static )
isDev Boolean 客戶端 & 服務端 是不是開發 dev 模式,在生產環境的數據緩存中用到
isHMR Boolean 客戶端 & 服務端 是不是經過模塊熱替換 webpack hot module replacement (僅在客戶端以 dev 模式)
route Vue Router 路由 客戶端 & 服務端 Vue Router 路由實例
store Vuex 數據 客戶端 & 服務端 Vuex.Store 實例。只有vuex 數據流存在相關配置時可用
env Object 客戶端 & 服務端 nuxt.config.js 中配置的環境變量,見 環境變量 api
params Object 客戶端 & 服務端 route.params 的別名
query Object 客戶端 & 服務端 route.query 的別名
req http.Request 服務端 Node.js API 的 Request 對象。若是 Nuxt 以中間件形式使用的話,這個對象就根據你所使用的框架而定。nuxt generate 不可用
res http.Response 服務端 Node.js API 的 Response 對象。若是 Nuxt 以中間件形式使用的話,這個對象就根據你所使用的框架而定。nuxt generate 不可用
redirect Function 客戶端 & 服務端 用這個方法重定向用戶請求到另外一個路由。狀態碼在服務端被使用,默認 302 redirect([status,] path [, query])
error Function 客戶端 & 服務端 用這個方法展現錯誤頁:error(params) 。params 參數應該包含 statusCode 和 message 字段
nuxtState Object 客戶端 Nuxt 狀態,在使用 beforeNuxtRender 以前,用於客戶端獲取 Nuxt 狀態,僅在 universal 模式下可用
beforeNuxtRender(fn) Function 服務端 使用此方法更新 NUXT 在客戶端呈現的變量,fn 調用 (能夠是異步) { Components, nuxtState } ,參考 示例

asyncData 函數

  • **類型:**Function

asyncData 方法會在組件(限於頁面組件)每次加載以前被調用。它能夠在服務端或路由更新以前被調用。在這個方法被調用的時候,第一個參數被設定爲當前頁面的上下文對象,你能夠利用 asyncData 方法來獲取數據並返回給當前組件。

export default {
  data () {
    return { project: 'default' }
  },
  asyncData (context) {
    return { project: 'nuxt' }
  }
}
複製代碼

注意:因爲 asyncData 方法是在組件 初始化 前被調用的,因此在方法內是沒有辦法經過 this 來引用組件的實例對象。

fetch 函數

fetch 方法用於在渲染頁面前填充應用的狀態樹(store)數據, 與 asyncData 方法相似,不一樣的是它不會設置組件的數據。

  • **類型:**Function

若是頁面組件設置了 fetch 方法,它會在組件每次加載前被調用(在服務端或切換至目標路由以前)。

fetch 方法的第一個參數是頁面組件的 上下文對象 context,咱們能夠用 fetch 方法來獲取數據填充應用的vuex狀態樹。爲了讓獲取過程能夠異步,你須要返回一個 Promise,Nuxt.js 會等這個 promise 完成後再渲染組件。

警告: 您沒法在內部使用 this 獲取組件實例,fetch 是在組件初始化以前被調用

例如 pages/index.vue:

<template>
  <h1>Stars: {{ $store.state.stars }}</h1>
</template>
<script>
export default {
  fetch ({ store, params }) {
    return axios.get('http://my-api/stars')
    .then((res) => {
      store.commit('setStars', res.data)
    })
  }
}
</script>
你也可使用 async 或 await 的模式簡化代碼以下:
<template>
  <h1>Stars: {{ $store.state.stars }}</h1>
</template>
<script>
export default {
  async fetch ({ store, params }) {
    let { data } = await axios.get('http://my-api/stars')
    store.commit('setStars', data)
  }
}
</script>
複製代碼

若是要在 fetch 中調用並操做 store,請使用 store.dispatch,可是要確保在內部使用 async / await 等待操做結束:

<script>
export default {
  async fetch ({ store, params }) {
    await store.dispatch('GET_STARS');
  }
}
</script>
store/index.js
// ...
export const actions = {
  async GET_STARS ({ commit }) {
    const { data } = await axios.get('http://my-api/stars')
    commit('SET_STARS', data)
  }
}
複製代碼

監聽 query 字符串的改變 默認狀況下,不會在查詢字符串更改時調用 fetch 方法。若是想更改此行爲,例如,在編寫分頁組件時,您能夠設置經過頁面組件的 watchQuery 屬性來監聽參數的變化。瞭解更多有關 API watchQuery page 的信息。

增長用戶體驗的兩個插件

@nuxtjs/toast模塊

toast能夠說是很經常使用的功能,通常的UI框架都會有這個功能。但若是你的站點沒有使用UI框架,而alert又太醜,不妨引入該模塊:

npm install @nuxtjs/toast
複製代碼

而後在nuxt.config.js中引入

module.exports = {
    modules: [
    '@nuxtjs/toast',
    ['@nuxtjs/dotenv', { filename: '.env.prod' }] // 指定打包時使用的dotenv
  ],
  toast: {// toast模塊的配置
    position: 'top-center', 
    duration: 2000
  }
}
複製代碼

這樣,nuxt就會在全局註冊$toast方法供你使用,很是方便:

this.$toast.error('服務器開小差啦~~')
this.$toast.error('請求成功~~')
複製代碼

loading方法

nuxt內置了頁面頂部loading進度條的樣式 推薦使用,提供頁面跳轉體驗。

//打開
this.$nuxt.$loading.start() 
//完成 
this.$nuxt.$loading.finish()
複製代碼

更多 API 詳見官網 zh.nuxtjs.org/api

源碼淺析

源碼地址:github.com/nuxt/nuxt.j…

源碼目錄:

圖片

一、經過 .nuxt 文件來執行咱們的工做流程

圖片

這個是咱們項目生成的臨時文件,咱們項目運行時候配置的文件都是在這裏,你們能夠看到這裏的路由文件,沒錯,這個就是系統自動給咱們配置的路由文件,根據咱們的 pages 文件夾路徑生成的,你們還能夠看到,由app.js ,client.js 和 server.js 這兩個就是相似咱們的 SSR 中配置的那個 server.js 入口文件,而後還有 middleware.js 中間件文件,其實這個時候咱們大概能懂了,上邊咱們說的工做流程,走的就是這個 臨時文件.nuxt 文件夾中的內容,可是這個文件夾是如何生成的呢,你們請往下看。

二、.nuxt 是如何產生的

本文主要研究nuxt的運行原理,分析它從接收一條nuxt指令,到完成指令背後所發生的一系列事情,在開始本文以前,請讀者務必親自體驗過nuxt.js的使用,而且具有必定的vue.js相關開發經驗。

經過查看nuxt.js工程目錄下的package.json文件,咱們能夠看到下列幾條指令:

"scripts": { "dev": "nuxt",           // 開啓一個監聽3000端口的服務器,同時提供hot-reloading功能
    "build": "nuxt build", //構建整個應用,壓縮合並JS和CSS文件(用於生產環境)
    "start": "nuxt start", // 開啓一個生產模式的服務器(必須先運行nuxt build命令)
    "generate": "nuxt generate" //構建整個應用,併爲每個路由生成一個靜態頁面(用於靜態服務器)
} 
複製代碼

我們還歷來沒有看過咱們的依賴包哈,今天就來看看,打開咱們的 node_modules 文件夾下的 nuxt工程文件夾 進入到到bin目錄,咱們能夠看到幾個文件:

圖片

我們就說一下 dev 是如何工做的,我們先找到一個片斷,發現基本是執行了如下幾個步驟:

async run (cmd) {
    const { argv } = cmd
    await this.startDev(cmd, argv, argv.open)
  },

  async startDev (cmd, argv) {
    let nuxt
    try {
      nuxt = await this._listenDev(cmd, argv)
    } catch (error) {
      consola.fatal(error)
      return
    }
    try {
      await this._buildDev(cmd, argv, nuxt)
    } catch (error) {
      await nuxt.callHook('cli:buildError', error)
      consola.error(error)
    }
    return nuxt
  },
複製代碼

圖片

那什麼是 nuxt() 類,它又是執行了什麼樣的方法呢?

圖片

上圖中每一步均可以在具體的代碼中自行瀏覽。在用戶輸入指令並實例化了Nuxt()類之後,實例化

同時,Nuxt()類也提供了一個close()公有方法,用於關閉其所開啓的服務器。

三、builder.build() 進行編譯

圖片

簡單來講,build()方法在判斷完運行條件後,會先初始化產出目錄.nuxt,而後經過不一樣目錄下的文件結構來生成一系列的配置,寫入模板文件後輸出到.nuxt目錄。接下來,則會根據不一樣的開發環境來調用不一樣的webpack配置,運行不一樣的webpack構建方案。

四、render.js文件 打包輸出渲染

在nuxt/lib目錄下找到render.js文件,它包含着咱們即將要分析的三個方法:render(), renderRoute(), renderAndGetWindow()。

圖片

經過這張圖片,咱們能夠知道nuxt對於處理「客戶端渲染」與「服務端渲染」的邏輯實際上是很是清晰的。

  • 首先,在render()方法在處理完一系列的路徑問題後,會調用renderRoute()方法,獲取響應所需內容並完成響應。
  • 其中renderRoute()方法會判斷當前響應是否應執行服務端渲染。若是是,則調用vue提供的bundleRenderer()方法,把html內容渲染完畢之後再總體輸出;若是不是,則直接輸出一個
    字符串,交由客戶端渲染。
  • 最後,經過renderAndGetWindow()來檢查輸出的html是否存在問題,而後發出通知,代表html可用。

打包部署

上傳所有代碼到本身到服務器上執行 編譯打包:

npm run build
npm run start
複製代碼

建議部署方式Docker+K8S

------------------------------------我的項目-----------------------------------

項目介紹

  • 項目地址:www.ffbig.cn/ 項目來源於博主本身的職業生涯技能總結和梳理,內容在不斷充實中。 全棧大前端系列總共分爲 3 期:
  • 1 期梳理基礎知識和經常使用技術棧
  • 2 期學習跨端融合技術認識"大前端"
  • 3 期結合服務端技術通曉 "全棧"

項目大綱

若是你發現本項目有內容上的錯誤,歡迎提交 issues 進行指正。

學習交流

建了一個「全棧大前端」的微信交流羣,歡迎純粹技術交流愛好者加入!

相關文章
相關標籤/搜索