目錄
一、SSR是什麼
#傳統web開發
SSR主要解決了以下兩種問題:
對於同構開發,我們依然使用webpack打包,我們要解決兩個問題:服務端首屏渲染和客戶端啟動
首頁 web前端 Vue.js 什麼是SSR? vue中怎麼實作SSR服務端渲染?

什麼是SSR? vue中怎麼實作SSR服務端渲染?

Feb 25, 2022 am 11:23 AM
ssr vue

什麼是SSR?以下這篇文章跟大家介紹一下在vue中實作SSR服務端渲染的方法,希望對大家有幫助!

什麼是SSR? vue中怎麼實作SSR服務端渲染?

一、SSR是什麼

#Server-Side Rendering 我們稱之為SSR ,意為服務端渲染

指由服務側完成頁面的 HTML 結構拼接的頁面處理技術,傳送到瀏覽器,然後為其綁定狀態與事件,成為完全可互動頁面的過程。 【相關推薦:vuejs影片教學

先來看看Web3個階段的發展史:

  • 傳統服務端渲染SSR
  • 單頁應用SPA
  • 服務端渲染SSR

#傳統web開發

##網頁內容在服務端渲染完成,⼀次性傳輸到瀏覽器

什麼是SSR? vue中怎麼實作SSR服務端渲染?

開啟頁面查看原始碼,瀏覽器拿到的是全部的

dom#結構

單頁應用SPA

單頁應用優秀的使用者體驗,使其逐漸成為主流,頁面內容由

JS渲染出來,這種方式稱為客戶端渲染

什麼是SSR? vue中怎麼實作SSR服務端渲染?

開啟頁面查看源碼,瀏覽器拿到的僅有宿主元素

#app,並沒有內容

服務端渲染SSR

SSR解決方案,後端渲染出完整的首屏的dom結構返回,前端拿到的內容包含首屏及完整spa結構,應用激活後依然按照spa方式運行

什麼是SSR? vue中怎麼實作SSR服務端渲染?##看完前端發展,我們再看看

Vue

官方對SSR的解釋:

Vue.js 是建立客戶端應用程式的框架。預設情況下,可以在瀏覽器中輸出 Vue 元件,進行產生 DOM 和操作 DOM。然而,也可以將同一個元件渲染為伺服器端的HTML 字串,將它們直接傳送到瀏覽器,最後將這些靜態標記"激活"為客戶端上完全可交互的應用程式

伺服器渲染的Vue.js 應用程式也可以被認為是"同構"或"通用",因為應用程式的大部分程式碼都可以在伺服器和客戶端上運行

##我們從上門解釋得到以下結論:

Vue SSR
    是一個在
  • SPA上改良的服務端渲染透過Vue SSR
  • 渲染的頁面,需要在客戶端啟動才能實現互動
  • Vue SSR
  • 將包含兩部分:服務端渲染的首屏,包含互動的
  • SPA
  • 二、解決了什麼

SSR主要解決了以下兩種問題:

seo:搜尋引擎優先爬取頁面

HTML
    結構,使用
  • ssr時,服務端已經產生了和業務想關聯的HTML,有利於seo首屏呈現渲染:使用者不需要等待頁面所有js
  • 載入完成就可以看到頁面視圖(壓力來到了伺服器,所以需要權衡哪些用服務端渲染,哪些交給客戶端)
  • 但使用
  • SSR
同樣存在以下的缺點:

複雜度:整個專案的複雜度
  • #函式庫的支持性,程式碼相容
  • 效能問題
  • #每個請求都是

    n
      個實例的創建,不然會污染,消耗會變得很大
    • 快取 node serve 
    • 、 
    • nginx判斷目前使用者有沒有過期,如果沒過期的話就緩存,用剛剛的結果。 降級:監控cpu
    • 、記憶體佔用過多,就
    • spa,回傳單一的殼
    伺服器負載變大,相對於前後端分離務器只需要提供靜態資源來說,伺服器負載更大,所以要慎重使用
  • 所以在我們選擇是否使用
  • SSR
前,我們需要慎重問問自己這些問題:

需要
    SEO
  • 的頁面是否只是少數幾個,這些是否可以使用預渲染( Prerender SPA Plugin)實作

    首屏的請求回應邏輯是否複雜,資料回傳是否大量且緩慢
  • ##三、如何實作

對於同構開發,我們依然使用webpack打包,我們要解決兩個問題:服務端首屏渲染和客戶端啟動

這裡需要產生一個伺服器bundle檔案用於服務端首屏渲染和一個客戶端bundle檔案用於客戶端啟動

什麼是SSR? vue中怎麼實作SSR服務端渲染?

程式碼結構除了兩個不同入口之外,其他結構和之前vue應用完全相同

