lottie-player icon indicating copy to clipboard operation
lottie-player copied to clipboard

Window is not defined - Angular 17

Open BugProg opened this issue 1 year ago • 11 comments

Hi !

I just updated my project to Angular 17, and I'm using modern compilation method with Vite. I have an issue with lottie-player , I get the following error: [vite] Internal server error: window is not defined during the compilation.

at eval (/home/user/Projects/Angular/angular-project/.angular/vite-root/angular-project/node_modules/.pnpm/@[email protected]/node_modules/@lottiefiles/lottie-player/dist/lottie-player.esm.js:1359:9)
at async instantiateModule (file:///home/user/Projects/Angular/angular-project/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:56052:9)

Version :

  • Angular: 17
  • lottie-player : 2.02

BugProg avatar Nov 11 '23 22:11 BugProg

Did you activate the SSR option?

sey avatar Dec 06 '23 21:12 sey

Yes, I have SSR enable.

BugProg avatar Dec 07 '23 08:12 BugProg

I think you should isolate the LottiePlayer in a dedicated component and skip the hydration process for that component as the window context is only available on the client side and not on the server side. https://angular.io/guide/hydration#how-to-skip-hydration-for-particular-components

sey avatar Dec 11 '23 09:12 sey

Hi @sey !

Thank you for your solution ! I will try this very soon and notice you if it's working.

BugProg avatar Dec 16 '23 13:12 BugProg

@sey The workaround isn't working.

I have a lottie-lazy component that lazily renders the lottie component (which in turn loads the web component).

Some relevant excerpts:

lottie-player-lazy:

@Component({
  selector: "ringe-lottie-player-lazy",
  templateUrl: "./lottie-player-lazy.component.html",
  styles: [],
  host: { ngSkipHydration: "true" },
})
export class LottiePlayerLazyComponent implements AfterViewInit {
  private platformId = inject(PLATFORM_ID);
  private viewContainer = inject(ViewContainerRef);

  async ngAfterViewInit(): Promise<void> {
    // We cannot access window during prerendering, which is indirectly used by the lottie web component under the hood.
    if (!isPlatformBrowser(this.platformId)) return;

    const url = this.data?.file?.data?.attributes?.url;
    if (url === undefined) return;

    this.viewContainer?.clear();
    const { LottiePlayerComponent } = await import("./lottie-player.component");
    const player = this.viewContainer?.createComponent(LottiePlayerComponent);
    if (player !== undefined) player.instance.url = url;
  }
}

lottie-player

import { Component, Input } from "@angular/core";
import "@lottiefiles/lottie-player";

@Component({
  selector: "ringe-lottie-player",
  templateUrl: "./lottie-player.component.html",
  styles: [],
  host: { ngSkipHydration: "true" },
})
export class LottiePlayerComponent {
  @Input() url?: string;
}

ciriousjoker avatar Feb 05 '24 01:02 ciriousjoker

Nevermind, found the issue. Need to dynamically import the web component javascript.

// Remove this
import "@lottiefiles/lottie-player";

// Add this
constructor() {
  import ("@lottiefiles/lottie-player");
}

Why this suddenly works is beyond me though. I would expect that this approach also requires a check for isPlatformBrowser, but apparently it doesn't.

ciriousjoker avatar Feb 05 '24 01:02 ciriousjoker

Hi @ciriousjoker !

Where did you add import ("@lottiefiles/lottie-player"); ? When I imported lottie-player in my component, ng s crash immediately and return error 1.

BugProg avatar Feb 05 '24 18:02 BugProg

@BugProg inside the constructor

ciriousjoker avatar Feb 07 '24 00:02 ciriousjoker

Hmmm, I added in the constructor but ng s crash immediately.

Node.js v20.9.0
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
github.com/evanw/esbuild/internal/helpers.(*ThreadSafeWaitGroup).Wait(...)
        github.com/evanw/esbuild/internal/helpers/waitgroup.go:36
main.runService.func2()
        github.com/evanw/esbuild/cmd/esbuild/service.go:114 +0x59
main.runService(0x1)
        github.com/evanw/esbuild/cmd/esbuild/service.go:160 +0x4ed
main.main()
        github.com/evanw/esbuild/cmd/esbuild/main.go:240 +0xa29

goroutine 6 [chan receive]:
main.runService.func1()
        github.com/evanw/esbuild/cmd/esbuild/service.go:98 +0x4a
created by main.runService
        github.com/evanw/esbuild/cmd/esbuild/service.go:97 +0x1e5

goroutine 7 [chan receive]:
main.(*serviceType).sendRequest(0xc0000fe060, {0x93c480, 0xc011bc0cf0})
        github.com/evanw/esbuild/cmd/esbuild/service.go:192 +0xfa
main.runService.func3()
        github.com/evanw/esbuild/cmd/esbuild/service.go:125 +0x39
created by main.runService
        github.com/evanw/esbuild/cmd/esbuild/service.go:122 +0x31c
 ELIFECYCLE  Command failed with exit code 1.

Do you use Vite? Can you provide an example of the code?

BugProg avatar Feb 08 '24 08:02 BugProg

@BugProg im not sure. I used the default compiler in angular 17, so I guess not. I just upgraded, an older default might still be in use

ciriousjoker avatar Feb 08 '24 08:02 ciriousjoker

Thanks for that detail @ciriousjoker ! I'm going to try the same code without Vite.

BugProg avatar Feb 08 '24 08:02 BugProg