基於NUXT.JS搭建一款VUE版SSR前端框架(解決SPA應用的SEO優化優化問題)

来源:https://www.cnblogs.com/qdjianghao/archive/2023/03/04/17178646.html
-Advertisement-
Play Games

本文檔是從官網文檔中摘錄的一些重點內容,以及加入了自己的一些調整和對官網內容的理解和解釋。適合新手學習,有一定技術水平的寶子,建議直接查看 [NUXT英文官網] ...


小仙男·言在前

關於框架:為瞭解決VUE的SPA單頁應用對SEO搜索引擎優化不友好的問題,這幾天一直在調研各種SSR框架。比如doc.ssr-fc.com/ 和 fmfe.github.io/genesis-do 都是比較不錯,且有自己理念和想法的框架。但是對於公司來說技術規範差異太大,團隊學習成本比較高,思來想去,還是基於NUXT.JS自己搭建一套SSR框架慢慢完善吧。
關於本文檔:本文檔是從官網文檔中摘錄的一些重點內容,以及加入了自己的一些調整和對官網內容的理解和解釋。
關於官網:NUXT中文網 特別適合新手學習,文檔及案例十分清楚詳盡,可以說有手就行。但是,中文網的更新不及時,有些章節(比如fetch鉤子中不能使用this)甚至存在明顯錯誤,所以有一定技術水平的寶子,建議直接查看 NUXT英文官網 。

【一、框架概述】

1、框架介紹

  • SSR 技術(即服務端渲染技術),區別於原先純Vue框架的SPA應用(即單頁應用)。SPA應用只有一個index.html的入口文件,頁面顯示的所有內容均靠客戶端JS進行渲染,對於搜索引擎(SEO)優化來說,整個網站只有一個空頁面,十分不友好。而服務端渲染技術,是藉助node.js作為框架服務端,在初次訪問一個頁面的時候,先在服務端預請求介面,併在服務端組裝完成的html頁面後,返回給客戶端呈現。
  • Nuxt.js是基於Vue框架的一款服務端渲染框架,提供了特有的框架結構和服務端渲染聲明周期。

2、開發環境

  • 本框架基於Node.js+Webpack+vue+Nuxt.js進行開發,提供ElementUI作為UI框架。開發前需全局安裝Node.jswebpack開發環境。
  • 框架推薦Node.js版本為v16.15.0,最低版本不得低於12,推薦安裝nvmn等node版本管理工具。

3、分支要求

  • 遵循[前端團隊git倉庫及版本管理規範],即master分支只用於拉取框架代碼,xxx_dev為開發分支,xxx_test為開發分支,xxx為生產分支。

3、關於本文檔

【二、啟動與部署】

# 安裝框架以來
$ npm install

# 啟動本地開發環境,預設埠號:3000
$ npm run dev

# 編譯併在生產環境啟動
$ npm run build
$ npm run start

# 將網站打包成靜態化頁面
$ npm run generate

【三、框架結構】

-- 框架根目錄
  -- .nuxt        Nuxt運營和編譯自動生成
  -- dist         執行Nuxt靜態化時生成
  -- api          全局通用的Api請求函數(非Nuxt提供)
  -- assets       靜態資源目錄,存放全局css、image等
  -- components   自定義組件目錄,此目錄下組件無需引入,按需使用即可
  -- layout       佈局文件,參考https://www.nuxtjs.cn/guide/views
  -- middleware   中間件,類似於路由守衛
  -- modules      模塊,用於設置全局監聽等,參考https://www.nuxtjs.cn/guide/modules
  -- pages        頁面目錄,Nuxt會根據此目錄自動生成路由,參考https://www.nuxtjs.cn/guide/routing
  -- plugins      插件目錄,自定義各種插件,參考https://www.nuxtjs.cn/guide/plugins
   > global.js    (全局變數與全局方法)
   > plugin.js    (全局引入第三方組件)
   > request.js   (全局請求封裝)
   > filter.js    (全局過濾器封裝)
   > util.js      (全局工具函數封裝)
   > all.client.js(僅在客戶端執行插件,暫時替代原app.vue)
     
  -- static       不需要webpack編譯的靜態文件,一般存放ico等文件
  -- store        Vue狀態樹,與原寫法有所不同,參考https://www.nuxtjs.cn/guide/vuex-store
  -- utils        工具類包 (非Nuxt提供)
  .editorconfig   
  .gitignore
  env.js          環境變數配置,分dev、test、pro三種環境
  nux.config.js   Nuxt的所有配置項,參考https://www.nuxtjs.cn/api/configuration-build
  package-lock.json
  package.json
  README.md       框架使用文檔
  ReleaseNote.md  版本更新說明

