NUXT SSR初級入門筆記

WanFengZ發表於2019-12-14

nuxt 是基於 vue 開發的一個應用框架,最常用的就是拿來做 ssr。那麼什麼是 ssr 呢,這就要提及一個相對的概念:csr。

CSR & SSR

web網頁開發從之前的 jsp,php 轉向現在的三大框架 angular react vue,其實就是從 csr 到 ssr 的轉變,即從服務端渲染轉而變為客戶端渲染。

有使用經驗的大概知道,例如之前的 php 開發,是將網頁內容和服務端程式碼邏輯寫在一起的,在客戶端請求時,服務端經過 php 引擎的渲染生成完整的 html 頁面再返回給客戶端,這種渲染出的頁面在瀏覽器中右鍵檢視原始碼都是能看見 頁面全部的 html 程式碼的。而客戶端渲染如 vue,返回的就只有一個掛在 app 節點的 html檔案和一個 js 檔案,頁面的內容都是在客戶端的 js 渲染生成的。所以渲染 html 文字所在的位置就是 CSR(客戶端渲染) 和 SSR(服務端渲染) 最本質的區分

既然web開發從 ssr 過渡到了 csr,那我們為什麼又再去做 ssr 呢,這就要涉及到雙方的優缺了:

SSR:

優點:

  1. 便於 SEO,渲染完整的 html 更利於搜尋引擎的抓取。

  2. 頁面載入的白屏時間短(幾乎沒有)。

缺點:

  1. 每載入一個頁面都要對伺服器發起一次請求,伺服器的渲染負荷重,請求緩慢。

  2. 每次載入都會重新整理頁面,即使只是頁面中的小區域需要改變。

CSR:

優點:

  1. 頁面具有優秀的效能,更利於頁面互動。

缺點:

  1. 不利於SEO

  2. 首頁初始化載入白屏時間長。

在我們普遍使用三大框架的今天,如果我們的頁面需要對 SEO 的良好支援,這就需要我們做 ssr 了。

NUXT 專案的初始化

使用以下命令呼叫腳手架生成專案,腳手架選項按需選擇就可以了:

npx create-nuxt-app <專案名>
複製程式碼

生成的目錄結構如下:

NUXT SSR初級入門筆記

.nuxt

執行快取目錄

assets

資源目錄,用於存放如 css 檔案,js 檔案,圖片

components

元件目錄,用於存放 vue 元件

layouts

佈局目錄,用於設定佈局,檔名即為佈局名

在 pages 目錄裡的元件可以通過 layout 屬性指定佈局元件,不指定預設為 default。

佈局元件中使用 <nuxt /> 標籤指定應用佈局時,page 元件所在的位置。

middleware

中介軟體目錄,用於設定中介軟體函式,檔名即為中介軟體名

在 pages 目錄裡的元件可以通過 middleware 屬性指定中介軟體函式,中介軟體會在元件渲染前執行

pages

頁面目錄,用於設定路由頁面,目錄下的 vue 檔案會自動生成相應的路由配置

如以下目錄結構對應的配置:

pages/
--| _slug/
-----| comments.vue
-----| index.vue
--| users/
-----| _id.vue
--| index.vue

router: {
  routes: [
    {
      name: 'index',
      path: '/',
      component: 'pages/index.vue'
    },
    {
      name: 'users-id',
      path: '/users/:id?',
      component: 'pages/users/_id.vue'
    },
    {
      name: 'slug',
      path: '/:slug',
      component: 'pages/_slug/index.vue'
    },
    {
      name: 'slug-comments',
      path: '/:slug/comments',
      component: 'pages/_slug/comments.vue'
    }
  ]
}
複製程式碼

nuxt 中使用 <nuxt-link> 代替了<router-link>

nuxt 會為 page 元件提供額外的配置項,常用到的如下:

layout 指定當前頁面使用的佈局(layouts 根目錄下的佈局檔案)。

validate 校驗方法用於校驗動態路由的引數。

middleware 指定頁面的中介軟體函式,中介軟體函式會在頁面渲染之前被呼叫,也可以指定為middleware資料夾內的中介軟體名。

asyncData 支援非同步資料處理,拿來為 page 元件請求非同步資料,返回物件中的 data 會覆蓋到元件的 data 中。

fetch 用於在渲染頁面之前獲取資料填充應用的狀態樹(store)。不同的是 fetch 方法不會設定元件的資料。

plugins

外掛目錄,用於引入第三方模組,

如 element-ui.js:

import Vue from 'vue'
import Element from 'element-ui'
import locale from 'element-ui/lib/locale/lang/en'

