Angular isPlatformBrowser 检查 PLATFORM_ID 不会阻止服务器端预渲染

Posted

技术标签:

【中文标题】Angular isPlatformBrowser 检查 PLATFORM_ID 不会阻止服务器端预渲染【英文标题】:Angular isPlatformBrowser checking against PLATFORM_ID doesn't prevent server-side pre rendering 【发布时间】:2017-10-04 08:37:20 【问题描述】:

我正在尝试编译基于此处示例项目创建的 Angular 4 + ASP.NET 通用应用程序,使用此提示 https://github.com/angular/universal#universal-gotchas 当我使用 webpack 构建项目,然后运行它时,会抛出错误,因为如果块检查了

isPlatformBrowser

在服务器端预渲染。如何在不进行预渲染的情况下在客户端有效地强制执行此代码,而其他与服务器端预渲染配合使用的代码则留在服务器端进行预渲染?

这是我的组件,其中 Leaflet 代码封装在条件块中,检查平台是否为浏览器。

import Component, OnInit, Inject from '@angular/core';
import  PLATFORM_ID  from '@angular/core';
import  isPlatformBrowser, isPlatformServer  from '@angular/common';
import * as L from 'leaflet';


@Component(
    selector: 'leaflet-map',
    templateUrl: 'leaflet-map.component.html',
    styleUrls: ['leaflet-map.component.css', '../../../..//node_modules/leaflet/dist/leaflet.css'],
)
export class LeafletMapComponent implements OnInit  

    constructor(@Inject(PLATFORM_ID) private _platformId: Object)   

    ngAfterViewInit()  


    

    ngOnInit()   
        if (isPlatformBrowser(this._platformId)) 
             L.map('leafletMap').setView([50.08, 19.93], 13);
        
        if (isPlatformServer(this._platformId)) 
            // Server only code.
            // https://github.com/angular/universal#universal-gotchas
        
    


【问题讨论】:

【参考方案1】:

您可以使用 *ngIf 从 DOM 中删除一些元素。将当前状态写入组件的属性并在 html 文件中检查。

component.ts

import  Component, Inject  from '@angular/core';
import  PLATFORM_ID  from '@angular/core';
import  isPlatformBrowser  from '@angular/common';

@Component(
  selector: 'mySpecial',
  templateUrl: './mySpecial.component.html'
)
export class MySpecialComponent 
  isBrowser: boolean;

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

component.html

<h2>Hello World</h2>
<p>
  <md-select *ngIf="isBrowser" placeholder="Favorite food" name="food">
    <md-option value="Steak">Steak</md-option>
    <md-option value="Pizza">Pizza</md-option>
    <md-option value="Tacos">Tacos</md-option>
  </md-select>
</p>

这将在服务器端创建一个不包含 md-select 的 DOM,因此不会失败。但请注意,这可能会导致用户看到的内容发生一些意想不到的变化,因为该网站将首先在没有元素的浏览器中呈现(因为这是服务器提供的内容),并且在加载 javascript 并且 angular 采取行动元素之后突然出现。

【讨论】:

以上是关于Angular isPlatformBrowser 检查 PLATFORM_ID 不会阻止服务器端预渲染的主要内容,如果未能解决你的问题,请参考以下文章

使用 Angular Universal 进行服务器端渲染的防御性编程思路

Angular篇—Angular1和Angular2的区别

从“@angular”而不是“angular2”导入 *

找不到模块'angular2/angular2'

Angular 6 和业力'无法加载“@angular-devkit/build-angular”,它未注册'

angular.js 的angular.copy angular.extend angular.merge