Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 9 Universal ReferenceError: window is not defined

I'm trying to setup SSR on angular 9 project with some third party librairies without success.

Below the error

ReferenceError: window is not defined
at ./node_modules/intl-tel-input/build/js/intlTelInput.js (main.js:295050:32)
at Object../node_modules/intl-tel-input/build/js/intlTelInput.js (main.js:295052:3)
at __webpack_require__ (main.js:20:30)
at Object../node_modules/intl-tel-input/index.js (main.js:296381:18)
at __webpack_require__ (main.js:20:30)
at Module../node_modules/intl-tel-input-ng/__ivy_ngcc__/fesm2015/intl-tel-input-ng.js (main.js:294832:72)
at __webpack_require__ (main.js:20:30)
    at Object.. main.js:463107:29)
    at __webpack_require__ (main.js:20:30)
    at Object.. main.js:462977:33)
A server error has occurred.
node exited with 1 code.
connect ECONNREFUSED 127.0.0.1:50362

I don't have access to window object on the server side, it's normal, so to avoid this error I'm checking the platform and using conditional logic in the components that need intl-tel-input lib ...without success.

How can I fix window, navigator, document error while SSR ?

below package.json file

    {
  "name": "dz",
  "version": "0.0.0",
  "scripts": {

    "compile:server_bak": "webpack --mode production --config webpack.server.config.js --progress --colors",
    "build:ssr_bak": "npm run build:client-and-server-bundles && npm run compile:server",
    "serve:ssr_bak": "node dist/server",
    "build:client-and-server-bundles_bak": "npm run build-prod && ng run dz:server:production",
    "dev:ssr": "ng run dz:serve-ssr",
    "serve:ssr": "node dist/server/main.js",
    "build:ssr": "ng build --prod && ng run dz:server:production",
    "prerender": "ng run dz:prerender"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^9.0.0",
    "@angular/cdk": "^9.0.0",
    "@angular/common": "^9.0.0",
    "@angular/compiler": "^9.0.0",
    "@angular/core": "^9.0.0",
    "@angular/forms": "^9.0.0",
    "@angular/google-maps": "^9.0.0-rc.0",
    "@angular/localize": "^9.0.0-next.5",
    "@angular/material": "^9.0.0",
    "@angular/platform-browser": "^9.0.0",
    "@angular/platform-browser-dynamic": "^9.0.0",
    "@angular/platform-server": "^9.0.0",
    "@angular/pwa": "^0.803.23",
    "@angular/router": "^9.0.0",
    "@angular/service-worker": "^9.0.0",
    "@kolkov/angular-editor": "^1.0.3",
    "@ng-bootstrap/ng-bootstrap": "^5.2.1",
    "@ng-toolkit/universal": "^8.0.3",
    "@nguniversal/common": "~9.0.0",
    "@nguniversal/express-engine": "^9.0.0",
    "@ngx-translate/core": "^11.0.1",
    "@ngx-translate/http-loader": "^4.0.0",
    "@nicky-lenaers/ngx-scroll-to": "^3.0.1",
    "@sentry/browser": "^5.11.1",
    "@smip/ngx-materialize": "^0.3.0",
    "@swimlane/ngx-charts": "^13.0.2",
    "@trilon/ng-universal": "^2.1.0",
    "@types/express": "^4.17.1",
    "@types/lodash": "^4.14.141",
    "acorn": "^7.1.0",
    "angular-calendar": "0.27.9",
    "angular-in-memory-web-api": "~0.9.0",
    "angular-resizable-element": "^3.3.0",
    "angular2-image-upload": "1.0.0-rc.2",
    "body-parser": "^1.19.0",
    "bootstrap": "^4.4.1",
    "calendar-utils": "0.7.0",
    "cookie-parser": "^1.4.4",
    "cookieconsent": "^3.1.1",
    "core-js": "^3.6.4",
    "cors": "~2.8.5",
    "date-fns": "^1.30.1",
    "domino": "^2.1.4",
    "express": "^4.17.1",
    "express-http-proxy": "^1.6.0",
    "font-awesome": "^4.7.0",
    "google-libphonenumber": "^3.2.6",
    "gzip-all": "^1.0.0",
    "imagesloaded": "^4.1.4",
    "intersection-observer": "^0.7.0",
    "intl-tel-input": "16.0.10",
    "intl-tel-input-ng": "0.1.0",
    "materialize-css": "^1.0.0",
    "mock-browser": "^0.92.14",
    "moment": "^2.24.0",
    "ng2-sticky-kit": "^6.1.0",
    "ngx-cookieconsent": "^2.2.3",
    "ngx-google-places-autocomplete": "^2.0.4",
    "ngx-lightbox": "^2.1.0",
    "ngx-moment": "^3.5.0",
    "ngx-pagination": "5.0.0",
    "ngx-progressbar": "^6.0.1",
    "ngx-quicklink": "^0.2.0",
    "ngx-scrollspy": "^1.2.1",
    "path": "^0.12.7",
    "popper.js": "^1.16.1",
    "positioning": "1.4.0",
    "preboot": "^7.0.0",
    "reflect-metadata": "^0.1.13",
    "rxjs": "^6.5.4",
    "rxjs-compat": "^6.5.4",
    "sweetalert2": "^9.7.0",
    "ts-helpers": "^1.1.2",
    "tslib": "^1.10.0",
    "typings": "^2.1.1",
    "webpack": "^4.41.5",
    "workbox-sw": "^4.3.1",
    "zone.js": "~0.10.2"
  },
  "devDependencies": {
    "@angular-devkit/architect": "^0.900.1",
    "@angular-devkit/build-angular": "^0.900.1",
    "@angular/cli": "^9.0.1",
    "@angular/compiler-cli": "^9.0.0",
    "@angular/language-service": "^9.0.0",
    "@types/jasminewd2": "~2.0.6",
    "@types/jquery": "^3.2.12",
    "firebase-tools": "^6.10.0",
    "fuzzy": "^0.1.3",
    "http-server": "^0.11.1",
    "inquirer": "^6.2.2",
    "inquirer-autocomplete-prompt": "^1.0.1",
    "jasmine-core": "~3.5.0",
    "jasmine-spec-reporter": "~4.2.1",
    "karma-jasmine": "~2.0.1",
    "karma-jasmine-html-reporter": "^1.5.1",
    "protractor": "~6.0.0",
    "ts-loader": "^5.4.5",
    "@nguniversal/builders": "^9.0.0",
    "@types/express": "^4.17.0",
    "@types/node": "^12.11.1",
    "@types/jasmine": "~3.5.0",
    "codelyzer": "^5.1.2",
    "karma": "~4.3.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage-istanbul-reporter": "~2.1.0",
    "ts-node": "~8.3.0",
    "tslint": "~5.17.0",
    "typescript": "~3.7.5",
    "webpack-cli": "^3.3.10",
    "webpack-node-externals": "^1.7.2"
  },
  "budgets": [
    {
      "type": "initial",
      "maximumWarning": "2mb",
      "maximumError": "5mb"
    }
  ]
}
like image 987
Franky Avatar asked Feb 12 '20 12:02