【四、生命周期】

-- Nuxt完整聲明周期
  【服務端渲染】
    -- 全局
  nuxtServerInit    第一個:nuxt中第一個運行的生命周期
  RouteMiddleware   第二個:中間件,類似於原框架的路由導航守衛
    -- 組件
  validate          是用來校驗url參數符不符合
  asyncData         Nuxt專屬聲明周期,可用於數據請求,只有page可用,子組件內部不可用
  beforeCreate      Vue聲明周期,但是服務端會執行(不可用於數據請求,數據請求相關操作會在客戶端執行)
  created           Vue聲明周期,但是服務端會執行(同上)
  fetch             Nuxt專屬聲明周期,可用於數據請求, page和子組件都可用 
  
  【客戶端渲染】
    -- 全局
  * `@/plugins/all.client.js` (並非Nuxt聲明周期,是只在客戶端運行的插件。此框架中用於暫時替代原框架中在App.vue中進行的全局初始化操作。)
    -- 組件
  beforeCreate
  created
  beforeMount
  mounted
  ... (其他Vue後續聲明周期)
  

幾點說明:

  1. beforeCreate/created 是Vue的生命周期,但是會在服務端和客戶端各執行一次,但這兩個鉤子,僅供瞭解,不能用於數據請求。
  2. asyncDatafetch都是Nuxt提供的聲明周期,都可用於數據請求。只是寫法略有不同(參考後續章節【五、數據請求】)。
  3. @/plugins/all.client.js 並非Nuxt聲明周期,是只在客戶端運行的插件。但是Nuxt框架去掉了app.vue,此插件的聲明周期,近似於原來的app.vue,故暫時用於替代原框架中在App.vue中進行的全局初始化操作(是否恰當暫時不知)。

【五、數據請求】

1. 數據請求鉤子

1.1 鉤子相關說明

  • asyncDatafetch都是Nuxt提供的聲明周期,都可用於數據請求,都會在服務端預請求數據進行組裝;
  • asyncData只能在pages級別的頁面中調用,在子組件內部不能調用;fetch則可以同時在頁面和子組件中調用;
  • 官方建議數據請求均採用asyncData,但為了保持與老框架寫法的一致,本框架暫時建議採用fetch(後果未知)
  • fetch請求相比於asyncData的已知缺陷有:
    • ① 數據請求較慢,本框架Demo,從index頁進入Detail頁,當使用fetch請求時,可明顯看到瀏覽器選項卡的title出現一瞬間undefined
  • 儘管beforeCreate/created也可以在服務端渲染,但是這兩個鉤子的數據請求操作只會在客戶端執行,非特殊情況,切勿用於頁面初始化。

1.2 asyncData

  • asyncData 中不能訪問this,但是可以在第一參數中,拿到context上下文,使用context.app訪問Vue根示例;
    • context上下文還包含store、route、params、query等數據,詳見context上下文
  • asyncData中無法拿到組件實例,不能訪問組件實例中的data method等方法。
  • 詳細介紹:asyncData
  • 【請求示例】
// ① 使用return返回的對象,將直接初始化到組件`data`中
async asyncData({app, params}) {
    const { code, data } = await app.$get('/policy/findById/'+params.id)
    return {detail: data}
},
// ② return一個Promise,將在Promise執行完成後,將數據初始化到組件`data`中
asyncData({app, params}) {
    return app.$get('/policy/findById/'+params.id).then(res => {
      return {detail: data}
    })
},
// ③ 第二個參數為callback回調函數,可直接傳入數據,初始化到組件`data`中
asyncData({app, params}, callback) {
    app.$get('/policy/findById/'+params.id).then(res => {
      callback(null, {detail: data}) 
    })
},

