代码之家  ›  专栏  ›  技术社区  ›  Saurabh Palatkar

角度通用:未定义导航器

  •  13
  • Saurabh Palatkar  · 技术社区  · 6 年前

    我遵循官方的angular cli tutorial 将angular universal集成到现有angular cli应用程序。

    我能够为angular cli应用程序执行SSR。但当我尝试整合时 ngx-leaflet ,我收到以下错误:

    ReferenceError:未定义导航器 位于D:\ng2 ssr pwa\dist\server。js:40251:29

    现在,我了解到传单正在尝试访问节点上下文中不可用的navigator对象。所以我决定推迟传单的呈现,直到页面加载到浏览器中,如图所示 SO thread 。 但我还是犯了同样的错误。您可以查看带有传单发行的演示应用程序 here

    /src/app/browserModuleLoader。服务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/传单/app/传单。组成部分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。组成部分html:

    <div>
      <app-leaflet></app-leaflet>
    </div>
    

    如何安全地延迟传单渲染,直到平台不是浏览器?

    编辑:

    我删除了与传单相关的所有代码(browserModuleLoader.service.ts、spool.component.ts等)并在应用程序中仅保留传单模块导入。单元实际上,这个导入导致了问题。

    /src/app/app。单元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。服务器单元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传单模块导入?

    3 回复  |  直到 6 年前
        1
  •  11
  •   Saurabh Palatkar    6 年前

    通过使用解决了此问题 Mock Browser

    服务器ts:

    const MockBrowser = require('mock-browser').mocks.MockBrowser;
    const mock = new MockBrowser();
    
    
    global['navigator'] = mock.getNavigator();
    
        2
  •  0
  •   Daniel Danielecki    3 年前

    固定人 (global as any).navigator = win.navigator; ,更加优雅,绝对地道,不依赖过时的 Mock Browser

        3
  •  0
  •   CICSolutions    3 年前

    我也收到了这个角度通用的错误。使用上述解决方案中的模拟浏览器确实为我修复了这个错误,但它也启动了一个与CommonJS相关的新警告。我没有深入研究这个问题,而是意识到我已经在服务器中使用了Domino。ts文件,因此我可以轻松地使用Domino设置导航器。这是对我最有效的方法:

    npm install domino

    服务器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;