saltyshiomix / nextron

⚡ Next.js + Electron ⚡
https://npm.im/nextron
MIT License
3.91k stars 225 forks source link

cannot disable SSR. #152

Open Lite5h4dow opened 3 years ago

Lite5h4dow commented 3 years ago

Im trying to use PixiJS & React-Pixi and despite wrapping it in a component imported with a dynamic import it still cant compile in the dev or build environment.

console error

ReferenceError: window is not defined
    at C:\Users\storm\Dev\NuzlockeLegends\renderer\.next\server\pages\overlay.js:197:28
    at Object.<anonymous> (C:\Users\storm\Dev\NuzlockeLegends\renderer\.next\server\pages\overlay.js:209:10)
    at Module._compile (internal/modules/cjs/loader.js:759:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:770:10)
    at Module.load (internal/modules/cjs/loader.js:628:32)
    at Function.Module._load (internal/modules/cjs/loader.js:555:12)
    at Module.require (internal/modules/cjs/loader.js:666:19)
    at require (internal/modules/cjs/helpers.js:16:16)
    at C:\Users\storm\Dev\NuzlockeLegends\node_modules\next\dist\build\utils.js:23:2428
    at C:\Users\storm\Dev\NuzlockeLegends\node_modules\next\dist\build\tracer.js:3:476 {
  type: 'ReferenceError'
}

component that references react-pixi (i know the dynamic export is a little overkill, but i was trying everything) OverlayStage.tsx

import {Stage} from "@inlet/react-pixi";
import dynamic from "next/dynamic";

const OverlayStage = props => {
  return <Stage>{props.children}</Stage>;
};

export default dynamic(() => Promise.resolve(OverlayStage), {ssr: false})

component that imports the isolated component overlay.tsx

import React from "react";
import Head from "next/head";
import dynamic from "next/dynamic";

const OverlayStageNoSSR = dynamic(() => import("../components/OverlayStage"), {ssr: false});

const Next = () => {
  return (
    <React.Fragment>
      <Head>
        <title>Nuzlocke Legends - Overlay</title>
      </Head>
      <OverlayStageNoSSR />
    </React.Fragment>
  );
};

export default dynamic(() => Promise.resolve(Next), {ssr: false});
grebett commented 3 years ago

Same problem here. Any hint?

Lite5h4dow commented 3 years ago

no nothing atm thinking i might switch to next-electron-server but that has issues too. this is a huge part of the plan i have for this app

yoroshikun commented 3 years ago

I'm not sure if I'm reading this wrong but wouldn't you just need to ensure that the component is not rendered unless the window is loaded? From my understanding dynamic is more a way to treeshake and codesplit.

If that is the case you can just use a component load use effect to set a state when dom is "ready".

import React from "react";
import Head from "next/head";
import OverlayStage from "../components/OverlayStage";

const Next = () => {
  const [windowReady, setWindowReady] = useState(false);

  useEffect(() => {
    setWindowReady(true)
  }, []) // (similar to onComponentMount)

  return (
    <React.Fragment>
      <Head>
        <title>Nuzlocke Legends - Overlay</title>
      </Head>
{ windowReady && <OverlayStage /> }
    </React.Fragment>
  );
};

export default Next;

or you might not need the useEffect and useState at all by wrapping the component in a conditional checking if window is a thing

{ window && <OverlayStage /> }

Hope any of this helps, (untested code above just wrote what I thought would work.

Lite5h4dow commented 3 years ago

No because that fails during build and test too.

afazzdev commented 3 years ago

Any answer for this? i tried using create-next-app with the exact same code and no problem occured..

gabriel-visualthinking commented 3 years ago

Having the same issue here. Import working fine in NextJS but not in Nextron... Anyone help?

yoroshikun commented 3 years ago

For more information on why this happens. It is because the build process exports the next project statically. You can see this in the build command here See Next Docs for information on that command

It may be happening because there will not be any SSR in the build export stage. You can try doing something like this which you can make a conditional to only load when window present. However this is likely to not work as the code might never load, but you can always give it a shot.

gabriel-visualthinking commented 3 years ago

Thank you! For anyone else having this issue, I'll post a little code snipped below:

let importedComponent = null
if (window !== undefined) {
        const importing = require("insert path here");
        const myComponent = importing.default //can also be a different export
        importedComponent = <myComponent/>
} else { //for build purposes only
        importedComponent = <div><p>Component not available.</p></div>;
}
//when returning:
return(
<div>
   {importedComponent}
</div>
)
Victugord commented 3 years ago

That Solution works for me

afazzdev commented 3 years ago

Thank you! For anyone else having this issue, I'll post a little code snipped below:

let importedComponent = null
if (window !== undefined) {
        const importing = require("insert path here");
        const myComponent = importing.default //can also be a different export
        importedComponent = <myComponent/>
} else { //for build purposes only
        importedComponent = <div><p>Component not available.</p></div>;
}
//when returning:
return(
<div>
   {importedComponent}
</div>
)

For some reason your answer not working on mine. so i change conditional statement to

global?.window && window !== undefined

and it's working.

yoroshikun commented 3 years ago

@gabriel-visualthinking

Thank you! For anyone else having this issue, I'll post a little code snipped below:

let importedComponent = null
if (window !== undefined) {
        const importing = require("insert path here");
        const myComponent = importing.default //can also be a different export
        importedComponent = <myComponent/>
} else { //for build purposes only
        importedComponent = <div><p>Component not available.</p></div>;
}
//when returning:
return(
<div>
   {importedComponent}
</div>
)

To keep this much less verbose it may be possible to write it as the following

return (
  <div>
    {window !== undefined ? (
      require("path").default
    ) : (
      <p>Component not available.</p>
    )}
  </div>
);

if that does not work

const importedComponent = window !== undefined ? require("path").default : <p>Component not available</p>

return (
  <div>
    <importedComponent />
  </div>
);

Should also, reducing boilerplate.

Let me know if any of these work and if none I can remove this comment. ( I have just wrote syntax from memory )