# 渲染方式对比

# CSR(客户端渲染)

系统类网页应用渲染方式,即组装页面这个步骤,是在客户端进行,服务端提供异步数据请求的后端服务。

CSR

# 优点

  1. 适合有大量动态数据的网站,即常规后台等需要 api 获取数据的网站类型
  2. 构建时间短

# 缺点

  1. 没有良好的 seo(后台网站不对公众开放,不影响)
  2. 页面从请求到首屏时间长
  3. 对部署前端的服务器压力较大

# 框架

  1. React
  2. Vue
  3. Angular

# SSR(服务端渲染)

门户类网站渲染方式

SSR

# 优点

  1. 有良好 seo
  2. 页面从请求到首屏时间较短,基本页面可以很快展示

# 缺点

  1. 只适合使用少量动态数据或完全不使用动态数据
  2. 构建时间较长
  3. 对部署前端的服务器压力较大

# 框架

  1. Next.js(React+Node.js)
  2. Nuxt.js(Vue+Node.js)
  3. Angular universal(Angular+Express.js)
  4. Nest.js(Node.js+Express.js)

# SSG(静态网站生成)

博客及文档类网站渲染方式

SSG

# 优点

  1. 优秀的 seo
  2. 页面从请求到首屏时间极短
  3. 对部署前端的服务器压力小

# 缺点

  1. 构建时间长
  2. 不能使用动态数据,每次修改都需要重新构建

# 框架

  1. Vuepress
  2. Jekyll
  3. Gatsby
  4. Hugo

# Angular universal 入门

# 安装

官网链接:https://angular.io/guide/universal

假设当前已有一个标准的 Angular 应用,安装 ssr 则需要先安装一个服务,这里是 express。

ng add @nguniversal/express-engine

安装前后目录对比:

安装前 安装后
image.png image.pngimage.png

主要分为两部分,一部分是修改了配置,另一部分是创建了 server 端代码

image.png

客户端方面的配置改动,是把原本的应用打包输出放在了二级文件夹下

image.png

服务端则是完全重新生成了一套配置,用于 ssr 项目的开发

image.png

在脚本中添加了 ssr 的开发,运行,打包和预渲染命令

import "zone.js/dist/zone-node";

import { ngExpressEngine } from "@nguniversal/express-engine";
import * as express from "express";
import { join } from "path";

import { AppServerModule } from "./src/main.server";
import { APP_BASE_HREF } from "@angular/common";
import { existsSync } from "fs";

// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
  const server = express();
  const distFolder = join(process.cwd(), "dist/ssr-project/browser");
  const indexHtml = existsSync(join(distFolder, "index.original.html"))
    ? "index.original.html"
    : "index";

  // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
  server.engine(
    "html",
    ngExpressEngine({
      bootstrap: AppServerModule
    })
  );

  server.set("view engine", "html");
  server.set("views", distFolder);

  // Example Express Rest API endpoints
  // server.get('/api/**', (req, res) => { });
  // Serve static files from /browser
  server.get(
    "*.*",
    express.static(distFolder, {
      maxAge: "1y"
    })
  );

  // All regular routes use the Universal engine
  server.get("*", (req, res) => {
    res.render(indexHtml, {
      req,
      providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }]
    });
  });

  return server;
}

function run(): void {
  const port = process.env["PORT"] || 4000;

  // Start up the Node server
  const server = app();
  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
  });
}

// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = (mainModule && mainModule.filename) || "";
if (moduleFilename === __filename || moduleFilename.includes("iisnode")) {
  run();
}

export * from "./src/main.server";

服务端最核心的则是根目录的 server.ts 文件,这里做了 Angular 页面与 express 服务的绑定,以及 express 服务的启动代码

image.png

image.png

main.ts 和 app.module.ts 都对服务端逻辑创建了一份新文件,当遇到服务端缓存数据或其他类型的需要操控服务端的逻辑,就需要在这里配置。如果只是普通的 ssr 网站,到这一步后则与开发常规 Angular 应用一样,正常开发即可

# 常见问题

# NG-ZORRO 一起使用

官网链接:https://ng.ant.design/docs/universal/zh

文档中有两种方式可以选择,一种较为复杂,需要自己安装 ng-zorro 以后,然后修改服务端文件;另一种则是直接 clone 一个模板项目,修改项目名即可使用。

# 区分服务端逻辑与客户端逻辑

constructor(
    @Inject(PLATFORM_ID) private platformId: Object
) {}

func() {
  if (isPlatformBrowser(this.platformId)) {
    // do something
  }
}

# 跨域配置

跨域配置分为两种情况,分别是开发模式和生产模式

# 开发模式
"dev:ssr": "ng run xw_offical:serve-ssr"

因为 ssr 会有服务端请求和客户端请求同时存在,客户端请求代理即 Angular 的 proxy 文件中配置,而服务端需要在 express 的 server.ts 文件中添加中间件。

import { createProxyMiddleware } from "http-proxy-middleware";

const server = app().use(
  "/api",
  createProxyMiddleware({
    target: "http://ip:port/",
    secure: false,
    logLevel: "debug",
    changeOrigin: true
  })
);
# 生产模式
"serve:ssr": "node dist/xw_offical/server/main.js"

生产模式会将客户端请求拦截并从服务端发送,因此只需要 server.ts 文件中的中间件即可。

发布日期: 4/18/2023, 6:04:25 AM