1.3 fetch

  • fetch 分兩種情況(新版本後支持第二種情況):
    • ① 第一個參數接受context上下文,則與asyncData一樣,不能訪問this和組件實例; (這種情況,也不支持像asyncData一樣通過return或者回調函數修改data內容)
    • ② 不接受任何參數時,則可以正常訪問this。(可以近似的看成created的用法,區別是 必須要使用await 或者return一個primary)
  • 詳細介紹:fetch英文文檔 (中文文檔嚴重延遲,存在錯誤)
  • 【請求示例】
// ① 使用return返回一個Promise
fetch() {
    return this.getDetail()
},
// ②  使用await/async
async fetch() {
    await this.getDetail()
},
methods: {
    // ① 使用await編寫methods方法
    async getDetail(id){
        const { code, data } = await this.$get('/policy/findById/'+this.$route.params.id)
        this.detail = data
    }
    // ② 使用return Promise編寫methods方法
    getDetail(id){
        return this.$get('/policy/findById/'+this.$route.params.id).then(resw => {
          this.detail = res.data
        })
    }
}

2. 數據請求方式

2.1 【框架推薦】 使用vue實例直接調用

  • 本框架會將$request/$get/$post掛在到vue根示例,建議直接只用this或上下文context.app調用
  • 【請求示例】
// 以this調用為例,如果是在`asyncData`中,需要使用上下文`context.app`調用
// ① get
this.$get('/policy/findById/'+this.$route.params.id)
// ②  post
this.$post('/policy/findAll/',{page:1,size:10,params:{}})
// ③  request
this.$request({
    url: '/policy/findAll/',
    method: 'post',
    data: {page:1,size:10,params:{}}
})

2.2 相容老框架的api分離式調用

  • 本框架推薦使用五 2.1的方式調用,但是也相容了老框架的api分離式調用,用於提取可復用的公共請求
  • 公共請求的api文件,統一放在@/api/*.js管理。
  • 【請求示例】
/**
 * @/api/index.js
 */ 
import request from '@/utils/request'
export function getPageList(data) {
    return request.post('/policy/findAll', data)
}
/**
 * @/pages/index.vue
 */ 
import { getPageList } from "@/api/index.js"
export default {
    fetch() {
        return this.getPageList(this.pageDto)
    },
    methods: {
        getPageList(pageDto) {
            return getPageList(pageDto).then(res => {
              this.pageList = res.data.result
            })
        }
    },
}

3. 其他註意事項

  • 原則上,所有初始化渲染數據的請求,都要在服務端渲染函數(asyncDatafetch)中進行,極個別無法在服務端渲染的請求,可以在Vue的生命周期(createdmounted)中初始化;
  • 服務端渲染的生命周期(即asyncData/fetch),不能使用任何瀏覽器專屬的對像(如DOM對象),也就是documentwindow,以及window的各種對象和方法,例如setTimeoutsetIntervallocalStoragesessionStorage等;
    有上述需求的初始化邏輯,可以放到createdmounted中初始化。

【六、其他規範與Q&A】

1. 關於pages

  • 本框架路由採用約定式路由,即不再使用route.js進行路由聲明,而是由框架根據pages目錄自動生成路由,詳見路由
  • 文件夾或者文件,如果以_開頭,表示此為動態路由,可以傳入不同參數,在組件內容,可以使用上下文或者this.$router取到路由參數;
    • 例如: /pages/news/detail/_id.vue/pages/news/detail/_id/index.vue
    • 訪問: http://domain.com/pages/news/detail/12345 (上述兩種寫法均為這一路徑)

【註意】

  • ① 使用_id.vue的寫法,表示id為可選參數,即可以通過http://domain.com/pages/news/detail訪問。如果要對id進行限制或驗證,可以在組件內使用validate()驗證;
  • ② 使用/_id/index.vue的寫法,表示id為必選參數,訪問http://domain.com/pages/news/detail會報404。如果只要求id必填,而沒有其他格式限制,可以使用此方式。
  • validate()驗證示例
