2

我正在将 simpleMDE 编辑器与我的 Angular 4 服务器端渲染应用程序一起使用,并使用获取 textarea 的参考

@ViewChild('simpleMDE') textarea : ElementRef;

并在 ngAfterViewInit() 中初始化它

   this.simplemde = new SimpleMDE(
      {
          element: this.textarea.nativeElement.value,
      })

在模板中使用这样的文本区域

<textarea id="simpleMDE" #simpleMDE></textarea> 

在启动服务器时,它的抛出错误说

projectpath\node_modules\codemirror\lib\codemirror.js:11
        typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
                                                                                 ^
ReferenceError: navigator is not defined
    at projectpath\node_modules\codemirror\lib\codemirror.js:18:17

请提出一些建议,我卡在这里。 GitHub 回购

4

4 回答 4

2

如 Angular 通用文档中所述

窗口、文档、导航器和其他浏览器类型 - 在服务器上不存在 - 因此使用它们或任何使用它们的库(例如 jQuery)将不起作用

如果您需要使用它们,请考虑将它们仅限于您的客户并根据情况进行包装。您可以使用使用 PLATFORM_ID 令牌注入的 Object 来检查当前平台是浏览器还是服务器。

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

 constructor(@Inject(PLATFORM_ID) private platformId: Object) { ... }

 ngOnInit() {
   if (isPlatformBrowser(this.platformId)) {
      // Client only code.
      ...
   }
   if (isPlatformServer(this.platformId)) {
     // Server only code.
     ...
   }
 }

需要操作图书馆:(

编辑:在以下行中,错误来自 codemirror.js

var userAgent = navigator.userAgent;
var platform = navigator.platform;

尝试操作该代码

if(navigator){
  var userAgent = navigator.userAgent;
  var platform = navigator.platform;
}else{
 var userAgent="server";
 var platform="server";
}

PS:不确定会产生什么影响:D。

于 2017-04-11T04:31:36.720 回答
2

猜猜你的 js/ts 文件中有这样的代码。

import CodeMirror from 'codemirror';

正如@Parth Ghiya 所回答的,navigator仅在浏览器中支持,这将导致错误。

在尝试支持服务器渲染时,您可以通过这种方式在代码中进行一些更改(惰性要求):

// just before places where are using codemirror
const CodeMirror = require('codemirror');   
require('codemirror/addon/hint/show-hint');

CodeMirror(...)
于 2017-04-11T05:38:50.910 回答
1

这是我处理这个问题的方法。对我来说,服务器渲染仅用于 SEO 目的。像 codemirror 这样的东西并没有真正对 SEO 做任何事情。因此,我的做法是“不在服务器端渲染”。

在此处输入图像描述 参考

基本结构如上图。

您有 2 个引导文件,一个用于服务器渲染,另一个用于客户端渲染。

因此,您实际上可以为每个引导文件拥有不同的应用程序模块。

在服务端渲染的应用模块中,您可以使用模拟组件来代替使用浏览器对象的组件,而使用真实的组件作为客户端。

这样您就不必担心服务器渲染上有问题的组件。

另一种解决方案是使用 webpack 来处理这些浏览器对象。

像这样的参考

module: {
  rules: [
    { 
      test: /@angular(\\|\/)material/, use: "imports-loader?window=>global,CSS=>null,navigator=>{get userAgent(){return Zone.current.get('req')['headers']['user-agent'];}}"
    }
  ]
}

就个人而言,我更喜欢第一种解决方案。第二个对我来说有点老套,在服务器端渲染一个与 SEO 无关的组件并没有真正给我们带来任何好处。

于 2017-07-04T17:12:38.410 回答
0

为了简单起见,只需输入

global['navigator'] = {} or global['navigator'] = {  userAgent: ''};

// ...

在 server.ts 文件的顶部。这样,它将忽略错误。

于 2019-07-13T03:22:00.637 回答