Angular 9 SSR 构建服务错误 -- 错误 ReferenceError:文档未定义

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

错误参考错误:文档未定义

import { readFileSync } from 'fs';
const domino = require('domino');  // import the library `domino`
const DIST_FOLDER = join(process.cwd(), 'dist/browser');
const template = readFileSync(join(DIST_FOLDER, 'index.html')).toString(); // use `index.html` as template
const win = domino.createWindow(template); // create object Window
global['window'] = win;
global['Event'] = win.Event;               // assign the `win.Event` to prop `Event`
global['document'] = win.document;

即使在 Server.ts 中添加此解决问题,但在性能上 TTFB 时间太高。 有解决办法吗...?

angular server-side-rendering angular-universal angular9
5个回答
17
投票

尝试使用@angular/common包提供的DOCUMENT常量

import { Inject, Injectable } from '@angular/core';
import { DOCUMENT } from '@angular/common';

@Injectable()
export class MyService {
  constructor(@Inject(DOCUMENT) private document: Document) {}
}

6
投票

这些全局变量包括 window、document、localStorage、indexedDB、setTimeout 和 setInterval,您不能在 Angular 通用应用程序中使用

使用 Anguar 公共模块中的文档对象

从库导入

import { DOCUMENT } from '@angular/common';

投入使用

@Inject(DOCUMENT) private document: Document,

4
投票

尽管有标题,但看起来您的问题更多的是关于缓慢的 TTFB,而不是

document
未定义的错误。

关于未定义文档错误,解决办法是:

  • 使用以下注入

    @Inject(DOCUMENT) private document
    如果错误出现在你自己的代码中

  • 如果错误出现在第 3 方库中,并且无法将这些库替换为与 Angular Universal 兼容的其他库,请使用

    domino

要解决TTFB慢的问题,没有什么神奇的解决办法。尽量避免渲染那些绝对不需要在服务器端渲染的组件,确保没有长时间运行的 API 调用,使用缓存


0
投票

如果您有一个与 Angular Universal 不兼容的库,则不应在服务器上渲染此包,而应在服务器返回响应后在客户端上渲染它。

isBrowser = false;
constructor(@Inject(PLATFORM_ID) private platformId) {
  this.isBrowser = isPlatformBrowser(this.platformId);
}

现在你必须像这样使用该包:

if (this.isBrowser) {
  ... use package
}

或者你可以在html代码中使用ngIf。


0
投票

文档中指出:某些常见的浏览器 API 和功能可能在服务器上不可用。应用程序无法使用特定于浏览器的全局对象,例如窗口、文档、导航器或位置以及 HTMLElement 的某些属性。

一般来说,依赖于浏览器特定符号的代码只能在浏览器中执行,而不是在服务器上执行。这可以通过 afterRender 和 afterNextRender 生命周期挂钩来强制执行。这些仅在浏览器上执行并在服务器上跳过。

因此,依赖于浏览器特定 API 的代码应移至 afterRender 和 afterNextRender 生命周期挂钩。 例如

import { Component, ViewChild, afterNextRender } from '@angular/core';
@Component({
selector: 'my-cmp',
 template: `<span #content>{{ ... }}</span>`,
 })
export class MyComponent {
 @ViewChild('content') contentRef: ElementRef;
  constructor() {
   afterNextRender(() => {
    // Safe to check `scrollHeight` because this will only run in the 
    browser, not the server.
    console.log('content height: ' + 
    this.contentRef.nativeElement.scrollHeight);
});

} }

您也可以使用 afterRender()。 您需要重新启动服务器才能显示更改

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