src 
├── router 
├────── index.js # 路由声明 
├── store 
├────── index.js # 全局状态 
├── main.js # ⽤于创建vue实例 
├── entry-client.js # 客户端⼊⼝,⽤于静态内容“激活” 
└── entry-server.js # 服务端⼊⼝,⽤于⾸屏内容渲染
登入後複製

路由配置

import Vue from "vue"; import Router from "vue-router"; Vue.use(Router);
//导出⼯⼚函数
export function createRouter(){
    return new Router({
    mode: 'history',
    routes: [ 
       // 客户端没有编译器,这⾥要写成渲染函数 
        { path: "/", component: { render: h => h('div', 'index page') } }, 
        { path: "/detail", component: { render: h => h('div', 'detail page') }} 
    ] 
  });
 }
登入後複製

主檔案main.js

跟之前不同,主檔案是負責建立vue實例的工廠,每次請求都會有獨立的vue實例建立

import Vue from "vue";
import App from "./App.vue";
import { createRouter } from "./router"; 
// 导出Vue实例⼯⼚函数,为每次请求创建独⽴实例 
// 上下⽂⽤于给vue实例传递参数
export function createApp(context) {
    const router = createRouter();
    const app = new Vue({ router, context, render: h => h(App) });
    return { app, router };
  }
登入後複製

編寫服務端入口src/entry-server.js

它的任務是建立Vue實例並根據傳入url指定首屏

import { createApp } from "./main";
// 返回⼀个函数,接收请求上下⽂,返回创建的vue实例
export default context => {
// 这⾥返回⼀个Promise,确保路由或组件准备就绪
    return new Promise((resolve, reject) => {
        const { app, router } = createApp(context);
        // 跳转到⾸屏的地址
        router.push(context.url);
        // 路由就绪,返回结果
        router.onReady(() => {
        resolve(app);
        }, reject);
    }); 
};
登入後複製

寫客戶端入口entry-client.js

#客戶端入口只需建立vue實例並執行掛載,這⼀步稱為啟動

import { createApp } from "./main"; 
// 创建vue、router实例
const { app, router } = createApp();
// 路由就绪,执⾏挂载
router.onReady(() => { app.$mount("#app"); });
登入後複製

webpack進行設定

安裝依賴

npm install webpack-node-externals lodash.merge -D

vue.config.js進行配置

// 两个插件分别负责打包客户端和服务端
const VueSSRServerPlugin = require("vue-server-renderer/server-plugin");
const VueSSRClientPlugin = require("vue-server-renderer/client-plugin");
const nodeExternals = require("webpack-node-externals");
const merge = require("lodash.merge");
// 根据传⼊环境变量决定⼊⼝⽂件和相应配置项
const TARGET_NODE = process.env.WEBPACK_TARGET === "node";
const target = TARGET_NODE ? "server" : "client";
module.exports = {
    css: {
        extract: false
    },
    outputDir: './dist/'+target,
    configureWebpack: () => ({
        // 将 entry 指向应⽤程序的 server / client ⽂件
        entry: `./src/entry-${target}.js`,
        // 对 bundle renderer 提供 source map ⽀持
        devtool: 'source-map',
        // target设置为node使webpack以Node适⽤的⽅式处理动态导⼊,
        // 并且还会在编译Vue组件时告知`vue-loader`输出⾯向服务器代码。
        target: TARGET_NODE ? "node" : "web",
        // 是否模拟node全局变量
        node: TARGET_NODE ? undefined : false,
        output: {
            // 此处使⽤Node⻛格导出模块
            libraryTarget: TARGET_NODE ? "commonjs2" : undefined
        },
        // https://webpack.js.org/configuration/externals/#function
        // https://github.com/liady/webpack-node-externals
        // 外置化应⽤程序依赖模块。可以使服务器构建速度更快,并⽣成较⼩的打包⽂件。
        externals: TARGET_NODE
        ? nodeExternals({
            // 不要外置化webpack需要处理的依赖模块。
            // 可以在这⾥添加更多的⽂件类型。例如,未处理 *.vue 原始⽂件,
            // 还应该将修改`global`(例如polyfill)的依赖模块列⼊⽩名单
            whitelist: [/\.css$/]
        })
        : undefined,
        optimization: {
            splitChunks: undefined
        },
        // 这是将服务器的整个输出构建为单个 JSON ⽂件的插件。
        // 服务端默认⽂件名为 `vue-ssr-server-bundle.json`
        // 客户端默认⽂件名为 `vue-ssr-client-manifest.json`。
        plugins: [TARGET_NODE ? new VueSSRServerPlugin() : new
                  VueSSRClientPlugin()]
    }),
    chainWebpack: config => {
        // cli4项⽬添加
        if (TARGET_NODE) {
            config.optimization.delete('splitChunks')
        }

        config.module
            .rule("vue")
            .use("vue-loader")
            .tap(options => {
            merge(options, {
                optimizeSSR: false
            });
        });
    }
};
登入後複製

