node.js - 最佳实践 : Angular SSR Partial Pre-rendering with dynamic fallback

标签 node.js angular express angular-universal prerender

背景:使用 Angular Universal 执行预渲染,但并非所有路由都将被渲染(大部分是查询参数或仅经过身份验证的页面),因此希望回退到快速渲染器需要。

快速复制 (bash):

npm install -g @angular/cli@next
ng new partial-prerender -s -t --minimal --routing --interactive=false
cd partial-prerender/
ng add @nguniversal/express-engine@'^9.0.0-rc.1'
ng g m child --route child --module app
cat << 'EOF' > src/app/app.component.ts
import { Component } from '@angular/core';

@Component({
  template: `<div [routerLink]="['/']">Root</div><div [routerLink]="['child']">Child</div><router-outlet></router-outlet>`,
})
export class AppComponent {}
EOF
npm run prerender
npm run serve:ssr

此快速复制将生成应用程序、通用实现、子页面,并替换应用程序 html 以提供 2 个链接和一个路由器导出,然后构建/预渲染。两条路线都将被预渲染,但这足以讨论这个问题。

问题: 执行动态 SSR,因为 Express 服务器将接收请求而不是提供预呈现的静态文件。通常无需指定 /index.html 即可访问 URL。

请注意,静态文件可以在 /dist/partial-prerender/browser/index.html.../child/index.html 中找到。为了进行测试,我已将这些文件的内容替换为垃圾内容,以确保一目了然地确定加载了哪些文件。

也可以添加一个console.log('DYNAMIC');server.ts:

server.get('*', (req, res) => {
    console.log('DYNAMIC');
    res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
});

当向 localhost:4000localhost:4000/child 发出请求时,将打印“DYNAMIC”并生成动态渲染版本,而不是给我我损坏的预渲染文件。

当向 localhost:4000/index.htmllocalhost:4000/child/index.html 发出请求时,

server.get('*.*', express.static(distFolder, { maxAge: '1y' }));

拾取并提供损坏的文件。

一切都是有道理的,为什么会发生,但我希望能够只点击给定的 url(没有 /index.html 并接收预渲染文件(如果可用),然后回过头来让 SSR 发挥作用。


可能的解决方案: 修改 server.ts 以测试与给定请求路径匹配的文件是否存在 + /index.html 并为它们提供服务,回退到 res.render(.. .

  • 这是最好的方法吗?
    • 如果是这样,为什么这不是默认功能?我唯一的猜测是您可以灵活地使用反向代理执行此操作,同时不会增加这种检查开销。
  • 最好的方法是什么?
    • 大概 6 年没有大量使用 Express,但感觉 express.static 应该以某种方式使用 fs
    • 如果 fs 是答案,那么将预渲染文件缓存在内存中是否有意义?

如果有帮助,我会生成一个 alpine-node 容器并使用 Nginx 入口部署到 K8s。仅提及这一点,因为可能有一个神奇的类似 try-files 的功能,可以从 Node 容器中“尝试”文件 + /index.html 检索,然后没有 /index.html 的回退,但似乎不太可能。

最佳答案

您可以像这样在 get 请求中使用 if 语句

const fullPath = join(distFolder, req.originalUrl);
  if (existsSync(fullPath)) {
    console.log('STATIC Exists');
    return res.sendFile(join(distFolder, req.originalUrl));
  } else {
     //Dynamic
     res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
   }

关于node.js - 最佳实践 : Angular SSR Partial Pre-rendering with dynamic fallback,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60089967/

相关文章:

javascript - 使用 puppeteer js 按标题查找元素

angular - 在 Angular 9 中将 agGroupCellRenderer 与自定义单元格渲染器一起使用

具有可选查询参数的 Angular 路由器

Angular2,如何导入visjs

javascript - 使用正确的后备路由结构从 Nodejs 中的异步调用传递数据的最佳实践

c# - 我该如何解决 'Microsoft.AspNetCore.NodeServices.HostingModels.NodeInvocationException'

javascript - 聚合函数中跳过计数 0

node.js - 将 json 对象存储到 Azure blob 存储

javascript - 如何查找 NodeJS 上是否存在 Azure 文件

javascript - Node 中的基本 html 引擎