Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSR "window is not defined" Error in Angular 18 after Build and Serve #29885

Closed
sonu-mamsys opened this issue Mar 19, 2025 · 5 comments
Closed
Labels
needs: repro steps We cannot reproduce the issue with the information given

Comments

@sonu-mamsys
Copy link

Which @angular/* package(s) are the source of the bug?

compiler-cli

Is this a regression?

Yes

Description

After upgrading to Angular 18 from Angular 15 and building an Angular SSR (Server-Side Rendering) application, I encountered a ReferenceError: window is not defined when running the application with npm run serve:ssr. The error appears to be caused by server-side code attempting to access the window object, which is not available in the server environment.

angular.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "cli": {
    "analytics": false
  },
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "myangularapp": {
      "projectType": "application",
      "schematics": {},
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/myangularapp/browser",
            "index": "src/index.html",    
            "main": "src/main.ts",       
            "polyfills": ["src/polyfills.ts"],
            "tsConfig": "tsconfig.app.json",
						"assets": [
              "src/favicon.ico",
              "src/favicon-alert.ico",
              "src/ads.txt",
              "src/robots.txt",
              "src/assets",
              "src/manifest.json",
              "src/manifest.webmanifest",
              "src/sitemaps",
              {
                "glob": "**/*",
                "input": "src/assets/",
                "output": "/assets/"
              }
            ],
            "styles": [],
            "scripts":  [],
            "extractLicenses": false,
            "sourceMap": false,
            "optimization": false,
            "namedChunks": true

          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "namedChunks": false,
              "extractLicenses": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "10mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "6kb",
                  "maximumError": "105kb"
                }
              ],
              "serviceWorker": true,
              "ngswConfigPath": "ngsw-config.json"
            }
          },
          "defaultConfiguration": ""
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "disableHostCheck": true,
            "buildTarget": "myangularapp:build"
          },
          "configurations": {
            "production": {
              "buildTarget": "myangularapp:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "buildTarget": "myangularapp:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.spec.json",
            "karmaConfig": "karma.conf.js",
						"assets": [
              "src/favicon.ico",
              "src/ads.txt",
              "src/robots.txt",
              "src/assets",
              "src/manifest.json",
              "src/manifest.webmanifest",
              "src/sitemaps"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          }
        },
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "myangularapp:serve"
          },
          "configurations": {
            "production": {
              "devServerTarget": "myangularapp:serve:production"
            }
          }
        },
        "server": {
          "builder": "@angular-devkit/build-angular:server",
          "options": {
            "outputPath": "dist/myangularapp/server",
            "main": "server.ts",
            "tsConfig": "tsconfig.server.json",
            "sourceMap": false,
            "optimization": false,
            "buildOptimizer": false
          },
          "configurations": {
            "production": {
              "outputHashing": "media",
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "sourceMap": false,
              "optimization": true,
              "buildOptimizer": true
            }
          },
          "defaultConfiguration": ""
        },
        "serve-ssr": {
          "builder": "@angular-devkit/build-angular:ssr-dev-server",
          "options": {
            "browserTarget": "myangularapp:build",
            "serverTarget": "myangularapp:server"
          },
          "configurations": {
            "production": {
              "browserTarget": "myangularapp:build:production",
              "serverTarget": "myangularapp:server:production"
            }
          }
        },
        "prerender": {
          "builder": "@angular-devkit/build-angular:prerender",
          "options": {
            "browserTarget": "myangularapp:build:production",
            "serverTarget": "myangularapp:server:production",
            "routes": [
              "/"
            ]
          },
          "configurations": {
            "production": {}
          }
        }
      }
    }
  }
}

package.json scripts

"scripts": {
    "ng": "ng",
    "start": "ng serve  --live-reload=false --host 0.0.0.0 --port 4205",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "serve:ssr": "node dist/myangularapp/server/main.js"
  },

Please provide a link to a minimal reproduction of the bug

No response

Please provide the exception or error you saw


Please provide the environment you discovered this bug in (run ng version)

_                      _                 ____ _     ___ 
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | | 
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | | 
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI: 18.2.15
Node: 20.18.3
Package Manager: npm 10.8.2
OS: win32 x64

Angular: 18.2.13
... animations, common, compiler, compiler-cli, core
... platform-browser, platform-browser-dynamic, platform-server
... router, service-worker