// return true表示驗證通過,return false表示驗證失敗 404
validate({ params }) {
    return /^\d+$/.test(params.id)
},

2. 關於plugins

  • 用於自定義框架所需的各種插件,聲明插件後在nuxt.config.js中引入插件即可,類似於原框架main.js相關功能。詳見插件
  • 框架已有的插件包(具體用戶參照各插件的頂部註釋):
    • plugin.js用於全局引入各種npm包;
    • global.js用於聲明全局變數與全局方法;
    • request.js實現了全局請求封裝(對應@/utils/request.js);
    • filter.js實現了全局請求封裝(對應@/utils/filter.js);
    • util.js實現了全局請求封裝(對應@/utils/util.js);
    • all.client.js只在客戶端引入,用於替代原框架中app.vue中的各種初始化操作;
  • 其他插件可根據需要自行定義,*.js表示服務端客戶端均導入;*.client.js表示僅在客戶端導入;*.server.js表示只在服務端導入;

3. 關於layout

  • 用於定義框架中的各種佈局文件,可根據需要自行定義,詳見佈局與視圖
  • 預設視圖為default.vue,預設所有頁面都將調用;error.vue是錯誤視圖,當頁面出現問題時,自動調用;
  • 其他視圖,可根據需要自行定義,併在組件內部聲明引用。
  • 【組件調用示例】
export default {
    // 需要調用的視圖名稱,不寫預設調用default.vue
    layout: 'onlyBody',
    data(){
      return {}
    }
}

4. 關於components

  • 用於定義框架中的各種自定義組件,可根據需要自行定義。
  • 自定義組件中的數據,一般應從頁面傳入,如果需要再組件內部獲取數據,應該使用fetch(子組件中不支持asyncData)。
  • components中聲明的各種組件,在使用時,無需import導入。直接使用組件名按需調用即可。
  • 【使用示例】
<template>
  <div>
    // Header組件
    <Header />
  </div>
</template>

5. 關於store

  • store文件夾為Nuxt提供用於定義Vuex狀態樹的文件夾,詳細文檔參照:Vuex狀態樹
  • 此文件夾下麵的xxx.js,分別表示一個模塊,例如index.js對應$store.state.xxx,而user.js對應$store.state.user.xxx
  • 本框架中store中模塊的定義與普通Vue框架大體相同,只是Nuxt框架會自動引用Vuex並載入到構建配置重,無需我們自己new Vuex()
  • 【使用示例】
/**
 * 【註意區別】
 * state mutations action不再是包裹在一個對象中,併在new Vuex()的時候傳入。 而是分別作為單獨模塊使用export導出即可。
 */
export const state = () => ({
    counter: 0
})
export const mutations = {
    increment(state) {
        state.counter++
    }
}

6. 關於middleware

  • middleware是框架中用於聲明中間件的文件夾,聲明後在nuxt.config.js中配置中間件即可,詳細文檔參照:中間件
  • @/middleware/router.js為已經升級聲明好的路由守衛中間件,可替代原框架中router.beforeEach中的路由守衛功能;

7. 關於modules

  • 用於自定義模塊的文件夾,可以在模塊中對Nuxt啟動部署的各種聲明周期設置監聽,詳細文檔參照:模塊
  • @/modules/generator.ts實現了一個對靜態化結束generate:done時進行監聽並處理的示例。
const generator: any = function () {
    this.nuxt.hook('generate:done', (context: any) => {
        // TODO samething
    })
}
export default generator
  • 類似this.nuxt.hook('generate:done',() => {})的Nuxt框架hooks還有很多,例如:readyerrorrender:beforebuild:compile 等等……詳細參見INTERNALS

8. 其他Q&A

1)每個頁面,必須使用head設置title,必要時還需在詳情頁設置description。(!!!切記!!!)

export default {
    head() {
        return {
            // title必須設置!!! 列表可以直接寫“xxx列表”,詳情頁等有不同標題的,要用新聞標題、商品標題等作為title首碼。
            title: this.detail.title + '_新聞詳情',
            meta: [
                // 詳情頁,需要設置不同的description。 this.$getDesc 為全局封裝的從富文本中截取100字元的description
                { hid: 'description', name: 'description', content: this.$getDesc(this.detail.details) },
            ],
        }
    }
}

