【问题标题】:window is not defined angular universal third library窗口未定义角通用第三库
【发布时间】:2017-10-20 13:12:17
【问题描述】:

我正在使用库 ng2-mqtt,我在我的组件中使用它,如下所示:

 import 'ng2-mqtt/mqttws31.js';
declare var Paho: any;

现在我收到以下错误:

ReferenceError: window is not defined
    at Object.<anonymous> (/Users/Picchu/Documents/em3/node_modules/ng2-mqtt/mqttws31.js:2143:4)
    at Module._compile (module.js:556:32)
    at Object.Module._extensions..js (module.js:565:10)
    at Module.load (module.js:473:32)
    at tryModuleLoad (module.js:432:12)
    at Function.Module._load (module.js:424:3)
    at Module.require (module.js:483:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/Picchu/Documents/em3/dist/server.js:18707:18)

我该如何解决这个问题?

【问题讨论】:

  • 您可以使用 angular/common 中的 isPlatformBrowser 有选择地仅在浏览器中运行这部分代码

标签: javascript angular typescript angular-universal


【解决方案1】:

避免服务器错误的一种可能方法是不渲染使用window 的组件(如果它是一个选项)。类似的东西:

<ng-container *ngIf="isBrowser">
   <!-- mqttws31-component -->
   <mqttws31-component></mqttws31-component> 
</ng-container>

isBrowser 可以从(ng2) 导入

import { isBrowser } from 'angular2-universal';

或者如果ng4+,你也可以在你的浏览器模块中定义这个:

// app.browser
@NgModule({
  providers: [
    { provide: 'isBrowser', useValue: true }
  ]
})

然后从构造函数注入

export class SomeComponent implements OnInit {
  constructor(@Inject('isBrowser') private isBrowser: boolean)
  ngOnInit() { 
    // example usage, this could be anywhere in this Component of course
    if (this.isBrowser) { 
      alert('we're in the browser!');
    }
}

【讨论】:

  • 使用最新的 Angular 版本,我们可以使用 Angular 提供的注入器,而不是手动提供 useValues。在下面提供了我的解决方案。
【解决方案2】:

更新

扩展 Leon Li 的回答,如果需要位置或窗口等浏览器 API,我们可以避免加载无法在服务器端呈现的组件。

This answer解释如何使用

import { PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser, isPlatformServer } from '@angular/common';

constructor( @Inject(PLATFORM_ID) platformId: Object) {
  this.isBrowser = isPlatformBrowser(platformId);
}

只需将 PLATFORM_ID 注入您的服务,并将其传递给 isPlatformBrowserisPlatformServer 以获取布尔值。因此,如果它们依赖于浏览器 API,您可以显示/隐藏无法在服务器上呈现的组件。

【讨论】:

    【解决方案3】:

    Angular 6 在 server.ts 中使用:

    const domino = require('domino');
    const fs = require('fs');
    const path = require('path');
    const template = fs.readFileSync('dist/browser/index.html').toString();
    const win = domino.createWindow(template);
    
    global['window'] = win;
    global['document'] = win.document;
    global['DOMTokenList'] = win.DOMTokenList;
    global['Node'] = win.Node;
    global['Text'] = win.Text;
    global['HTMLElement'] = win.HTMLElement;
    global['navigator'] = win.navigator;
    

    【讨论】:

    • 这适用于 Angular 通用 ssr 吗?
    • 刚刚在 Angular Universal SSR 上试过,但现在我遇到了一个新错误 ReferenceError: SVG is not defined
    【解决方案4】:

    window 不应该在服务器端的通用应用程序中使用,因为 Node.js 没有 window,并且拥有一个虚拟的 global.window 目前会影响 Angular 检测全局变量的方式。

    如果包使用window,则可以在其存储库中打开问题和/或将其分叉并更改为不使用window

    由于依赖window 的包通常依赖于客户端特定的东西,因此即使解决了这个问题,它们也不会在服务器端按预期工作。

    Package description 说:

    取决于库来自:https://eclipse.org/paho/clients/js/

    虽然library description 说:

    Paho JavaScript 客户端是一个 MQTT基于浏览器的客户端库,用 Javascript 编写,使用 WebSockets 连接到 MQTT 代理。

    通常不应在服务器端按预期工作的第三方 Angular 模块应该被存根或模拟;在app.server.ts 中导入带有虚假指令和服务的虚拟模块,而不是真正的模块。

    【讨论】:

    • 好吧,我不太明白。有没有办法解决这个问题?我应该在我的 node.js 应用程序中创建一个 globa 变量窗口吗?我应该如何以及在哪里执行此操作?
    • 见最后一段。它适用于你的情况。这完全取决于该模块在您的应用程序中的使用方式,即该模块如何影响在服务器端生成的页面。另外,考虑打开一个问题。供应商有责任提供一个不会导致通用应用出错的模块。
    • 我已经在 repo 中打开了这个问题。我将该模块用作客户端,但错误发生在服务器端。我不确定如何解决这个问题。但是感谢您的帮助
    • 不要在服务器应用程序中导入ng2-mqtt 模块。如果它的导入导致Paho 全局变量(我猜是),请在服务器应用程序中创建虚拟global.Paho 变量,以存根或模拟此模块预期的行为。实际上,我在这个模块中看不到任何特定于 Angular 的东西,即使它有 ng2 前缀。它只是一个暴露全局变量的库(这就是全局变量不好的原因)。
    • 重点是Paho global 不应该工作,因为真正的ng2-mqtt 不应该在服务器端导入。相反,Paho global 应替换为模块的虚拟实现。因为真正的 ng2-mqtt 不能在 Node.js 中工作。
    【解决方案5】:

    为我工作ng9+

    // app.module.ts
    @NgModule({
      providers: [
        { provide: 'isBrowser', useValue: true }
      ]
    })
    

    并替换绝对路径(先去掉/):

    /assets/images/... 到 assets/images/...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-01
      • 2021-10-06
      • 2019-06-03
      • 2021-01-15
      相关资源
      最近更新 更多