universal: "Window is not defined" even when isPlatformBrowser used.
đ Bug report
What modules are related to this issue?
- aspnetcore-engine
- builders
- common
- express-engine
- hapi-engine
- module-map-ngfactory-loader
Is this a regression?
Yes the project worked correctly in all circumstances in Angular 8.1.1
Description
Large Angular 8 application with SSR support. Upgraded to Angular 9. All migration scripts related to my project ran and worked correctly with no errors.
Project works fine with ng serve and builds fine when targeting SSR with the command:
NODE_OPTIONS=--max-old-space-size=8192 ng build --source-map --configuration=development && ng run front:server:development
.
When I try to run the resulting server (to host with express / express-engine) it gives the âWindow not definedâ because of a reference in a third party module. All uses of that module are guarded with an âisPlatformBrowserâ check.
đŹ Minimal Reproduction
Seemingly you just have to include any module that references 3rd party modules that try to access âwindowâ. Note that this did not cause any problem in Angular 8 as long as you guarded against use of those modules with âisPlatformBrowserâ checks.
Now it seems merely having the module referenced is enough.
Set up a vanilla universal app and then add any angular module that references any non-angular JS module that makes a call to window. Note that this will cause the problem even if the angular module is correctly using isPlatformBrowser
.
https://github.com/jasonburrows/angularUniversal1675.git
đ„ Exception or Error
> front@2.30.0 servedev:ssr /Users/me/Development/front
> NODE_ENV=dev node dist/server/main
/Users/me/Development/front/dist/server/main.js:200603
}( window, function factory( Outlayer, getSize ) {
^
ReferenceError: window is not defined
at Object../node_modules/masonry-layout/masonry.js (/Users/me/Development/front/dist/server/main.js:200603:4)
at __webpack_require__ (/Users/me/Development/front/dist/server/main.js:20:30)
at Module../node_modules/ngx-masonry/__ivy_ngcc__/fesm2015/ngx-masonry.js (/Users/me/Development/front/dist/server/main.js:225304:72)
at __webpack_require__ (/Users/me/Development/front/dist/server/main.js:20:30)
at Object../src/modules/core/core.module.ts (/Users/me/Development/front/dist/server/main.js:286092:23)
at __webpack_require__ (/Users/me/Development/front/dist/server/main.js:20:30)
at Object../src/app/app.module.ts (/Users/me/Development/front/dist/server/main.js:276737:23)
at __webpack_require__ (/Users/me/Development/front/dist/server/main.js:20:30)
at Object../src/app/app.server.module.ts (/Users/me/Development/front/dist/server/main.js:276890:22)
at __webpack_require__ (/Users/me/Development/front/dist/server/main.js:20:30)
at Object../src/main.server.ts (/Users/me/Development/front/dist/server/main.js:277166:27)
at __webpack_require__ (/Users/me/Development/front/dist/server/main.js:20:30)
at Object../server.ts (/Users/me/Development/front/dist/server/main.js:276464:23)
at __webpack_require__ (/Users/me/Development/front/dist/server/main.js:20:30)
at Object.0 (/Users/me/Development/front/dist/server/main.js:354592:18)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! front@2.30.0 servedev:ssr: `NODE_ENV=dev node dist/server/main`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the front@2.30.0 servedev:ssr script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/me/.npm/_logs/2020-05-11T15_57_49_863Z-debug.log
đ Your Environment
ng:analytics getGlobalAnalytics +0ms
ng:analytics Client Analytics config found: false +26ms
ng:analytics Analytics disabled. Ignoring all analytics. +1ms
ng:analytics getSharedAnalytics +0ms
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ âł \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI: 9.1.5
Node: 12.16.2
OS: darwin x64
Angular: 9.1.6
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... platform-server, router
Ivy Workspace: Yes
Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.901.5
@angular-devkit/build-angular 0.901.5
@angular-devkit/build-optimizer 0.901.5
@angular-devkit/build-webpack 0.901.5
@angular-devkit/core 9.1.5
@angular-devkit/schematics 9.1.5
@angular/cdk 9.2.3
@angular/cli 9.1.5
@angular/material 9.2.3
@ngtools/webpack 9.1.5
@nguniversal/builders 9.1.0
@nguniversal/common 9.1.0
@nguniversal/express-engine 9.1.0
@schematics/angular 9.1.5
@schematics/update 0.901.5
rxjs 6.5.5
typescript 3.8.3
webpack 4.42.0
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 4
- Comments: 55 (1 by maintainers)
So hey @alan-agius4 - any updates on this?
Kinda looks like SSR has been effectively broken for two versions of Angular and its even more broken in 10 than in 9.
Whatâs the update? This is a pretty core feature of Angular - how is it not getting any attention?
After an update to Angular 10+
I encountered a regression compared to Angular 9 version On the main.server.ts side, I had defined window via domino (everything was functional in ng9):
Since the release in angular version 10. The same code no longer works. It seems that
global ['window']
is no longer recognized in the main.js suiteReferenceError: window is not defined because of
node_modules / leaflet / dist / leaflet-src.js
from ngx-leaflet which does not work in SSR.I tried to move the redefinition of the global in the server.ts and the main.server.ts but nothing there still makes the same error.
Has there been a change in the consideration of the global between the versions @nguniversal/common": â^9.1.0 and @nguniversal/express-engineâ: â^9.1.0 compare to @nguniversal/commonâ: â^10.1.0â and â@nguniversal/express-engineâ: â^10.1.0â
It seems that since 10.1.0 all people canât build in SSR anymore because of a potential script with
window
.I am working with angular 12, and I am still facing this issue with a third library. I tried all the domino solutions but they are not working.
Nope. Essentially it breaks multi platform support in angular and makes using âisPlatformBrowserâ a waste of time that accomplished nothing.
I eventually got past it by literally mocking out every single call that anything I use uses (even had to do it for libs used by libs I use).
Amazing waste of time, total hack, and the fact this totally breaking change hasnât been even really looked at makes my lose confidence in Angular. I wonât be selecting it for future projects.
@alan-agius4 broâŠ
After speaking with the author of
ngx-masonry
and taking a look myself, the calls tomasonry.js
are ALREADY correctly guarded with anisPlatformBrowser
check.So what are we supposed to do in this case? It seems like no matter how you guard against it the error will be thrown for SSR merely by importing the module no matter whoâs guarding against it.
Hello I have the same problem with angular universal. I have a check with the method isBrowserPlatform in all the places where I called the window but nothing changed. I did the same for the localStorage with the @Santoshah method but nothing to do. I have a huge project and these changes take me a lot of time I also tried many other solutions like domino etc⊠There is nothing to do My angular version is 12 Thanks anyway for all yours answers
@mocanapena Letâs not assume things on our own.
I had the same issue 10 days back. Whenever I try to run
npm run serve:ssr
I get windows not defined.I have also open stack explaing my question here . I fixed them by following this website
and lastly i updated the
tsconfig.server.json
âmoduleâ: âcommonjsâ inside compilerOptions solve the issue for window not defined.
You need to update every window object to the reference. Also make sure you do no have localstorage used or you need to make a reference to window in that case also.
I have manage to fixed this issue in my Angular 12.0.1 v project. Its very big and it took 3 days to fixed that issue and making changes all over the site. If you need personal assistant I can help. (its FREE). lets connect via skype: cssmaniaa
@alan-agius4
Iâm sure your root cause is accurate but it happens in many libraries, not just ngx-masonry.
The workaround I have posted only works in v9. It breaks in v10.
What needs to be changed using that technique to have it work in v10?
Hello, we reviewed this issue and determined that it doesnât fall into the bug report or feature request category. This issue tracker is not suitable for support requests, please repost your issue on StackOverflow using tag
angular-universal
.If you are wondering why we donât resolve support issues via the issue tracker, please check out this explanation.
hey, maybe someone will find this useful, works for angular 11 (and leaflet) p.s. thanks @Santoshah i was missing âmoduleâ: âcommonjsâ inside compilerOptions
Is there a concrete solution for this yet? Iâm stuck. Thanks.
@kamilmysliwiec looks like #451 might be related to the topic here. Definitely related to #830 (comment and a couple above). It seems to be relying solely on Angular CLI Builders for building & serving SSR apps caused this regression bug and
domino
is no longer working for packages accessingwindow
/otherDOM
objects directly.Iâve created 2 repos: one with working Angular 8 and not working Angular 9 using
NestJS
and itsapplyDomino
, which under the hood is basically domino we tend to use. On of the projects haveAngular 10
and it also doesnât work there, I suspect thatâs the same problem withAngular 11
- looks like this problem hasnât been tackled yet.@jasonburrows, sorry for the late reply.
The problem here is that
ngx-masonry
depends on a browser only librarymasonry-layout
. When running the server, the JavaScript engine will need to parse the entire contents of the server JS bundle, it will encounter awindow
reference and throw an error because this is not defined.The problem in v9+ occuries because NGCC is transforming the lazy
require
statement https://github.com/wynfred/ngx-masonry/blob/9c616d8b0598d8795760d1f5fd93aa629669e6b3/src/lib/ngx-masonry.component.ts#L52-L54 into a import statement, which is changing the lazy import into a proper import:Note: using a
require
, there is far from ideal, I think it can be replaced with animport()
without causing any issue.In order to get around this, you can mock the window object, prior to importing the
AppServerModule
, as per your comment: https://github.com/angular/universal/issues/1675#issuecomment-627030594There is a great article here by @CaerusKaru to why using
isPlatformBrowser
is not a good idea and might result in errors, while he also explains better alternatives https://medium.com/@caerus.karu/isplatformbrowser-is-not-your-friend-5ee52b06da89@Teebo This doesnât work for me either, apparently for now the only way to use incompatible third party libraries is by editing the code from the same library, this is obviously bad practice. Since in future updates we will have problems, but to solve it momentarily it is a good option. So it would be great if @jasonburrows showed how I solve this by editing the code of those incompatible libraries. In my case I have error in jspdf and @ zxing / ngx-scanner
@jasonburrows thanks, I am wrapping the editor.js code within the isPlatformBrowser, thank you for the points you have raised I will consider those, you have helped me a lot to at least find a way out, I will take it from here, all the best!