Package                            Version
------------------------------------------------------------
@angular-devkit/architect          0.1802.15
@angular-devkit/build-angular      18.2.15
@angular-devkit/core               18.2.15
@angular-devkit/schematics         18.2.15
@angular/cdk                       18.2.14
@angular/cli                       18.2.15
@angular/forms                     19.2.2
@angular/google-maps               18.2.14
@angular/material                  16.2.14
@angular/material-moment-adapter   18.2.14
@angular/ssr                       18.2.15
@schematics/angular                18.2.15
rxjs                               7.8.1
typescript                         5.5.4
zone.js                            0.14.10

Anything else?

No response

@alan-agius4 alan-agius4 transferred this issue from angular/angular Mar 19, 2025
@alan-agius4
Copy link
Collaborator

This seems like a bug but we'll need to look at a reproduction to find and fix the problem. Can you setup a minimal repro please?

You can read here why this is needed. A good way to make a minimal repro is to create a new app via ng new repro-app and adding the minimum possible code to show the problem. Then you can push this repository to github and link it here.

This might be related to your directory structure so its really important to get an accurate repro to diagnose this.

@alan-agius4 alan-agius4 added the needs: repro steps We cannot reproduce the issue with the information given label Mar 19, 2025
@sonu-mamsys
Copy link
Author

This seems like a bug but we'll need to look at a reproduction to find and fix the problem. Can you setup a minimal repro please?

You can read here why this is needed. A good way to make a minimal repro is to create a new app via ng new repro-app and adding the minimum possible code to show the problem. Then you can push this repository to github and link it here.

This might be related to your directory structure so its really important to get an accurate repro to diagnose this.

Sorry, but as I mentioned earlier, since we were on Angular 15 and upgraded to Angular 18, I won't be able to reproduce this issue.

What I can share is that we have tried different fixes:

  1. Adding the following in app.component.ts:

    if (globalThis.window === undefined) {
      globalThis.window = {
        addEventListener: () => {},
        // add more methods as needed
      } as never;
    }
  2. Adding the Domino window in server.ts:

I can also provide other TypeScript configuration files if you'd like.

Here are the configuration files:


1. tsconfig.json

/* To learn more about this file, see: https://angular.io/config/tsconfig. */
{
  "compileOnSave": true,
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "@app/*": [
        "app/*"
      ]
    },
    "outDir": "./dist/out-tsc",
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "skipLibCheck": true,
    "importHelpers": true,
    "target": "ES2022",
    "module": "es2020",
    "lib": [
      "es2018",
      "dom"
    ],
    "useDefineForClassFields": false
  },
  "angularCompilerOptions": {
    "enableI18nLegacyMessageIdFormat": false
  }
}

2. tsconfig.server.json

/* To learn more about this file, see: https://angular.io/config/tsconfig. */
{
  "extends": "./tsconfig.app.json",
  "compilerOptions": {
    "outDir": "./out-tsc/server",
    "types": [
      "node"
    ]
  },
  "files": [
    "src/main.server.ts",
    "server.ts"
  ],
  "angularCompilerOptions": {
    "entryModule": "./src/app/app.server.module#AppServerModule"
  }
}

3. tsconfig.app.json

/* To learn more about this file, see: https://angular.io/config/tsconfig. */
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/app",
    "types": []
  },
  "angularCompilerOptions": {
    "fullTemplateTypeCheck": false
  },
  "files": [
    "src/main.ts",
    "src/polyfills.ts"
  ],
  "include": [
    "src/**/*.d.ts"
  ]
}

Let me know if you need further clarification or additional files

@alan-agius4
Copy link
Collaborator

alan-agius4 commented Mar 19, 2025

If general if you need to access browser-only APIs or manipulate the DOM directly, the dedicated hooks should be used:

Unfortunately, without a minimal reproduction, there’s not much we can investigate.

@sonu-mamsys
Copy link
Author

If general if you need to access browser-only APIs or manipulate the DOM directly, the dedicated hooks should be used:

Unfortunately, without a minimal reproduction, there’s not much we can investigate.

Ok, so what’s the best way to update my current Angular project to Angular 17 SSR using NgModule-based modules, without standalone components or ESBuild, and keeping only Webpack? I followed the Angular upgrade guide, but I don’t have any info on doing it the way I want.

@alan-agius4
Copy link
Collaborator

The above mentioned hooks also with NgModules.

Ultimately, without a reproduction, it's impossible to understand what the problem is.

@alan-agius4 alan-agius4 closed this as not planned Won't fix, can't repro, duplicate, stale Mar 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs: repro steps We cannot reproduce the issue with the information given
Projects
None yet
Development

No branches or pull requests

2 participants