tinesoft/ngx-cookieconsent

Cannot read property 'initialise' of undefined in angular universal 10

nilot111 opened this issue · 4 comments

Bug Report or Feature Request (mark with an x)

- [x] bug report -> please search issues before submitting
- [ ] feature request

CookieConsent and Library Versions?

- cookieconsent version: 3.1.1
- ngx-cookieconsent version: 2.2.3

OS Version?

Windows 10

Angular, Node and al Versions?

Angular CLI: 10.0.3
Node: 14.5.0
OS: win32 x64
Angular: 10.0.4
... animations, common, compiler, compiler-cli, core, forms
... language-service, localize, platform-browser
... platform-browser-dynamic, platform-server, router
Ivy Workspace: Yes

Package Version

@angular-devkit/architect 0.1000.3
@angular-devkit/build-angular 0.1000.3
@angular-devkit/build-optimizer 0.1000.3
@angular-devkit/build-webpack 0.1000.3
@angular-devkit/core 10.0.3
@angular-devkit/schematics 10.0.3
@angular/cdk 10.1.3
@angular/cli 10.0.3
@ngtools/webpack 10.0.3
@nguniversal/builders 10.0.1
@nguniversal/common 10.0.1
@nguniversal/express-engine 10.0.1
@nguniversal/module-map-ngfactory-loader 8.2.6
@schematics/angular 10.0.3
@schematics/update 0.1000.3
rxjs 6.6.0
typescript 3.9.7
webpack 4.43.0

Repro steps

npm run build:ssr && npm run serve:ssr
Where:
"serve:ssr": "node dist/compy/server/main.js",
"build:ssr": "ng build --prod && ng run compy:server:production",

The log given by the failure

Node Express server listening on http://localhost:4000
ERROR TypeError: Cannot read property 'initialise' of undefined
at NgcCookieConsentService.init (C:\Coding\compyFront\dist\compy\server\main.js:1:3482889)
at new NgcCookieConsentService (C:\Coding\compyFront\dist\compy\server\main.js:1:3482119)
at Object.NgcCookieConsentService_Factory [as factory] (C:\Coding\compyFront\dist\compy\server\main.js:1:3484065)
at R3Injector.hydrate (C:\Coding\compyFront\dist\compy\server\main.js:1:2802301)
at R3Injector.get (C:\Coding\compyFront\dist\compy\server\main.js:1:2799033)
at NgModuleRef$1.get (C:\Coding\compyFront\dist\compy\server\main.js:1:2977443)
at Object.get (C:\Coding\compyFront\dist\compy\server\main.js:1:2946537)
at getOrCreateInjectable (C:\Coding\compyFront\dist\compy\server\main.js:1:2713691)
at Module.ɵɵdirectiveInject (C:\Coding\compyFront\dist\compy\server\main.js:1:2832947)
at NodeInjectorFactory.AppComponent_Factory [as factory] (C:\Coding\compyFront\dist\compy\server\main.js:1:1694986)

Desired functionality

I would like to run it without any problem in angular universal (server side rendering), since it is running perfect in regular angular.

Mention any other details that might be useful

It works great in regular app, but fail in universal angular app, so i think it is mainly due to trying to open up a window o dialog when running in server side mode. Or the other, it is possible that some way i need to add it in other places apart of angular.json config file.
Please any file you need just tell me , i just can not post entire project since it is private, but i can delivery single files without issue.
Thanks in advance.

A conditional check for global window object in cookieconsent.service.ts seems to be not working on a current Angular 10 server-side rendering.

My quick workaround was to add an empty function in server.ts.

const distFolder = join(process.cwd(), 'dist/browser');
const template = readFileSync(join(distFolder, 'index.html')).toString();
const domino = require('domino');
const win = domino.createWindow(template);

global['window'] = win;
global['window']['cookieconsent'] = { initialise: function () {
        console.warn('Cookie consent is not working on server side');
} };

This is sufficient to make the angular server working.

Thank you so much, that really works perfect. Just one more simple question, how do you solve to only show once? , since even when i accepted if i refresh it appears again, i suppose it should be something about saving cookies when accepting consent but not sure how to properly do it..

@nilot111: I've noticed that a cookie consent appears after refresh again just yesterday. Seems it worked fine (didn't appear after acceptance) in my previous angular not-SSR version. I'm still investigating why it's happening and how this plugin handles a one-time showing popup. If nothing helps I think I would use the browser's local storage to save the info about that user accepted cookies. Not perfect of course, but at my project, it's urgent to be fixed.

@nilot111: I found out that the plugin adds a "cookieconsent_status" field with value "dismiss" when user accepts cookies. It may be checked in Chrome Dev Tools > Application > Storage > Cookies.

I think that I've introduced the bug myself (bug when a cookie popup shows all the time). I changed a domain property in cookie config:

export const cookieConfig: NgcCookieConsentConfig = {
    cookie: {
        domain: environment.domain // previously was: `window.location.hostname`
    },
    ...
}

But I had to do that in order to fix a "window is undefined" issue in Angular SSR build. So probably the config update in a browser on the fly should work. Somewhere in app.component.ts:

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

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
   
    constructor(@Inject(PLATFORM_ID) private platformId: Object) {
    }
    
    ngOnInit() {
        if (isPlatformBrowser(PLATFORM_ID) {
            this.cookieService.getConfig().cookie.domain = window.location.hostname;
        }
    }
    ...
}