對腳本進行配置,安裝依賴

npm i cross-env - D

"scripts": {
 "build:client": "vue-cli-service build",
 "build:server": "cross-env WEBPACK_TARGET=node vue-cli-service build",
 "build": "npm run build:server && npm run build:client"
}
登入後複製

執行打包:npm run build

#最後修改宿主檔案/public/index.html##

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width,initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <!--vue-ssr-outlet-->
    </body>
</html>
登入後複製

是服務端渲染入口位置,注意不能為了好看而在前後加空格

安裝

vuex

npm install -S vuex

建立

vuex工廠函數

import Vue from &#39;vue&#39;
import Vuex from &#39;vuex&#39;
Vue.use(Vuex)
export function createStore () {
    return new Vuex.Store({
        state: {
            count:108
        },
        mutations: {
            add(state){
                state.count += 1;
            }
        }
    })
}
登入後複製

#在

main.js檔案中掛載store

import { createStore } from &#39;./store&#39;
export function createApp (context) {
    // 创建实例
    const store = createStore()
    const app = new Vue({
        store, // 挂载
        render: h => h(App)
    })
    return { app, router, store }
}
登入後複製

伺服器端渲染的是應用程式的"快照",如果應用依賴於⼀些異步數據,那麼在開始渲染之前,需要先預取和解析好這些數據

store進行一步資料取得

export function createStore() {
    return new Vuex.Store({
        mutations: {
            // 加⼀个初始化
            init(state, count) {
                state.count = count;
            },
        },
        actions: {
            // 加⼀个异步请求count的action
            getCount({ commit }) {
                return new Promise(resolve => {
                    setTimeout(() => {
                        commit("init", Math.random() * 100);
                        resolve();
                    }, 1000);
                });
            },
        },
    });
}
登入後複製

元件中的資料預取邏輯

export default {
    asyncData({ store, route }) { // 约定预取逻辑编写在预取钩⼦asyncData中
        // 触发 action 后,返回 Promise 以便确定请求结果
        return store.dispatch("getCount");
    }
};
登入後複製

服務端資料預取,

entry-server.js

import { createApp } from "./app";
export default context => {
    return new Promise((resolve, reject) => {
        // 拿出store和router实例
        const { app, router, store } = createApp(context);
        router.push(context.url);
        router.onReady(() => {
            // 获取匹配的路由组件数组
            const matchedComponents = router.getMatchedComponents();

            // 若⽆匹配则抛出异常
            if (!matchedComponents.length) {
                return reject({ code: 404 });
            }

            // 对所有匹配的路由组件调⽤可能存在的`asyncData()`
            Promise.all(
                matchedComponents.map(Component => {
                    if (Component.asyncData) {
                        return Component.asyncData({
                            store,
                            route: router.currentRoute,
                        });
                    }
                }),
            )
                .then(() => {
                // 所有预取钩⼦ resolve 后,
                // store 已经填充⼊渲染应⽤所需状态
                // 将状态附加到上下⽂,且 `template` 选项⽤于 renderer 时,
                // 状态将⾃动序列化为 `window.__INITIAL_STATE__`,并注⼊ HTML
                context.state = store.state;

                resolve(app);
            })
                .catch(reject);
        }, reject);
    });
};
登入後複製

客戶端在掛載到應用程式之前,

store 就應該取得到狀態,entry-client.js

// 导出store
const { app, router, store } = createApp();
// 当使⽤ template 时,context.state 将作为 window.__INITIAL_STATE__ 状态⾃动嵌⼊到最终的 HTML 
// 在客户端挂载到应⽤程序之前,store 就应该获取到状态:
if (window.__INITIAL_STATE__) {
    store.replaceState(window.__INITIAL_STATE__);
}
登入後複製

客戶端資料預先取處理,

main.js

Vue.mixin({
    beforeMount() {
        const { asyncData } = this.$options;
        if (asyncData) {
            // 将获取数据操作分配给 promise
            // 以便在组件中,我们可以在数据准备就绪后
            // 通过运⾏ `this.dataPromise.then(...)` 来执⾏其他任务
            this.dataPromise = asyncData({
                store: this.$store,
                route: this.$route,
            });
        }
    },
});
登入後複製

修改伺服器啟動檔案

