0

I'm adding Raygun.io APM to our Angular 8 app with Angular Universal.

It is known that raygun.io has a client side javascript library and to add this to a Angular with Universal, DOM window API must be created. This can be done using domino npm using this code below:

There is also an installation guide for Angular via npm called raygun4js however the problem still exists.

// Domino for defining Windows API in SSR 
(found @ https://www.npmjs.com/package/domino )

const domino = require('domino');
const fs = require('fs');
const path = require('path');
const template = fs.readFileSync(index.html).toString();
const win = domino.createWindow(template);

global['window'] = win; // will be used for NodeJS to read Window API
global['document'] = win.document;

*domino creates a window api and sets it to a global called win. After adding this line to an NPM project server.ts, build and run command - an exception is found:

  Raygun.Utilities = raygunUtilityFactory(window, Raygun);
  ^

ReferenceError: raygunUtilityFactory is not defined

This roots that a raygunUtilityFactory function is not defined within window API. Looking inside raygun.js in Github

window.raygunUtilityFactory = function(window, Raygun) {
  var rg = {
    getUuid: function() {
      function _p8(s) {
        var p = (Math.random().toString(16) + '000000000').substr(2, 8);
        return s ? '-' + p.substr(0, 4) + '-' + p.substr(4, 4) : p;
      }

 // more code.....

Question is, how can NodeJS read raygunUtilityFactory function during build if it can't find it in window API?

UPDATE: I tried to do this on a smaller project but it seems that even its document for installing raygun.io doesn't include procedures for Angular Universal. It basically can't detect window API using domino

  Raygun.Utilities = raygunUtilityFactory(window, Raygun);
  ^

ReferenceError: raygunUtilityFactory is not defined

2 Answers2

0

Answer: Setting Raygun js as a global object and referencing it to a declared variable inside a service.

Reference: https://hackernoon.com/how-to-use-javascript-libraries-in-angular-2-apps-ff274ba601af

declare var rg4js: any;

*place this inside your service or your main component ts.

<script type="text/javascript">
  !function(a,b,c,d,e,f,g,h){a.RaygunObject=e,a[e]=a[e]||function(){
  (a[e].o=a[e].o||[]).push(arguments)},f=b.createElement(c),g=b.getElementsByTagName(c)[0],
  f.async=1,f.src=d,g.parentNode.insertBefore(f,g),h=a.onerror,a.onerror=function(b,c,d,f,g){
  h&&h(b,c,d,f,g),g||(g=new Error(b)),a[e].q=a[e].q||[],a[e].q.push({
  e:g})}}(window,document,"script","//cdn.raygun.io/raygun4js/raygun.min.js","rg4js");
</script>

*add this to your index.html or download and add it to your project.

Do take note that the raygun script should be referenced as rg4js. Angular will automatically know that the rg4js inside your TS file is reference to your raygun script tag.

-- I'm now able to see the crash reporting and the pulse monitoring inside our client dashboard. However, I noticed that all client side errors logs are not caught. I'm still researching way to send these unhandled errors - starting with windows.onerror.

0

Good to hear you have figured out part of the solution!

AngularJS captures a lot of errors under the hood automatically and to properly capture errors you will need to register your own angular error handler and when the callback is fired you can use the Raygun4JS send method to send the message to Raygun.

export class RaygunErrorHandler implements ErrorHandler {
  handleError(e: any) {
    rg4js('send', {
      error: e,
    });
  }
}

Raygun has a little bit of angular documentation but can't import raygun4js via npm for Angular Universal (as per your discovery) so you will need to modify the examples shown. That said they should provide a good starting point.

  • They had an update for Angular 2+ and it works for most cases but if you're using Universal, adding a custom handler for error will not work and will mostly display an error – ALBlancoIV Jun 04 '20 at 11:14