Using angular 7 universal with Openlayers 5

蹲街弑〆低调 提交于 2021-01-28 13:48:06

问题


I've got an angular 7.2 app using open layers 5.3. I'm trying to set up angular universal for this app, but when I run the universal server (node dist/server.js), I got some errors due to client only variables not being defined, such as window.

webpack:///./node_modules/ol/has.js?:54
var DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1;
                     ^
ReferenceError: window is not defined

I tried using domino to mock these variables, but it just fails with another error, because of a canvas element

Error: NotYetImplemented
   at HTMLCanvasElement.exports.nyi (/my/project/dist/server.js)

All the OL code is imported and used in a single MapComponent component. My imports look like this in this component:

import Map from 'ol/Map.js';
import View from 'ol/View.js';
import TileLayer from 'ol/layer/Tile.js';

My main problem is that the mentionned errors occur as soon as I run the universal server, so even before trying to access the universal rendered website in a browser.

Consequently, using something like this to only instantiate MapComponent when the app is running client side does not work, since the crash occurs before that

<app-map *ngIf="isBrowser"></app-map>

where the isBrowser variabled is initialised in the component with the value of isPlatformmBrowser(platformId)

Any suggestions?


回答1:


This is how I control over SSR in my app,

my component side,

    import { isPlatformBrowser } from '@angular/common';
    import * as JQuery from "jquery";


    constructor(
    @Inject(PLATFORM_ID) public platformId){...}      

    ngOnInit() {
      if (isPlatformBrowser(this.platformId)){
       var $: any = jQuery; //for example, load jQuery if you are sure about platform is browser
      }
     }

For example, I'm showing loading bar while ssr is not browser.

my template side,

<ssr-loading *ngIf="platformId != 'browser'"></ssr-loading>



回答2:


Try to use Openlayer latest version "ol": "^5.3.1",




回答3:


The error I had was caused by the pixelworks library, which is a dependency of OL 5.

This library instantiates a canvas and tries to get a 2d context from it, which is not supported by domino

var context = document.createElement('canvas').getContext('2d');

The context is not used straight away, but is created at a place where it is always instantiated.

Since I do not want to use OL when the code is executed server side, my solution was to modify the server.js file during the build process to remove this instantiation.

sed -i "s/var context = document.createElement('canvas').getContext('2d');/var context = null;/" dist/server.js

Note: domino is still needed because the modules exported from OL also try to access global variables, such as window




回答4:


Add to server.ts

const domino = require('domino');
const fs = require('fs');
const path = require('path');
const template = fs.readFileSync(path.join(__dirname, '.', 'dist', 'index.html')).toString();
const win = domino.createWindow(template);
const files = fs.readdirSync(`${process.cwd()}/dist-server`);
// const styleFiles = files.filter(file => file.startsWith('styles'));
// const hashStyle = styleFiles[0].split('.')[1];
// const style = fs.readFileSync(path.join(__dirname, '.', 'dist-server', `styles.${hashStyle}.bundle.css`)).toString();

global['window'] = win;
Object.defineProperty(win.document.body.style, 'transform', {
  value: () => {
    return {
      enumerable: true,
      configurable: true
    };
  },
});
global['document'] = win.document;
global['CSS'] = null;
// global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest;
global['Prism'] = null;


来源:https://stackoverflow.com/questions/55120373/using-angular-7-universal-with-openlayers-5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!