davidfig / pixi-viewport

A highly configurable viewport/2D camera designed to work with pixi.js
https://davidfig.github.io/pixi-viewport/
MIT License
1.04k stars 174 forks source link

Use with Sveltekit: window is not defined #398

Closed Donny-H closed 1 year ago

Donny-H commented 1 year ago

Doing a standard import:

import { Viewport } from 'pixi-viewport';

and get terminal error:

window is not defined ReferenceError: window is not defined

This is before doing anything else at all.

I know Sveltekit uses Vite. I've looked around for potential solutions but can't come up with anything solid.

Any ideas?

davidfig commented 1 year ago

that's weird. pixi-viewport attaches listener events to window, which should be defined in javascript. are you running it in a browser?

Donny-H commented 1 year ago

that's weird. pixi-viewport attaches listener events to window, which should be defined in javascript. are you running it in a browser?

Yeah, just vanilla chrome. In case it was something with my app I tried installing a completely fresh sveltekit skeleton project from kit.svelte.dev, simply adding the dependency, importing it on the index page, and same error.

Sveltekit is still pretty new so could be a bug on their end, but I haven't run into anything similar with other libraries. Let me know if I can help solve it in any way

Donny-H commented 1 year ago

This thread seems helpful:

https://www.reddit.com/r/sveltejs/comments/mhcmv0/sveltekit_window_is_not_defined/

https://stackoverflow.com/questions/69874742/sveltekit-console-error-window-is-not-defined-when-i-import-library

EDIT:

Using a suggestion there, I tried putting `

    const lib = await import('pixi-viewport')
    const Viewport = lib.Viewport`

In onMount and it no longer errors out, but it doesn't seem to have affected the canvas either. I believe it's because Sveltekit loads imports before the DOM is rendered (as it is SSR-based), so 'window' doesn't exist at the import stage.

Is there a way to tweak the above so that it works client-side only? Otherwise I'll just load from a CDN if needed.

Donny-H commented 1 year ago

Solved with onMount(async () => { const { Viewport } = await import('pixi-viewport'); })

mutewinter commented 1 year ago

Another solution to this problem is to remove the module-scoped usage of window.innerHeight and window.innerWidth.

The use-case is in hybrid SSR apps (like Next.js) you might want to use an export from Pixi Viewport (e.g. the Viewport TypeScript interface), but never actually render anything on the server. In that case, the server will crash just from import 'pixi-viewport'.

I patched my local pixi-viewport to remove the module-scoped dependence on window.

diff --git a/src/Viewport.ts b/src/Viewport.ts
--- a/src/Viewport.ts
+++ b/src/Viewport.ts
@@ -126,8 +126,8 @@
const DEFAULT_VIEWPORT_OPTIONS: ICompleteViewportOptions = {
-    screenWidth: window.innerWidth,
-    screenHeight: window.innerHeight,
+    screenWidth: 400,
+    screenHeight: 400,
    worldWidth: null,
    worldHeight: null,
    threshold: 5,
@@ -341,8 +341,8 @@ export class Viewport extends Container
      * @param {number} [worldHeight]
      */
     resize(
-        screenWidth: number = window.innerWidth,
-        screenHeight: number = window.innerHeight,
+        screenWidth: number = 400,
+        screenHeight: number = 400,
         worldWidth?: number,
         worldHeight?: number
     ): void

In my view, this fallback to window isn't very useful and instead screenHeight / screenWidth should be required params.