使用 SSR 将 CalHeatMap 集成到 Anguar 应用程序中

问题描述 投票:0回答:1

我尝试集成 CalHeatMap https://cal-heatmap.com/docs/getting-started/quickstart

进入我的应用程序:

import { Component } from '@angular/core';
import { NgIconComponent, provideIcons } from '@ng-icons/core';
import { matWavingHandOutline } from '@ng-icons/material-icons/outline';
import CalHeatMap from 'cal-heatmap';

@Component({
  selector: 'app-dashboard-summary',
  standalone: true,
  imports: [NgIconComponent],
  templateUrl: './dashboard-summary.component.html',
  styleUrl: './dashboard-summary.component.css',
  viewProviders: [provideIcons({ matWavingHandOutline })],
})
export class DashboardSummaryComponent {
  ngOnInit() {
    let cal = new CalHeatMap();
    // cal.paint({});
  }
}

但是当我尝试打电话时

cal.paint({});

我得到了:

ReferenceError: document is not defined

随之而来的是:

import {Selection, root} from "./selection/index.js";

export default function(selector) {
  return typeof selector === "string"
      ? new Selection([[document.querySelector(selector)]], [document.documentElement])
      : new Selection([[selector]], root);
}

所以我尝试了:

import { JSDOM } from 'jsdom';
import { Selection, root } from './selection/index.js';

export default function(selector) {
  // Jeśli jest to Node.js, użyj jsdom do stworzenia dokumentu
  if (typeof document === "undefined") {
    const { window } = new JSDOM();
    global.document = window.document;
    global.window = window;
  }

  return typeof selector === "string"
      ? new Selection([[document.querySelector(selector)]], [document.documentElement])
      : new Selection([[selector]], root);
}

但我仍然收到此错误。 您知道如何将其集成到 SSR 应用程序中吗?

angular
1个回答
0
投票

要将 CalHeatMap 集成到 服务器端渲染 (SSR) Angular 应用程序,您需要考虑以下事项:

了解问题

  • 出现错误
    ReferenceError: document is not defined
    是因为CalHeatMap正在使用DOM API,特别是
    document.querySelector
    ,在服务器端环境中不可用。在 SSR 应用程序中,代码首先在服务器上运行,因此
    document
    window
    不可用。

解决步骤

  1. 确保客户端执行: 由于 CalHeatMap 是一个与 DOM 交互的客户端 JavaScript 库,因此它只能在客户端执行,而不能在 SSR 期间执行。在初始化 CalHeatMap 之前,您可以使用 Angular 的

    isPlatformBrowser
    检查代码是否在浏览器中运行。

  2. 延迟加载或动态导入: 您只能在客户端延迟加载 CalHeatMap,以防止出现任何 SSR 问题。

解决方案:修改组件代码

以下是如何修改代码以确保 CalHeatMap 仅在客户端初始化。

第1步:修改
ngOnInit
仅在浏览器中运行

使用 Angular 中的

isPlatformBrowser
确保代码仅在浏览器环境中运行。

第 2 步:延迟加载 CalHeatMap

为了防止 SSR 期间出现错误,您可以使用动态导入或

ngOnInit
有条件地加载库。

这是组件的更新版本:

import { Component, Inject, PLATFORM_ID, OnInit } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { NgIconComponent, provideIcons } from '@ng-icons/core';
import { matWavingHandOutline } from '@ng-icons/material-icons/outline';

@Component({
  selector: 'app-dashboard-summary',
  standalone: true,
  imports: [NgIconComponent],
  templateUrl: './dashboard-summary.component.html',
  styleUrls: ['./dashboard-summary.component.css'],
  viewProviders: [provideIcons({ matWavingHandOutline })],
})
export class DashboardSummaryComponent implements OnInit {

  constructor(@Inject(PLATFORM_ID) private platformId: Object) {}

  ngOnInit() {
    // Check if the platform is the browser
    if (isPlatformBrowser(this.platformId)) {
      // Dynamically import CalHeatMap in the browser only
      import('cal-heatmap').then((CalHeatMap) => {
        const cal = new CalHeatMap();
        cal.paint({
          // CalHeatMap configuration
        });
      }).catch(err => {
        console.error('Error loading CalHeatMap:', err);
      });
    }
  }
}

说明:

  1. isPlatformBrowser
    :此函数检查应用程序是否正在浏览器中运行。如果是,我们继续动态导入并初始化 CalHeatMap。
  2. 动态导入 (
    import('cal-heatmap')
    )
    :这可确保 CalHeatMap 仅在浏览器上运行时加载,从而防止 SSR 问题。
  3. 错误处理:动态导入被包装在
    then
    块中,以确保我们可以在库加载失败时处理任何错误。

补充说明:

  • JSDOM:您提到的使用

    jsdom
    的方法是在 Node.js 环境中模拟 DOM 的一种解决方法,但在大多数使用 Angular 的 SSR 场景中,最好确保执行任何客户端代码仅在浏览器中,从而避免需要
    jsdom

  • SSR 与 Angular Universal:如果您使用 Angular Universal 进行 SSR,关键是隔离任何依赖于浏览器的代码(例如 CalHeatMap),使其仅在客户端运行,这就是上面的解决方案所实现的。

这种方法应该可以帮助您集成 CalHeatMap,而不会在服务器端出现问题。

© www.soinside.com 2019 - 2024. All rights reserved.