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

Angular 13 SSR构建运行报错:ReferenceError: document is not defined

Angular 13 SSR 报错 document is not defined 修复方案

错误根因

Angular SSR 运行在Node.js服务端环境,该环境不存在浏览器专属的BOM对象(document/window/navigator等),代码中直接调用document.createElement('canvas')时,服务端找不到对应对象就会抛出该引用错误。
错误触发代码与调用栈:

var canvasElement = document.createElement('canvas');
                    ^
ReferenceError: document is not defined
at C:\Users\aakas\Desktop\ArteryUniversal\dist\Universal\server\main.js:64680:25
at C:\Users\aakas\Desktop\ArteryUniversal\dist\Universal\server\main.js:64682:4
at Object.13504 (C:\Users\aakas\Desktop\ArteryUniversal\dist\Universal\server\main.js:64786:3)
at __webpack_require__ (C:\Users\aakas\Desktop\ArteryUniversal\dist\Universal\server\main.js:224497:42)
at Module.16720 (C:\Users\aakas\Desktop\ArteryUniversal\dist\ArteryUniversal\server\main.js:5796:71)
at __webpack_require__ (C:\Users\aakas\Desktop\ArteryUniversal\dist\Universal\server\main.js:224497:42)
at Module.90158 (C:\Users\aakas\Desktop\ArteryUniversal\dist\Universal\server\main.js:488:121)
at __webpack_require__ (C:\Users\aakas\Desktop\ArteryUniversal\dist\Universal\server\main.js:224497:42)
at Module.36747 (C:\Users\aakas\Desktop\ArteryUniversal\dist\Universal\server\main.js:641:77)
at __webpack_require__ (C:\Users\aakas\Desktop\ArteryUniversal\dist\Universal\server\main.js:224497:42)

修复方案

按优先级从高到低排列:

  • 方案1:平台判断隔离浏览器专属逻辑(推荐)
    Angular 内置了平台识别工具,仅在客户端环境下执行DOM、canvas相关操作,从根源上避免服务端调用不存在的API。
    实现步骤:

    1. 注入平台标识,调用isPlatformBrowser判断运行环境
    2. 将所有调用document、操作canvas的逻辑全部放入浏览器环境判断块内
      示例代码:
    import { Component, Inject, PLATFORM_ID } from '@angular/core';
    import { isPlatformBrowser } from '@angular/common';
    
    @Component({
      selector: 'app-canvas-demo',
      template: ''
    })
    export class CanvasDemoComponent {
      constructor(@Inject(PLATFORM_ID) private platformId: Object) {
        if (isPlatformBrowser(this.platformId)) {
          // 仅浏览器端执行
          const canvasElement = document.createElement('canvas');
          // 后续canvas绘图、第三方canvas库调用逻辑全部写在这里
        }
      }
    }
    

    如果报错来自引入的第三方canvas库,同样在判断块内动态加载库即可,避免服务端打包时执行库内的浏览器API代码。

  • 方案2:使用Angular封装的Renderer2操作DOM
    避免直接原生调用document,使用Angular官方提供的Renderer2API操作DOM,框架会自动适配不同运行环境,减少跨平台报错。
    示例代码:

    import { Component, Renderer2, ElementRef, AfterViewInit } from '@angular/core';
    import { isPlatformBrowser, PLATFORM_ID } from '@angular/common';
    
    @Component({
      selector: 'app-canvas-demo',
      template: ''
    })
    export class CanvasDemoComponent implements AfterViewInit {
      constructor(
        private renderer: Renderer2,
        private el: ElementRef,
        @Inject(PLATFORM_ID) private platformId: Object
      ) {}
    
      ngAfterViewInit(): void {
        // 视图初始化后执行,进一步降低服务端执行概率
        if (isPlatformBrowser(this.platformId)) {
          const canvas = this.renderer.createElement('canvas');
          this.renderer.appendChild(this.el.nativeElement, canvas);
          // 后续canvas操作
        }
      }
    }
    

    注意:Renderer2在服务端仅能生成空DOM节点,无法支持canvas绘图相关API,涉及绘图逻辑依然需要加平台判断。

  • 方案3:服务端注入DOM模拟对象兜底
    如果必须在服务端执行DOM相关逻辑,可以在服务端入口server.ts中提前挂载模拟的全局document对象。
    实现步骤:

    1. 安装服务端DOM模拟依赖:npm i domino
    2. 在server.ts最顶部、启动SSR服务前添加全局模拟配置:
    import * as fs from 'fs';
    import * as domino from 'domino';
    // 替换为你的项目browser端构建产物的index.html路径
    const browserIndex = fs.readFileSync('dist/Universal/browser/index.html').toString();
    const mockWindow = domino.createWindow(browserIndex);
    (global as any).window = mockWindow;
    (global as any).document = mockWindow.document;
    // 其他用到的BOM对象可按需在此挂载
    

    注意:模拟DOM和真实浏览器环境存在差异,canvas绘图、音视频等浏览器专属能力无法在服务端完整模拟,非必要不使用该方案。


内容的提问来源于stack exchange,提问作者Aakash Bhatt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 10:06:30