• Asp .Net Core Spa (二)


    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项目的管道管理

     

  • 相关阅读:
    IP保留地址
    HTML5读取本地文件
    angularjs中动态为audio绑定src
    canvas移动端常用技巧图片loading
    angularjs三级联动
    angular实现select的ng-options
    ng-bind-html在ng-repeat中问题的解决办法
    JS判断是否在微信浏览器打开
    angular实现select的ng-options
    创建 AngularJS 自定义过滤器,带自定义参数
  • 原文地址:https://www.cnblogs.com/JiarongGu/p/10431616.html
Copyright © 2020-2023  润新知