如何在Angular Universal服务端禁用@agm/core避免window未定义报错
解决Angular 12 Universal SSR集成@agm/core时window未定义报错方案
核心思路
服务端渲染环境不存在window、document等浏览器原生对象,而@agm/core内部强依赖这类对象,因此仅在客户端侧加载该模块,服务端侧用空逻辑替代即可规避报错。
步骤1:拆分模块导入逻辑,区分客户端/服务端加载范围
Angular Universal项目默认存在三个根模块,把@agm/core的导入从公共AppModule迁移到仅客户端生效的AppBrowserModule中:
AppModule:存放客户端、服务端通用的公共逻辑,移除原有的AgmCoreModule导入代码AppBrowserModule:客户端专用根模块,仅在浏览器环境加载,在此处导入@agm/coreAppServerModule:服务端专用根模块,仅在SSR服务端运行,无需导入@agm/core
app.browser.module.ts参考代码:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppModule } from './app.module'; import { AppComponent } from './app.component'; import { AgmCoreModule } from '@agm/core'; @NgModule({ imports: [ BrowserModule.withServerTransition({ appId: 'serverApp' }), AppModule, // 仅客户端加载@agm/core AgmCoreModule.forRoot({ apiKey: 'YOUR_API_KEY_HERE' }) ], bootstrap: [AppComponent], }) export class AppBrowserModule {}
步骤2:服务端添加Mock组件(可选)
如果服务端编译时提示agm-map不是已知组件,在app.server.module.ts中添加空占位组件避免编译报错:
import { NgModule, Component } from '@angular/core'; import { ServerModule } from '@angular/platform-server'; import { AppModule } from './app.module'; import { AppComponent } from './app.component'; // Mock agm-map组件,服务端渲染时返回空占位 @Component({ selector: 'agm-map', template: '' }) class MockAgmMapComponent {} @NgModule({ imports: [ AppModule, ServerModule, ], declarations: [MockAgmMapComponent], bootstrap: [AppComponent], }) export class AppServerModule {}
步骤3:模板内添加环境判断,避免渲染不匹配
在用到地图的组件中注入PLATFORM_ID判断运行环境,仅在客户端渲染时加载agm-map组件:
import { Component, Inject, PLATFORM_ID } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; @Component({ selector: 'app-map-page', template: ` <!-- 仅浏览器环境渲染地图 --> <agm-map *ngIf="isBrowser" [latitude]="lat" [longitude]="lng"></agm-map> ` }) export class MapPageComponent { isBrowser: boolean; lat = 51.678418; lng = 7.809007; constructor(@Inject(PLATFORM_ID) platformId: Object) { this.isBrowser = isPlatformBrowser(platformId); } }
注意:所有@agm/core相关的API调用都要放在判断
isBrowser为true之后执行,不要在constructor、ngOnInit等服务端会触发的生命周期中直接调用地图相关逻辑。
内容的提问来源于stack exchange,提问作者JuanDa237
相关产品推荐
相关产品推荐

