我尝试集成 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 应用程序中吗?
要将 CalHeatMap 集成到 服务器端渲染 (SSR) Angular 应用程序,您需要考虑以下事项:
ReferenceError: document is not defined
是因为CalHeatMap正在使用DOM API,特别是document.querySelector
,在服务器端环境中不可用。在 SSR 应用程序中,代码首先在服务器上运行,因此 document
或 window
不可用。确保客户端执行: 由于 CalHeatMap 是一个与 DOM 交互的客户端 JavaScript 库,因此它只能在客户端执行,而不能在 SSR 期间执行。在初始化 CalHeatMap 之前,您可以使用 Angular 的
isPlatformBrowser
检查代码是否在浏览器中运行。
延迟加载或动态导入: 您只能在客户端延迟加载 CalHeatMap,以防止出现任何 SSR 问题。
以下是如何修改代码以确保 CalHeatMap 仅在客户端初始化。
ngOnInit
仅在浏览器中运行使用 Angular 中的
isPlatformBrowser
确保代码仅在浏览器环境中运行。
为了防止 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);
});
}
}
}
isPlatformBrowser
:此函数检查应用程序是否正在浏览器中运行。如果是,我们继续动态导入并初始化 CalHeatMap。import('cal-heatmap')
):这可确保 CalHeatMap 仅在浏览器上运行时加载,从而防止 SSR 问题。then
块中,以确保我们可以在库加载失败时处理任何错误。JSDOM:您提到的使用
jsdom
的方法是在 Node.js 环境中模拟 DOM 的一种解决方法,但在大多数使用 Angular 的 SSR 场景中,最好确保执行任何客户端代码仅在浏览器中,从而避免需要 jsdom
。
SSR 与 Angular Universal:如果您使用 Angular Universal 进行 SSR,关键是隔离任何依赖于浏览器的代码(例如 CalHeatMap),使其仅在客户端运行,这就是上面的解决方案所实现的。
这种方法应该可以帮助您集成 CalHeatMap,而不会在服务器端出现问题。