Search code examples
angularopenlayersangular-universalopenlayers-5

Using angular 7 universal with Openlayers 5


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?


Solution

  • 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