You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Angular模板中借助Angular Universal实现Lit组件的SSR

解决Angular Universal中Lit组件的SSR嵌入问题

方法1:封装Angular组件,区分服务端/浏览器渲染逻辑

通过自定义Angular组件包裹Lit组件,在服务端直接生成HTML插入容器,浏览器端则使用原生自定义元素渲染,同时规避服务端代码打包到浏览器的问题。

实现步骤

  1. 创建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);
    }
  }
}
  1. 在根组件中使用封装组件
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 {}
  1. 配置服务端打包隔离
    修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 09:47:46