Window is not defined in Angular

5.9k Views Asked by At

I am trying to implement Server side rendering in my Angular project using angular universal, for that I referred to the documentation but am quite not able to proceed further as on executing npm run dev:ssr I am getting bundles generated but process fails complete execution due to an error which is

D:\CMS_clone1\CMS\CMSBIZ_admin_interface\dist\angular11-sample-app\server\main.js:100191
window.dataLayer = window.dataLayer || {};
^

ReferenceError: window is not defined
   at Module.9vUh (D:\CMS_clone1\CMS\CMSBIZ_admin_interface\dist\angular11-sample-app\server\main.js:100191:1)
   at __webpack_require__ (D:\CMS_clone1\CMS\CMSBIZ_admin_interface\dist\angular11-sample-app\server\main.js:26:30)
   at Module.vY5A (D:\CMS_clone1\CMS\CMSBIZ_admin_interface\dist\angular11-sample-app\server\main.js:382815:78)
   at __webpack_require__ (D:\CMS_clone1\CMS\CMSBIZ_admin_interface\dist\angular11-sample-app\server\main.js:26:30)
   at Module.ZAI4 (D:\CMS_clone1\CMS\CMSBIZ_admin_interface\dist\angular11-sample-app\server\main.js:236347:78)
   at __webpack_require__ (D:\CMS_clone1\CMS\CMSBIZ_admin_interface\dist\angular11-sample-app\server\main.js:26:30)
   at Module.24aS (D:\CMS_clone1\CMS\CMSBIZ_admin_interface\dist\angular11-sample-app\server\main.js:51247:69)
   at __webpack_require__ (D:\CMS_clone1\CMS\CMSBIZ_admin_interface\dist\angular11-sample-app\server\main.js:26:30)
   at Module.K011 (D:\CMS_clone1\CMS\CMSBIZ_admin_interface\dist\angular11-sample-app\server\main.js:174790:80)
   at __webpack_require__ (D:\CMS_clone1\CMS\CMSBIZ_admin_interface\dist\angular11-sample-app\server\main.js:26:30)

A server error has occurred.
node exited with 1 code.
connect ECONNREFUSED 127.0.0.1:59092

I am stuck at this for a couple of days now, I tried a few suggestions related to domino, mockBrowser but neither seemed to help, If anyone can possibly help me out to resolve this issue of mine it would be a lot helpful. Thanking in advance.

3

There are 3 best solutions below

1
On

I had the same issue a few weeks back. SSR doesn't have any idea as to what a window or document is, so I added the following into server.ts:

const MockBrowser = require('mock-browser').mocks.MockBrowser;
const mock = new MockBrowser();
global['window'] = mock.getWindow();

// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));

0
On

Here is my server.ts file, I have added all the code, basically create window is giving the error most of the time. Once am able to compile the code. Then am able to access the window and local storage.

import 'localstorage-polyfill'
import { existsSync } from 'fs'
import { join } from 'path'

import 'zone.js/dist/zone-node'
import { ngExpressEngine } from '@nguniversal/express-engine'
import express from 'express'

import { createWindow } from 'domino'
const indexHtml = join(process.cwd(), 'dist/nbinar/browser/index2.html')
const win = createWindow(indexHtml)

// Polyfills
;(global as any).window = win
;(global as any).document = win.document
;(global as any).navigator = win.navigator

// needs to be after window definition
import { AppServerModule } from './src/main.server'

import { APP_BASE_HREF } from '@angular/common'

// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
  global['localStorage'] = localStorage
  const server = express()
  const distFolder = join(process.cwd(), 'dist/notus-angular/browser')
  const indexHtml = existsSync(join(distFolder, 'index.original.html'))
    ? 'index.original.html'
    : 'index'

  // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
  server.engine('html', (_, options: { req: any }, callback) => {
    const engine = ngExpressEngine({
      bootstrap: AppServerModule,
      providers: [
        { provide: 'request', useFactory: () => options.req as any, deps: [] }
      ]
    })
    engine(_, options, callback)
  })

  server.set('view engine', 'html')
  server.set('views', distFolder)

  // Example Express Rest API endpoints
  // server.get('/api/**', (req, res) => { });
  // Serve static files from /browser
  server.get(
    '*.*',
    express.static(distFolder, {
      maxAge: '1y'
    })
  )

  // All regular routes use the Universal engine
  server.get('*', (req, res) => {
    res.render(indexHtml, {
      req,
      providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }]
    })
  })

  return server
}

function run(): void {
  const port = process.env['PORT'] || 4000

  // Start up the Node server
  const server = app()
  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`)
  })
}

// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire
const mainModule = __non_webpack_require__.main
const moduleFilename = (mainModule && mainModule.filename) || ''
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
  run()
}

export * from './src/main.server'

0
On

I use a component called bs-stepper which needs window at load time, I try the @Fizz-Pop-Bang solution but it still have the problem because the main problem is the order how webpack loads the components, so I have to do a module import instead a require import, so I write the following workaround.

File src/browser-polyfill.ts

const MockBrowser = require('mock-browser').mocks.MockBrowser;
const browser = new MockBrowser();

global['window'] = browser.getWindow();
global['document'] = browser.getDocument();

File server.ts

// at the top of the imports/file
import './src/browser-polyfill';