【问题标题】:Best Practice: Angular SSR Partial Pre-rendering with dynamic fallback最佳实践:使用动态回退的 Angular SSR 部分预渲染
【发布时间】:2020-02-06 07:46:00
【问题描述】:

背景: 使用 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 找到静态文件。为了测试,我将这些文件的内容替换为垃圾文件,以确保一目了然地加载了哪些文件。

还可以在server.ts 中添加console.log('DYNAMIC');

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 类似功能可以“尝试”从节点容器中检索文件+/index.html,然后在没有/index.html 的情况下回退,但似乎不太可能。

【问题讨论】:

  • 如果您使用 nginx 或任何其他网络服务器作为反向代理,您可以让该网络服务器检查相应的预渲染文件是否存在;如果有,就发给它;如果没有,则使用角度通用动态 SSR
  • @David 将 nginx 作为 K8s 上的入口,它将流量引导到 pod,因此它不能直接执行try-files,因为它不在容器内。我能做的最接近的方法是运行一个包含 nginx 和托管应用程序的节点的容器。认为这是值得的开销而不是 node/express 只是这样做?
  • 我不确定,但为了简单起见,我会说让 nodejs 处理它

标签: node.js angular express angular-universal prerender


【解决方案1】:

您可以像这样在 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 }] });
   }

【讨论】:

    【解决方案2】:
    npm install @nguniversal/express-engine@11.2.1 --save
    

    默认已经自带静态页面了。

    【讨论】:

    • 不——刚刚从全新安装中再次尝试(npx ng version - Angular CLI: 11.2.8 + @nguniversal/express-engine: 11.2.1)。创建了一个子页面 (ng g m child --route child --module app),添加了一个登录 server:ts::34 以记录对渲染器的 URL 调用,然后运行 ​​npm run build:ssr &amp;&amp; npm run prerender &amp;&amp; npm run serve:ssr//child,再回到/都调用渲染端点。
    猜你喜欢
    • 2020-12-16
    • 2020-03-05
    • 2014-07-14
    • 2014-02-11
    • 2012-07-11
    • 2021-11-16
    • 1970-01-01
    • 2020-10-23
    • 2020-01-25
    相关资源
    最近更新 更多