React JS Server side issue - window not found
Asked Answered
N

8

35

Hi I'm trying to use react-rte in my reactJS project. I have server side rendering and every time I want to use this package I get:

return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
                               ^
ReferenceError: window is not defined

I guess the problem might be with isomorphic-tools but I don't know how to defer importing package to the client where window is going to be defined already.

Nickeliferous answered 15/8, 2016 at 8:27 Comment(0)
V
20

If you're doing server side rendering, there's a good chance that the global window object is going to be undefined because that is only something the client will understand.

Note: Initially, when you start up your project its going to render out a complete string of your DOM (at this point it will not know about window because it is server side, but then re-render with the client-side code to which your window object will be available!

There is a workaround that I am using in this case. This is what I have for my webpack plugin:

new webpack.DefinePlugin({
  'process.env.NODE_ENV': isDevelopment ? '"development"' : '"production"',
  'process.env.BROWSER': JSON.stringify(true),
  __DEV__: isDevelopment
}),

So I use process.env.BROWSER to my advantage because it will be defined as undefined if it is server side, and it will be true if the client side is done rendering.

Since everything just stops working when there isn't a window object on the server side we can add this:

const mySpecialWindowFunction = () => {

  /* START HACK */
  if (!process.env.BROWSER) {
    global.window = {}; // Temporarily define window for server-side
  }
  /* END HACK */

  return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
};

That way, your console won't scream at you and doesn't stop the server side rendering, to which you can now carry on with your glorious day! Although I have to admit that this is a bit Hacky, but it gets the job done because all we want to do is let the server side render out the initial DOM string and then let the client-side take over.

Also Note: Don't worry about setting window as an empty object, it will be back to normal once the client-side finishes rendering.

Viglione answered 9/10, 2016 at 4:4 Comment(5)
Where exactly would i add the "mySpecialWindowFunction" ?Flame
In addition to Spacemoose's comment, the answer could be updated to specify that the first snippet goes inside the module.exports = { plugins[ ] } area in the webpack config.Aalesund
can someone answer @Spacemoose's question?Unlearned
Please add details where to use "mySpecialWindowFunction"Covington
mySpecialWindowFunction here is just any function that uses window which is implied from OP. Which means we should include this type of code in each function that uses window. Or document. And this is not good. And you won't get away with empty object, obviously, event in this example - we'll throw at navigator.userAgent because navigator is null. Better solution is to either import predefined window everywhere in the code or define it for SSR build specifically before any code can run (but in this case you'll have to take in mind any possible mutations across multiple requests).Ardel
S
21

Here is a npm library which can handle window, document and global object for you: Global.

Then you can safely write:

import window from 'global'

const mySpecialWindowFunction = () => {
    return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
};
Sizzle answered 24/10, 2017 at 10:36 Comment(1)
Where exaclty i have to add this?Pedanticism
V
20

If you're doing server side rendering, there's a good chance that the global window object is going to be undefined because that is only something the client will understand.

Note: Initially, when you start up your project its going to render out a complete string of your DOM (at this point it will not know about window because it is server side, but then re-render with the client-side code to which your window object will be available!

There is a workaround that I am using in this case. This is what I have for my webpack plugin:

new webpack.DefinePlugin({
  'process.env.NODE_ENV': isDevelopment ? '"development"' : '"production"',
  'process.env.BROWSER': JSON.stringify(true),
  __DEV__: isDevelopment
}),

So I use process.env.BROWSER to my advantage because it will be defined as undefined if it is server side, and it will be true if the client side is done rendering.

Since everything just stops working when there isn't a window object on the server side we can add this:

const mySpecialWindowFunction = () => {

  /* START HACK */
  if (!process.env.BROWSER) {
    global.window = {}; // Temporarily define window for server-side
  }
  /* END HACK */

  return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
};

That way, your console won't scream at you and doesn't stop the server side rendering, to which you can now carry on with your glorious day! Although I have to admit that this is a bit Hacky, but it gets the job done because all we want to do is let the server side render out the initial DOM string and then let the client-side take over.

Also Note: Don't worry about setting window as an empty object, it will be back to normal once the client-side finishes rendering.

Viglione answered 9/10, 2016 at 4:4 Comment(5)
Where exactly would i add the "mySpecialWindowFunction" ?Flame
In addition to Spacemoose's comment, the answer could be updated to specify that the first snippet goes inside the module.exports = { plugins[ ] } area in the webpack config.Aalesund
can someone answer @Spacemoose's question?Unlearned
Please add details where to use "mySpecialWindowFunction"Covington
mySpecialWindowFunction here is just any function that uses window which is implied from OP. Which means we should include this type of code in each function that uses window. Or document. And this is not good. And you won't get away with empty object, obviously, event in this example - we'll throw at navigator.userAgent because navigator is null. Better solution is to either import predefined window everywhere in the code or define it for SSR build specifically before any code can run (but in this case you'll have to take in mind any possible mutations across multiple requests).Ardel
B
18

For anyone else trying to figure why their SSR fails even though they are checking if window object is undefined.

You need to check if the window reference exists, not if it's value is null!

  if (typeof window === 'undefined') console.log('Window is not there')

Your window && and if (window) checks with are failing because in JavaScript not declared and 'undefined' are different things.

const a = undefined;
if (a) console.log('a');  // logs nothing, since 'a' is undefined
if (b) console.log('b');  // ReferenceError: b is not defined

And answer to the original question is that whenever accessing that need 'window' object, you need to make them conditional:

return (typeof window === 'undefined') ?
   'node' :
   /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());

Buffum answered 21/5, 2020 at 7:12 Comment(1)
definitely a confusing situation. the typeof window is the string undefined and not the actual value undefinedYield
T
3

I've been using ReactJS.NET targeting build to client and server, and got the same problem.

The solution is to set output.globalObject to 'this'.

module.exports = {
  // ...
  output: {
    // ...
    globalObject: 'this'
  }
};

Without that option set, it's falling back to window which is working on client-only code.

Townes answered 11/12, 2019 at 12:43 Comment(0)
V
1

Move the window object to useEffect().

Villous answered 12/10, 2023 at 13:23 Comment(0)
E
0

When doing server-side-rendering, global like window, document will be undefined. And if you want to do it in isomorphic way, you have to test what environment is when rendering componets.

https://github.com/DavidWells/isomorphic-react-example

many example codes can be found on github, the link above is one of them, hope it can be helpful.

Ethereal answered 15/8, 2016 at 8:34 Comment(0)
A
0

I tried setting it in my constants as a global import:

export const GLOBAL_WINDOW = (typeof self === 'object' && self.self === self && self) || (typeof global === 'object' && global.global === global && global) || this;

In this case it returns window or global object depending on weather your running it on client application or server.

Now you need to import this constant wherever you want to make use of window object.

Ex:

import { GLOBAL_WINDOW } from '../constants/Constants';

const user = JSON.parse(GLOBAL_WINDOW.localStorage.getItem('user'));
Alisun answered 27/7, 2018 at 9:35 Comment(0)
E
-1

Another solution I found, is that you can assign your state variables with your 'window variables' in the 'componentDidMount' event, and in the 'render' method you can test if the state variables you want are null or undefined then return null, until the 'componentDidMount' finish.

Expansion answered 29/11, 2019 at 16:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.