pixijs: "window is undefined" in nextjs

  • FYI: going forward this will likely continue to be an issue due to the popularity of nextjs.
  • The root cause is that pixi does not work in node.js so it blows up when run in SSR.
  • This is related to an old bug with pixi.js v4: https://github.com/pixijs/pixi.js/issues/3224
  • The workaround is to use dynamic imports to remove it from the SSR phase. See https://medium.com/frontend-digest/why-is-window-not-defined-in-nextjs-44daf7b4604e
  • Unfortunately, this is not an ideal solution.
  • The use case is a React component that uses pixi.js under the hood. https://gitlab.com/robotandkid/awesome-react-cutscenes
  • Because of the dynamic import, this component is unable to manage it’s SSR lifecycle unless it includes nextjs-specific code.
  • But really all that needs to happen is for pixi to abort loading if the window is not present. (Something like wrapping everything in a giant if (typeof window === 'undefined') 😃 )

Expected Behavior

  • pixi errors gracefully when the window object is not present

Current Behavior

  • pixi cannot run in SSR

Possible Solution

  • Something like wrapping everything in a giant if (typeof window === 'undefined') 😃

Steps to Reproduce

Environment

  • pixi.js - v5.3.3

  • pixi.js version: e.g. 4.7.1

  • Browser & Version: e.g. Chrome 67

  • OS & Version: e.g. Ubuntu 18.04

  • Running Example: url

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 6
  • Comments: 17 (2 by maintainers)

Most upvoted comments

wrap pixi.js in a component

// pixi.tsx
import { useEffect, useRef } from "react";
import { Application, utils } from "pixi.js";
export default function Pixi() {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  useEffect(() => {
    if (process.browser) {
      let type = "WebGL";
      if (!utils.isWebGLSupported()) {
        type = "canvas";
      }
      utils.sayHello(type);
    }
  }, []);
  return <canvas ref={canvasRef} />;
}

and them dynamic import that with no ssr

// pages/PixiPage.tsx
import React from "react";
import dynamic from "next/dynamic";
const Pixi = dynamic(() => import("./pixi"), {
  ssr: false,
}); 
export default function PixiPage() {
  return (
      <Pixi/>
  );
}

Released v6.3.1, wait a few minutes for it to publish

hate to be that guy, but this was closed 4 days ago but there still hasn’t been a release. I can see all items in the 6.3.1 milestone are closed. Is there some schedule/timeline for when one gets sliced up? There are too many changes for me to just do/share a patch-package until then and I can’t npm install a commit from this repository due to:

npm ERR! Can't install git+https://github.com/pixijs/pixijs.git#c63e917a0e1cd57ee3403b9c0d9e4add83241204: Missing package version

I know some people are still struggling with this and may not have access to NextJS so I just wanted to post another solution that utilizes the native ES6 dynamic import feature.

In my case I’m using React, but for whatever library you’re using make sure that the code is going to be executed on the client, if there’s no ‘simple’ way of doing this, you can always run a window or document check for undefined.

React.useEffect(async () => {
  if(!process.browser) return;
  const app= (await import('path/to/app')).default;
  document.body.appendChild(app.view); 
});

In my case, I import PIXI regularly and export the app.

import * as PIXI from 'pixi.js'; 
const app = new PIXI.Application({
    width: window?.innerWidth || 0,
    height: window?.innerHeight || 0,
    backgroundColor: '#FF0000'
});
export default app;

– Full EX:

import styles from '../styles/Example.module.css'
import React from 'react';
import { useRouter } from 'next/router'; 

export default function Example() {
  const container = React.createRef(); 
  const router = useRouter(); 

  React.useEffect(async () => {
    try {
      if(!process.browser) return; 
      let app = (await import('@package/client')).default; 
      container.current.appendChild(app.view);
    } catch (error) {
      router.push('/internal-error'); 
    }
  }, []);

  return (
    <div ref={container} className={styles.container}></div>
  )
}