tinesoft / ngx-cookieconsent

Cookie :cookie: Consent module for Angular.
https://tinesoft.github.io/ngx-cookieconsent/
MIT License
163 stars 35 forks source link

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

Open nilot111 opened 3 years ago

nilot111 commented 3 years ago

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.

ihor-lev commented 3 years ago

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.

nilot111 commented 3 years ago

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..

ihor-lev commented 3 years ago

@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.

ihor-lev commented 3 years ago

@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;
        }
    }
    ...
}