当模块延迟加载时,标题服务在 SSR 中不起作用

发布于 2025-01-15 03:51:45 字数 2069 浏览 1 评论 0原文

当您正常加载模块时,标题服务在 SSR 中工作正常,并且使用新标题更新源代码,

// example.module.ts
let routes = [
  { path: '**', component:  ExampleComponent }
]
// example.component.ts
if(this.platform.isPlatformServer()){
  this.titleService.setTitle('example');
}

但是当模块延迟加载时,标题和元服务在 SSR 中不起作用(仅在客户端渲染中工作)

// app.module
  {
    path: '**',
    loadChildren: () =>
      import('./example.module').then(
        (modules) => modules.ExampleModule
      ),
  },

< code>ExampleComponent 按预期在服务器中呈现(通过将 this.platform.platformId 记录到控制台进行测试) 但标题和元服务仅在条件 if(this.platform.isPlatformServer() 被删除时才起作用。

我设置此条件是为了测试服务器端标题和元服务的行为。Angular 也不会'如果在客户端呈现,则不要在源代码中插入添加的元标记和新标题,这会导致 SEO 问题,并且当从应用程序中抓取元标记或共享到社交媒体平台时,这就是为什么不更新标题和元标记的原因在客户端对我来说很重要 另外,

如果模块是延迟加载的,则 fileReplacements 不起作用,因此 environment 在服务器和浏览器中具有不同的值。 如果您在开发模式下构建应用程序,console.log({environment }) 在服务器控制台和浏览器控制台中给出不同的值。

当模块延迟加载时,ngOnChanges似乎不会在服务器上触发 最小重现

feature/lazy-child.component.ts中运行npm start

,当检测到更改时应该设置标题,但事实并非如此。

console.log({changes}) 出现在浏览器控制台中,但不出现在服务器控制台中

Angular CLI: 13.2.6
Node: 16.14.2
Package Manager: npm 8.5.4
OS: linux x64

Angular: 13.2.6
... animations, cdk, cli, common, compiler, compiler-cli, core
... forms, material, platform-browser, platform-browser-dynamic
... platform-server, router, service-worker

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1302.6
@angular-devkit/build-angular   13.2.6
@angular-devkit/core            13.2.6
@angular-devkit/schematics      13.2.6
@nguniversal/express-engine     13.0.2
@schematics/angular             13.2.6
rxjs                            7.5.5
typescript     

when you load a module normally, title service works fine in SSR, and the source code updated with the new title

// example.module.ts
let routes = [
  { path: '**', component:  ExampleComponent }
]
// example.component.ts
if(this.platform.isPlatformServer()){
  this.titleService.setTitle('example');
}

but when the module is lazy loaded, title and meta services don't work in SSR (only works in client-rendering)

// app.module
  {
    path: '**',
    loadChildren: () =>
      import('./example.module').then(
        (modules) => modules.ExampleModule
      ),
  },

ExampleComponent is rendered in the server as expected, (tested by logging this.platform.platformId to the console)
but title and meta services only works when the condition if(this.platform.isPlatformServer() is removed.

I set this condition to test the behavior of title and meta services in server side. also Angular doesn't insert the added meta tags and the new title in the source code if rendered in client-side which makes issue with SEO and when scratching meta tags from the app or sharing to social media platform, that's why updating title and meta tags doesn't matter to me in client-side rendering.

also, it seems that if the module is lazy-loaded fileReplacements doesn't work, so environment has different values in the server and the browser
console.log({ environment }) gives different values in the server's console that the browser's console if you build the app in development mode.

it seems that ngOnChanges doesn't fire on the server when the module loaded lazily
minimal repro

run npm start

in feature/lazy-child.component.ts the title should be set when a change is detected,but it don't.

also console.log({ changes }) appears in the browser's console, but doesn't appear in the server's console

Angular CLI: 13.2.6
Node: 16.14.2
Package Manager: npm 8.5.4
OS: linux x64

Angular: 13.2.6
... animations, cdk, cli, common, compiler, compiler-cli, core
... forms, material, platform-browser, platform-browser-dynamic
... platform-server, router, service-worker

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1302.6
@angular-devkit/build-angular   13.2.6
@angular-devkit/core            13.2.6
@angular-devkit/schematics      13.2.6
@nguniversal/express-engine     13.0.2
@schematics/angular             13.2.6
rxjs                            7.5.5
typescript     

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

难以启齿的温柔 2025-01-22 03:51:45

我们在应用程序中遇到了同样的问题,因此我们只是将有关设置标题和元标记的逻辑移至 canActivate 防护。

这是显而易见且简单的解决方案

 {
    path: '',
    loadChildren: () => import('./modules/main/main.module').then(m => m.MainModule),
    canActivate: [setMetaTags],
    data: {
      title: 'Main title',
    }
  },


export class SetMetaTags implements CanActivate {

  constructor(
    private titleService: Title
  ) {}

  canActivate(
    route: ActivatedRouteSnapshot
  ): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    const value = route.data?.title || 'Default title';
    
    this.titleService.setTitle(value);

    return true;
  }

}

不太明显,您应该遵循本指南 https://www.linkedin.com/pulse/angular-seo-guide-universal-server-side-rendering-lazy-alapati/

主要思想是,你应该传递延迟加载模块的 SSR 映射,这样它就知道你有哪些模块:

app.server.module.ts 应该从 @nguniversal/module-map-ngfactory-loader 导入 ModuleMapLoaderModule,以便延迟加载模块查看源内容。

We had the same issue in our application, so we just moved logic about setting title and metatags to canActivate guard.

It's obvious and simple solution

 {
    path: '',
    loadChildren: () => import('./modules/main/main.module').then(m => m.MainModule),
    canActivate: [setMetaTags],
    data: {
      title: 'Main title',
    }
  },


export class SetMetaTags implements CanActivate {

  constructor(
    private titleService: Title
  ) {}

  canActivate(
    route: ActivatedRouteSnapshot
  ): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    const value = route.data?.title || 'Default title';
    
    this.titleService.setTitle(value);

    return true;
  }

}

less obvious, you should follow this guide https://www.linkedin.com/pulse/angular-seo-guide-universal-server-side-rendering-lazy-alapati/

The main idea is that, you should pass SSR map of lazy load modules, so it knows what modules do you have:

app.server.module.ts should have ModuleMapLoaderModule imported from @nguniversal/module-map-ngfactory-loader in order to work lazyloading modules view source content.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文