// 获取⽂件路径
const resolve = dir => require(&#39;path&#39;).resolve(__dirname, dir)
// 第 1 步:开放dist/client⽬录,关闭默认下载index⻚的选项,不然到不了后⾯路由
app.use(express.static(resolve(&#39;../dist/client&#39;), {index: false}))
// 第 2 步:获得⼀个createBundleRenderer
const { createBundleRenderer } = require("vue-server-renderer");
// 第 3 步:服务端打包⽂件地址
const bundle = resolve("../dist/server/vue-ssr-server-bundle.json");
// 第 4 步:创建渲染器
const renderer = createBundleRenderer(bundle, {
    runInNewContext: false, // https://ssr.vuejs.org/zh/api/#runinnewcontext
    template: require(&#39;fs&#39;).readFileSync(resolve("../public/index.html"), "utf8"), // 宿主⽂件
    clientManifest: require(resolve("../dist/client/vue-ssr-clientmanifest.json")) // 客户端清单
});
app.get(&#39;*&#39;, async (req,res)=>{
    // 设置url和title两个重要参数
    const context = {
        title:&#39;ssr test&#39;,
        url:req.url
    }
    const html = await renderer.renderToString(context);
    res.send(html)
})
登入後複製

小結

    ##使用
  • ssr

    不存在單例模式,每次使用者要求都會建立一個新的vue實例

  • 實作
  • ssr

    需要實作服務端首屏渲染與用戶端啟動

  • 服務端異步擷取資料
  • asyncData

    可以分為首屏非同步取得和切換元件取得

    #首屏異步獲取數據,在服務端預渲染的時候就應該已經完成
    • 切換組件通過
    • mixin
    • 混入,在beforeMount鉤子完成數據獲取
  • (學習影片分享:
vuejs教學

web前端

以上是什麼是SSR? vue中怎麼實作SSR服務端渲染?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

vue怎麼給按鈕添加函數 vue怎麼給按鈕添加函數 Apr 08, 2025 am 08:51 AM

可以通過以下步驟為 Vue 按鈕添加函數:將 HTML 模板中的按鈕綁定到一個方法。在 Vue 實例中定義該方法並編寫函數邏輯。

vue.js怎麼引用js文件 vue.js怎麼引用js文件 Apr 07, 2025 pm 11:27 PM

在 Vue.js 中引用 JS 文件的方法有三種:直接使用 &lt;script&gt; 標籤指定路徑;利用 mounted() 生命週期鉤子動態導入;通過 Vuex 狀態管理庫進行導入。

vue中怎麼用bootstrap vue中怎麼用bootstrap Apr 07, 2025 pm 11:33 PM

在 Vue.js 中使用 Bootstrap 分為五個步驟:安裝 Bootstrap。在 main.js 中導入 Bootstrap。直接在模板中使用 Bootstrap 組件。可選:自定義樣式。可選:使用插件。

vue中的watch怎麼用 vue中的watch怎麼用 Apr 07, 2025 pm 11:36 PM

Vue.js 中的 watch 選項允許開發者監聽特定數據的變化。當數據發生變化時,watch 會觸發一個回調函數,用於執行更新視圖或其他任務。其配置選項包括 immediate,用於指定是否立即執行回調,以及 deep,用於指定是否遞歸監聽對像或數組的更改。

vue返回上一頁的方法 vue返回上一頁的方法 Apr 07, 2025 pm 11:30 PM

Vue.js 返回上一頁有四種方法:$router.go(-1)$router.back()使用 &lt;router-link to=&quot;/&quot;&gt; 組件window.history.back(),方法選擇取決於場景。

Vue 實現跑馬燈/文字滾動效果 Vue 實現跑馬燈/文字滾動效果 Apr 07, 2025 pm 10:51 PM

在 Vue 中實現跑馬燈/文字滾動效果,可以使用 CSS 動畫或第三方庫。本文介紹了使用 CSS 動畫的方法:創建滾動文本,用 &lt;div&gt; 包裹文本。定義 CSS 動畫,設置 overflow: hidden、width 和 animation。定義關鍵幀,設置動畫開始和結束時的 transform: translateX()。調整動畫屬性,如持續時間、滾動速度和方向。

怎樣查詢vue的版本 怎樣查詢vue的版本 Apr 07, 2025 pm 11:24 PM

可以通過以下方法查詢 Vue 版本:使用 Vue Devtools 在瀏覽器的控制台中查看“Vue”選項卡。使用 npm 運行“npm list -g vue”命令。在 package.json 文件的“dependencies”對像中查找 Vue 項。對於 Vue CLI 項目,運行“vue --version”命令。檢查 HTML 文件中引用 Vue 文件的 &lt;script&gt; 標籤中的版本信息。

vue遍歷怎麼用 vue遍歷怎麼用 Apr 07, 2025 pm 11:48 PM

Vue.js 遍歷數組和對像有三種常見方法:v-for 指令用於遍歷每個元素並渲染模板;v-bind 指令可與 v-for 一起使用,為每個元素動態設置屬性值;.map 方法可將數組元素轉換為新數組。

See all articles