Angular Universal:未定义导航器
Posted
技术标签:
【中文标题】Angular Universal:未定义导航器【英文标题】:Angular Universal: navigator is not defined 【发布时间】:2018-09-25 02:29:49 【问题描述】:我按照官方 angular-cli tutorial 将 angular-universal 集成到我现有的 angular-cli 应用程序中。
我可以为我的 angular-cli 应用程序执行 s-s-r。但是当我尝试集成ngx-leaflet 时,我收到以下错误:
ReferenceError: 导航器未定义 在 D:\ng2-s-s-r-pwa\dist\server.js:40251:29
现在,我了解到传单正在尝试访问节点上下文中不可用的导航器对象。所以我决定延迟传单渲染,直到页面加载到浏览器中,如SO thread 中给出的那样。 但我仍然遇到同样的错误。您可以查看带有传单问题here 的演示应用程序。
./src/app/browserModuleLoader.service.ts:
import Component, Inject, Injectable, OnInit, PLATFORM_ID from '@angular/core';
import isPlatformBrowser, isPlatformServer from '@angular/common';
@Injectable()
export class BrowserModuleLoaderService
private _L: any;
public constructor(@Inject(PLATFORM_ID) private _platformId: Object)
this._init();
public getL()
return this._safeGet(() => this._L);
private _init()
if (isPlatformBrowser(this._platformId))
this._requireLegacyResources();
private _requireLegacyResources()
this._L = require('leaflet');
private _safeGet(getCallcack: () => any)
if (isPlatformServer(this._platformId))
throw new Error('invalid access to legacy component on server');
return getCallcack();
./src/app/leaflet/app/leaflet.component.ts:
// import * as L from 'leaflet';
import ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, PLATFORM_ID from '@angular/core';
import BrowserModuleLoaderService from '../browserModuleLoader.service';
import isPlatformBrowser from '@angular/common';
@Component(
selector: 'app-leaflet',
styleUrls: ['./leaflet.component.scss'],
template: `
<div *ngIf="isBrowser">
<div leaflet [leafletOptions]="options"></div>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
)
export class LeafletComponent
isBrowser: boolean;
options = ;
constructor(private cdr: ChangeDetectorRef,
@Inject(PLATFORM_ID) platformId: Object,
private browserModuleLoaderService: BrowserModuleLoaderService
)
this.isBrowser = isPlatformBrowser(platformId);
ngAfterViewInit()
console.log('this.isBrowser ', this.isBrowser);
if (this.isBrowser)
const L = this.browserModuleLoaderService.getL();
this.options =
layers: [
L.tileLayer('http://s.tile.openstreetmap.org/z/x/y.png', maxZoom: 18, attribution: '...' ),
],
zoom: 5,
center: L.latLng( lat: 38.991709, lng: -76.886109 ),
;
this.cdr.detach();
./src/app/app.component.html:
<div>
<app-leaflet></app-leaflet>
</div>
如何安全地延迟传单渲染,直到平台不是浏览器?
编辑:
我删除了所有与传单相关的代码(browserModuleLoader.service.ts、leaflet.component.ts 等),并且只在 app.module.ts 中保留传单模块导入,实际上这个导入导致了问题。
./src/app/app.module.ts:
import AppComponent from './app.component';
import BrowserModule from '@angular/platform-browser';
// import BrowserModuleLoaderService from './browserModuleLoader.service';
// import LeafletComponent from './leaflet/leaflet.component';
import LeafletModule from '@asymmetrik/ngx-leaflet';
import NgModule from '@angular/core';
@NgModule(
declarations: [
AppComponent,
// LeafletComponent
],
imports: [
BrowserModule.withServerTransition(appId: 'my-app'),
LeafletModule.forRoot()
],
providers: [
// BrowserModuleLoaderService
],
bootstrap: [AppComponent]
)
export class AppModule
./src/app/app.server.module.ts:
import AppComponent from './app.component';
import AppModule from './app.module';
import ModuleMapLoaderModule from '@nguniversal/module-map-ngfactory-loader';
import NgModule from '@angular/core';
import ServerModule from '@angular/platform-server';
@NgModule(
imports: [
AppModule,
ServerModule,
ModuleMapLoaderModule
],
bootstrap: [AppComponent],
)
export class AppServerModule
如何处理这个 nxg-leaflet 模块导入?
【问题讨论】:
不确定是否可行,但请尝试<div *ngIf="isBrowser" leaflet [leafletOptions]="options"></div>
还是同样的问题。
这是您唯一使用它的地方吗?另一个解决方案是不在你的 module.server.ts 文件中导入 ngx-leaflet 模块
我没有在 app.server.module.ts 中导入 ngx-leaflet,只在 app.module.ts 中导入。
在你的 app.server.module 中你没有导入 'app.module' ?如果不是,那么这意味着 ngx-lealeft 可能不是罪魁祸首。您应该查看 server.js 以尝试查看它的确切来源
【参考方案1】:
使用Mock Browser 解决了这个问题。
server.ts:
const MockBrowser = require('mock-browser').mocks.MockBrowser;
const mock = new MockBrowser();
global['navigator'] = mock.getNavigator();
【讨论】:
【参考方案2】:由(global as any).navigator = win.navigator;
修复,更加优雅,绝对是原生的,并且不依赖于过时的Mock Browser。
【讨论】:
是win.navigator
中的win
实际上是window
?我现在在运行我的角度 s-s-r 时遇到了这个问题。
@BelleZaid 我不记得所有的细节,除了它解决了:) 更多:github.com/angular/universal/issues/830#issuecomment-770369651
感谢@Daniel。在此之前我确实尝试过该问题中的评论,但仍然有导航器未定义错误。我对角度通用的东西很陌生。所以我找不到太多关于为什么这种情况持续存在的原因。
@BelleZaid 很遗憾听到,但 Angular Universal
的开发人员体验真的很差...
这是如果你使用多米诺,这需要你导入一个巨大的包【参考方案3】:
我也收到了 Angular Universal 的这个错误。使用上述解决方案中的模拟浏览器确实为我解决了这个错误,但它也启动了一个与 CommonJS 相关的新警告。我没有深入研究这个问题,而是意识到我已经在 server.ts 文件中使用了 Domino,因此我可以轻松地使用 Domino 设置导航器。这是最适合我的方法:
npm install domino
server.ts:
const domino = require('domino');
const fs = require('fs');
const path = require('path');
const template = fs
.readFileSync(path.join('dist/<your-app-name>/browser', 'index.html')) //<--- REPLACE WITH YOUR APP NAME
.toString();
const window = domino.createWindow(template);
global['window'] = window;
global['document'] = window.document;
global['navigator'] = window.navigator;
【讨论】:
以上是关于Angular Universal:未定义导航器的主要内容,如果未能解决你的问题,请参考以下文章
Angular Universal 错误 ReferenceError:未定义 MouseEvent
Angular5 webpack ReferenceError:未定义窗口
在 Angular 中需要 BrowserAnimationsModule 但在 Universal 中出现错误
Angular 2 Universal 404 Not Found 重定向