Franky


2 Answers

If you have mutiple components where you need window to be used. There is one more way to fix this error, where you need not to import or install any third party package.

Reason of this error is, while excuting or parsing the code at node server, window is not defined. So, to avoid that we can put if condition like this if (isPlatformBrowser(this.platformId)) which will be executed only when the script is running at browser level

import { isPlatformBrowser } from '@angular/common';


@Component({
  selector: 'space-app',
  templateUrl: './app.component.html'
})

export class AppComponent {

  constructor(
    @Inject(PLATFORM_ID) private platformId: any
  ) { }

  ngOnInit() {}

  onActivate() {
    if (isPlatformBrowser(this.platformId)) {
      window.scrollTo(0, 0);
    }
  }
}

This is for the places where you will be using window directly. But what if any third party angular package is using window that you aren't aware of. To prevent errors from those cases. We need to add a piece of code in server.ts

const path = require('path');
const domino = require('domino');
const templateA = fs.readFileSync(path.join('dist/browser', 'index.html')).toString();
const win = domino.createWindow(templateA);

global['window'] = win;
global['document'] = win.document;
// Express server
export const app = express();

But make sure the position of export const app = express() is correct

like image 151
Abhishek Tripathi Avatar answered Sep 19 '22 13:09

Abhishek Tripathi


Try using window object in this way

in .ts file import it

import { WINDOW } from '@ng-toolkit/universal';

then in constructor inject it

constructor(@Inject(WINDOW) public window: Window) {

}

and use it inside any function like below

getBlogs() {
    this.blogsService.getBlogs().subscribe((res) => {
      if (res.message === 'success') {
        this.blogs = res.data.blogs;
        this.window.scroll(0, 0);
      } else {
        console.log('No blogs');
      }
    }, (err) => {
      console.log(err);
    });
  }
like image 31
Nirali Avatar answered Sep 20 '22 13:09

Nirali