如何在Angular模板中借助Angular Universal实现Lit组件的SSR
解决Angular Universal中Lit组件的SSR嵌入问题
方法1:封装Angular组件,区分服务端/浏览器渲染逻辑
通过自定义Angular组件包裹Lit组件,在服务端直接生成HTML插入容器,浏览器端则使用原生自定义元素渲染,同时规避服务端代码打包到浏览器的问题。
实现步骤
- 创建Lit组件的Angular封装组件
import { Component, OnInit, PLATFORM_ID, Inject, ElementRef } from '@angular/core'; import { isPlatformServer } from '@angular/common'; import { render, html } from '@lit-labs/ssr'; import { collectResultSync } from '@lit-labs/ssr/lib/render-result'; @Component({ selector: 'app-lit-wrapper', template: '<div #litContainer></div>' }) export class LitWrapperComponent implements OnInit { constructor( @Inject(PLATFORM_ID) private platformId: Object, private elRef: ElementRef ) {} ngOnInit(): void { if (isPlatformServer(this.platformId)) { // 服务端:生成Lit组件HTML并插入容器 const litHtml = collectResultSync(render(html`<my-component></my-component>`)); this.elRef.nativeElement.querySelector('#litContainer').innerHTML = litHtml; } else { // 浏览器:创建自定义元素实例挂载 const litComponent = document.createElement('my-component'); this.elRef.nativeElement.querySelector('#litContainer').appendChild(litComponent); } } }
- 在根组件中使用封装组件
import { Component } from '@angular/core'; import '@my-lit-components-package/component'; import { LitWrapperComponent } from './lit-wrapper.component'; @Component({ selector: 'app-root', template: ` <h1>Angular App</h1> <app-lit-wrapper></app-lit-wrapper> `, styles: [] }) export class AppComponent {}
- 配置服务端打包隔离
修改angular.json,将@lit-labs/ssr标记为服务端外部依赖,避免打包进浏览器代码:
"server": { "builder": "@angular-devkit/build-angular:server", "options": { "outputPath": "dist/my-app/server", "main": "server.ts", "tsConfig": "tsconfig.server.json", "externalDependencies": ["@lit-labs/ssr"] } }
方法2:利用TransferState传递服务端渲染结果
通过Angular的TransferState把服务端生成的Lit组件HTML传递到浏览器,复用已有DOM触发Lit的hydration(水合),避免重复渲染。
实现步骤
import { Component, OnInit, PLATFORM_ID, Inject, ElementRef } from '@angular/core'; import { isPlatformServer, TransferState, makeStateKey } from '@angular/common'; import { render, html } from '@lit-labs/ssr'; import { collectResultSync } from '@lit-labs/ssr/lib/render-result'; // 定义TransferState的key const LIT_COMPONENT_HTML_KEY = makeStateKey<string>('litComponentHtml'); @Component({ selector: 'app-lit-wrapper', template: '<div #litContainer></div>' }) export class LitWrapperComponent implements OnInit { constructor( @Inject(PLATFORM_ID) private platformId: Object, private elRef: ElementRef, private transferState: TransferState ) {} ngOnInit(): void { let litHtml: string; if (isPlatformServer(this.platformId)) { litHtml = collectResultSync(render(html`<my-component></my-component>`)); // 把HTML存入TransferState this.transferState.set(LIT_COMPONENT_HTML_KEY, litHtml); this.elRef.nativeElement.querySelector('#litContainer').innerHTML = litHtml; } else { // 从TransferState获取服务端生成的HTML litHtml = this.transferState.get(LIT_COMPONENT_HTML_KEY, ''); if (litHtml) { this.elRef.nativeElement.querySelector('#litContainer').innerHTML = litHtml; // 加载Lit组件包,自动触发hydration import('@my-lit-components-package/component'); } else { // 降级为客户端渲染 const litComponent = document.createElement('my-component'); this.elRef.nativeElement.querySelector('#litContainer').appendChild(litComponent); } } } }
关键注意事项
- 服务端代码隔离:确保
@lit-labs/ssr相关逻辑仅在服务端执行,避免浏览器环境加载服务端专属模块。 - Lit水合触发:服务端生成的HTML需要在浏览器加载Lit组件后自动完成状态同步,无需手动重新渲染。
- 私有包兼容性:检查私有Lit组件是否依赖浏览器API(如
window、document),如有需在组件内部做平台判断,避免服务端渲染报错。
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

