Asp .Net Core Spa (二) - 服務器渲染1


Server Side Rendering 服務器渲染是各 Spa 項目目前很熱衷於解決的一個問題,畢竟針對SEO和首次加載優化

.Net Core SPA 服務器渲染 將分為 兩篇:

第一篇 主要分析 .net core 最新的服務器渲染中間件 和 基礎使用方式 和一些庫的原理分析

第二篇 主要分析 一些特殊的服務器渲染需求 和 實現方式, 外加客戶端 對於渲然后的html的優化處理等

注:主要針對 .Net Core 2.1 以上 MVC 和 SPA 完全分離的設計結構 所以下面主要講述的是使用 UseSpaPrerendering 而非 PrerenderResult + MVC

 

相關 Github Library

Microsoft.AspNetCore.SpaServices

Spa服務器渲染中間件

Microsoft.AspNetCore.NodeServices

調用NodeJs的核心服務

JS 服務端渲染入口

domian-task

JS 異步請求Task管理庫

 

服務器渲染流程

 

頁面請求 -> SPA 中間件 -> SSR 服務 -> Node 服務 -> 服務端js -> 生成網頁String結果 -> 返回

 

 

定義.Net Core服務器渲染

Angular

上一篇有講到過新的Spa 中間件 UseSpa 在 UseSpa下有選項 UseSpaPrerendering, 這就是主要定義服務器渲染的接口

Angular的服務器渲染相對來說比較簡單, 案例也多, 因為AngularCliBuilder 是一個自帶的SSR BootModuleBuilder

spa.UseSpaPrerendering(options => {
    options.BootModulePath = $"{spa.Options.SourcePath}/dist-server/main.js";
    options.BootModuleBuilder = env.IsDevelopment() ? new AngularCliBuilder(npmScript: "build:ssr") : null;
    options.ExcludeUrls = new[] { "/sockjs-node" };
});

這是一段Angular 通過 AngularCliBuilder 來定義 服務器渲染 從build 到 入口的定義。

隨便找了一個案例 https://github.com/joshberry/dotnetcore-angular-ssr

 

React

不過這不是我主要想探討的。。因為我對ng不算那么熟,哈哈,我主要來說如何自定義吧。下面用React作為案例 具體原理是相近的。

這個是我的案例 https://github.com/JiarongGu/ReactCoreTemplate

app.UseSpa(spa => {
    spa.Options.SourcePath = "ClientApp";
    spa.UseSpaPrerendering(options => {
        options.BootModulePath = $"{spa.Options.SourcePath}/build/server/bundle.js";
        options.SupplyData = SpaPrerenderingServiceLocator.GetProcessor(app);
    });
});

這是簡單的定義

BootModulePath:是我們 服務端 js 的入口

SupplyData: 是我們要給服務端js 的基本數據 例如當前的local的服務器地址和請求的url,具體有什么用 我下面會一一講解

我這里定義了一個單例的服務外加一個服務定位來執行處理 SupplyData 具體實現可以看我的github

 

制作服務器渲染入口

根據上面這個處理流程 我們首先需要定義一個 服務端的頁面 也就是 server/bundle.js 來執行客戶端的 javascript, 通過它來獲得我們需要的html結果。

因為在服務器上執行我們將會使用NodeJS來執行這個bundle.js,而且必須是能返回一個html結果的函數。

這里微軟給我們提供了一個npm包 aspnet-prerendering, 他提供了包裝Promise 返回值, SSR PreRenderer會調用NodeJs 去執行。

主要的方法就是這個 createServerRenderer

export default createServerRenderer(params => {
  return new Promise<RenderResult>((resolve, reject) => { ... } }

 

params 的數據類型

export interface BootFuncParams {
    location: any;              // e.g., Location object containing information '/some/path'
    origin: string;             // e.g., 'https://example.com:1234'
    url: string;                // e.g., '/some/path'
    baseUrl: string;            // e.g., '' or '/myVirtualDir'
    absoluteUrl: string;        // e.g., 'https://example.com:1234/some/path'
    domainTasks: Promise<any>;
    data: any;                  // any custom object passed through from .NET
}

其中 data 便是上面所說的 SupplyData 里面可以包括任何想傳遞的資料 最重要的是 里面會包括 originalHtml, 這就是默認讀取到的index.html頁面string

在最后 我們會渲染完Spa的所有組件 然后把生成的 string 替換在這個originalHtml 適合的位置上 這樣 服務器渲染就算是完成了

 

resolve promise 結果類型

在 JavaScriptService 下 RenderToStringResult 這便是我們需要返回的 結果給SSR Service

public class RenderToStringResult
{
    public JObject Globals { get; set; }

    // 服務端HTMl結果
    public string Html { get; set; }

    // 重定向,跳過服務渲染
    public string RedirectUrl { get; set; }

    // 自定義Response Code, 一般不需要設置
    public int? StatusCode { get; set; }
}

注:在使用UseSpaPrerendering的時候 Gloabls 必須為空 這是給 MVC 實現使用的

 

Webpack/Cli Build服務端

因為服務端JS的性質不同 所以 Webpack也需要另外定義一個 關鍵是 target: 'node', 然后 entry 定義為新的server.js 入口 這樣就會根據新的入口 來進行nodejs 模式編譯.

 

 

總結

這篇主要簡單講解 如何從SPA 通過服務器渲染生成靜態頁面,但是不包括異步數據獲取。

寫的還是比較粗糙,如果有哪里不清楚的 歡迎留言。

下一篇會主要講述關於數據管理,異步請求管理 包括如何使用 domian-task 或者 其他方式的實現,外加最近收集到的多Spa項目的管道管理

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM