Angular Universal运行npm run dev:ssr报window.addEventListener不存在错误
问题原因
Angular SSR(服务端渲染)运行在Node.js环境中,该环境不存在浏览器特有的window、document等全局对象。你遇到的报错是代码在服务端执行时尝试访问window.addEventListener导致的,从报错栈的supportsPassiveEventListeners方法可以定位到问题根源是hammerjs库(你项目依赖中安装了hammerjs,同时Angular Material部分组件依赖它做手势识别),另外你项目中引入的ngx-perfect-scrollbar、croppie、html2canvas等仅能在浏览器端运行的库,也可能触发同类问题。
解决方案
1. 全局Mock服务端缺失的浏览器对象(临时快速解决)
在服务端入口文件server.ts顶部添加window、document等对象的模拟定义:
const MockBrowser = require('mock-browser').mocks.MockBrowser; const mock = new MockBrowser(); global.window = mock.getWindow(); global.document = mock.getDocument(); global.navigator = mock.getNavigator(); // 补充addEventListener的空实现 global.window.addEventListener = () => {};
先安装对应的依赖包:npm i mock-browser --save
2. 仅在浏览器端加载依赖库(推荐,性能更优)
第一步:移除全局导入的问题库
删除项目中全局import 'hammerjs'这类代码,改为仅在浏览器环境动态导入。
第二步:使用Angular平台判断API隔离执行逻辑
封装平台判断,仅在浏览器端执行浏览器专属逻辑:
import { isPlatformBrowser } from '@angular/common'; import { PLATFORM_ID, Inject, Component } from '@angular/core'; @Component({ // 组件配置 }) export class YourComponent { isBrowser: boolean; constructor(@Inject(PLATFORM_ID) private platformId: Object) { this.isBrowser = isPlatformBrowser(this.platformId); if (this.isBrowser) { // 仅在浏览器端导入和初始化hammerjs、scrollbar等浏览器专属库 import('hammerjs'); // 所有DOM操作、第三方前端库初始化逻辑都放在这个判断里 } } }
第三步:服务端跳过渲染浏览器专属组件
对使用了浏览器专属库的组件添加渲染判断,服务端渲染时不加载这部分内容:
<ngx-perfect-scrollbar *ngIf="isBrowser"> <!-- 组件内部内容 --> </ngx-perfect-scrollbar>
3. Angular Material手势兼容处理
如果是Angular Material依赖的hammerjs触发的问题,可以在服务端模块app.server.module.ts中禁用服务端的Hammer手势支持:
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; import { ServerModule } from '@angular/platform-server'; import { AppModule } from './app.module'; import { AppComponent } from './app.component'; import { HAMMER_GESTURE_CONFIG } from '@angular/platform-browser'; @NgModule({ imports: [ AppModule, ServerModule, ], bootstrap: [AppComponent], schemas: [NO_ERRORS_SCHEMA], providers: [ { provide: HAMMER_GESTURE_CONFIG, useValue: { events: [], overrides: {} } } ] }) export class AppServerModule {}
修改完成后重新执行npm run dev:ssr即可正常启动服务。
内容的提问来源于stack exchange,提问作者Ranjiz kumar
相关产品推荐
相关产品推荐

