最佳做法:具有动态后备功能的Angular SSR部分预渲染

时间:2020-02-06 07:46:00

标签: 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,在内存中缓存预渲染的文件是否有意义?

如果有帮助,我会制作一个阿尔卑斯节点的容器,并使用Nginx入口部署到K8s。仅提及这一点,因为也许有一种神奇的类似于try-files的功能可以通过尝试从节点容器中“尝试”文件+ /index.html进行检索,然后在没有/index.html的情况下进行回退,但是似乎

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

npm install @nguniversal/express-engine@11.2.1 --save

它已经默认带上了静态页面。