2)pages目錄中的層級結構,務必按照功能梳理清楚,比如“news(新聞)”的列表、詳情都要在一個文件夾中。

(!!!目錄結構一旦確定,原則上不可再調整!!!)

3)框架中的其他重要文件之【CSS篇】!!

  • 框架各種css文件,位於@/assets/css/中。框架推薦使用scss語言,使用"sass": "~1.32.13"進行編譯;
  • common.scss 為全局公共CSS,請將全局樣式表聲明於此。或自行定義CSS文件,併在此文件中import導入;
  • font.scss 用於定義本框架各種字體、圖標庫等;
  • variables.scss 聲明瞭框架的各種全局Scss變數,可以在所有頁面使用。
    • 註意:全局主題色,請用$mainColor表示,不要在各自文件中自行聲明!
  • element-variables.scss 是ElementUI的主題聲明文件,如需全局調整ElementUI的配色,請在此調整;

4)(未完待續…)其他任何框架問題,詳詢小仙男

【本文作者】@小風飛魚
【原文出處】http://www.cnblogs.com/qdjianghao/
【版權聲明】本文版權歸原作者@小風飛魚所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
【聯繫方式】1987289469

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 原文:What is a Shell? 註意:本文是對原文的一個翻譯! Shell是一個巨集處理器,用於執行命令。巨集處理器意味著,將文本和符號展開,創建一個更大的表達式。 Unix shell 既是一個命令解釋器,也是一門編程語言。作為一個命令解釋器,它提供了豐富的GUN工具集可以與用戶進行交互。作為 ...
  • 前言 本文展示了一個比較完整的企業項目級別的Makefile文件,包括了:文件調用,源文件、頭文件、庫文件指定,軟體版本號、巨集定義,編譯時間,自動目錄等內容。 1、目錄架構 本文中所採用的目錄架構,在企業項目開發中十分常見:源文件都放在src目錄中,頭文件都放在inc目錄中,並且這兩個目錄都可以有對 ...
  • 1602LCD 是工業上常用的模塊, 在工廠交通運輸設備上經常能見到. 驅動晶元為 HD44780, 1602LCD 的字元顯示為兩行, 每行16個字元, 字元基於5×8的像素矩陣 ...
  • 1、工作應用場景 統計得到每個小時的UV、PV、IP的個數,構建如下表結構: 但是表中數據的存儲格式不利於直接查詢展示,需要進行調整:(以時間分區,去重、聚合等……對結果進行行列轉換) 2、行轉列 (1)多行轉多列 case when函數 功能:用於實現對數據的判斷,根據條件,不同的情況返回不同的結 ...
  • 1、全局排序(Order by) 功能:全局排序,只有1個reducer(用1個Reduce Task完成全局排序,與設置的Reduce Task個數無關) 參數:ASC:升序(預設) DESC:降序 使用:order by放在select語句的結尾 例如: --查詢員工信息按工資降序排列 sele ...
  • 前言 本文是關於使用flutter_download_manager下載功能的實踐和探索。我們將基於flutter_download_manager的功能擴展,改造成自己想要的樣子。在閱讀本文之前,建議先瞭解前兩篇文章: Flutter 下載篇 - 壹 | flutter_download_mana ...
  • 需求背景 繼上篇《Flutter 下載篇 - 壹 | flutter_download_manager 源碼解析》中詳細介紹了 flutter_download_manager 用法和原理。在優缺點中提到,該庫純 Dart 實現,支持下載管理,暫停,恢復,取消和斷點續傳。其中有個缺點是網路庫與 di ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 在開發管理後臺過程中,一定會遇到不少了增刪改查頁面,而這些頁面的邏輯大多都是相同的,如獲取列表數據,分頁,篩選功能這些基本功能。而不同的是呈現出來的數據項。還有一些操作按鈕。 對於剛開始只有 1,2 個頁面的時候大多數開發者可能會直 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...