Vue.use(Element, { locale })
複製程式碼

然後可以在 nuxt.config.js 中的 plugins 中引入:

plugins: [
    '@/plugins/element-ui'
  ],
複製程式碼

server

服務端目錄

static

靜態檔案目錄

store

vuex目錄,index.js 為主檔案,其他檔案預設會配置成 module 模組,預設啟用 namespace。

檔案形式為:

export const state = () => ({
    // state
})

export const actions = {
    // actions
}

export const mutations = {
    // mutations
}
複製程式碼

在 index.js 的 actions 中可以配置 nuxtServerInit,可以用來將資料從服務端傳到客戶端。

具體使用

建立專案如下:

NUXT SSR初級入門筆記

執行初始專案,效果如下:

NUXT SSR初級入門筆記

使用佈局

在 layouts 下新建檔案 myLayout.vue

<template>
  <div>
    <header>
      <h2>I am header</h2>
    </header>
    <main>
      <nuxt />
    </main>
    <footer>
      <h2>I am footer</h2>
    </footer>
  </div>
</template>
複製程式碼

然後我們在 pages 下新建檔案 layoutDemo.vue

<template>
  <div>
    <h1>I am layout demo</h1>
  </div>
</template>

<script>
export default {
  layout: 'myLayout'
}
</script>
複製程式碼

訪問 localhost:3000/layoutDemo,佈局效果如下:

NUXT SSR初級入門筆記

使用中介軟體

例如我們實現一個未登入攔截跳轉的中介軟體:

在 middleware 中新建 auth.js

export default function (ctx) {
  // eslint-disable-next-line no-constant-condition
  if (true) { // ctx 判斷得到未登入
    ctx.redirect({ path: '/' })
  }
}
複製程式碼

再在 layoutDemo.vue 中加上 middleware: 'auth',這樣訪問該頁面就會攔截跳轉回主頁面。

用 asyncData 實現 ssr

我們再在 pages 中新建頁面 ssr1.vue

<template>
  <div>
    <ul>
      <li v-for="item of list1" :key="item">
        {{ item }}
      </li>
    </ul>
    <ul style="margin-top: 50px">
      <li v-for="item of list2" :key="item">
        {{ item }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  layout: 'myLayout',
  data () {
    return {
      list1: []
    }
  },
  async created () {
    const { status, data: { list } } = await this.$axios.get('/list')
    if (status === 200) {
      this.list = list
    }
  },
  async asyncDate () {
    const { status, data: { list } } = await this.$axios.get('/list')
    if (status === 200) {
      return {
        list2: list
      }
    }
  }
}
</script>
複製程式碼

這裡我們 list1 是用傳統的 vue 方式獲取非同步資料, list2 用 asyncData 獲取非同步資料

然後我們在 server 中寫介面,應為 node 還是採用 require 的方式,如果我們想使用 import 的方式,可以安裝 babel-cli 和 babel-preset-env , 新建配置檔案 .babelrc:

{
  "presets": ["env"]
}
複製程式碼

然後在 package.json 裡將 dev 命令加上字尾 --exec babel-node, server 中書寫 node 就可以使用 import 了。

然後安裝 koa-router,在 index.js 里加入以下程式碼:

import Router from 'koa-router'

// 以下程式碼加在 start 函式內的 原有的 app.use 之前
const router = new Router()
router.get('/list', (ctx) => {
ctx.body = {
  list: ['a', 'b', 'c']
}
})
app.use(router.routes()).use(router.allowedMethods())
複製程式碼

然後訪問頁面,兩個列表都正常渲染

NUXT SSR初級入門筆記

我們右鍵檢視原始碼:

NUXT SSR初級入門筆記

list2 通過 asyncData 的方式實現了 ssr。

使用 nuxtServerInit 實現 ssr

我們新建頁面 ssr2.vue

<template>
  <div>
    <ul>
      <li v-for="item of $store.state.list" :key="item">
        {{ item }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  layout: 'myLayout'
}
</script>
複製程式碼

然後在 store 中新建 index.js

export const state = () => ({
  list: []
})

export const mutations = {
  setList (state, value) {
    state.list = value
  }
}

export const actions = {
  async nuxtServerInit ({ commit }, { app }) {
    const { status, data: { list } } = await this.$axios.get('/list')
    if (status === 200) {
      commit('setList', list)
    }
  }
}
複製程式碼

重新 npm run dev, 訪問 localhost:3000/ssr2

NUXT SSR初級入門筆記

檢視原始碼,也正確渲染

NUXT SSR初級入門筆記

相關文章