Error `window not defined` in Node.js - node.js

I know window doesn't exist in Node.js, but I'm using React and the same code on both client and server. Any method I use to check if window exists nets me:
Uncaught ReferenceError: window is not defined
How do I get around the fact that I can't do window && window.scroll(0, 0)?

Sawtaytoes has got it. I would run whatever code you have in componentDidMount() and surround it with:
if (typeof(window) !== 'undefined') {
// code here
}
If the window object is still not being created by the time React renders the component, you can always run your code a fraction of a second after the component renders (and the window object has definitely been created by then) so the user can't tell the difference.
if (typeof(window) !== 'undefined') {
var timer = setTimeout(function() {
// code here
}, 200);
}
I would advise against putting state in the setTimeout.

This will settle that issue for you:
typeof(window) === 'undefined'
Even if a variable isn't defined, you can use typeof() to check for it.

This kind of code shouldn't even be running on the server, it should be inside some componentDidMount (see doc) hook, which is only invoke client side. This is because it doesn't make sense to scroll the window server side.
However, if you have to reference to window in a part of your code that really runs both client and server, use global instead (which represents the global scope - e.g. window on the client).

This is a little older but for ES6 style react component classes you can use this class decorator I created as a drop in solution for defining components that should only render on the client side. I like it better than dropping window checks in everywhere.
import { clientOnly } from 'client-component';
#clientOnly
class ComponentThatAccessesWindowThatIsNotSafeForServerRendering extends Component {
render() {
const currentLocation = window.location;
return (
<div>{currentLocation}</div>
)
};
}
https://github.com/peterlazzarino/client-component

<Router onUpdate={() => window.scrollTo(0, 0)} history= {browserHistory}>
if you need to open new page on top in React JS app, use this code in router.js

Move the window and related code to the mounted() lifecycle hook. This is because mounted() hook is called on the client side only and window is available there.

Related

Crypto.randomUUID() not working with Next.js v13

The Environment
Next.js v13 (stable, no ./app folder) is running with Node v18 in Ubuntu WSL.
As per de docs , the Crypto API has been around since Node v14~ish.
This has been indeed tested in Node, in my environment:
Node 18 importing and running crypto.randomUUID()
I also printed the whole object and it looks as the docs says it should.
The Problem
Imagine this simple component:
import crypto from 'crypto';
export default function Crypto() {
console.log(crypto);
return (
<p>
{crypto.randomUUID()}
</p>
);
}
Next.js says it "compiled client and server successfully in 397 ms". But after the UUID renders in the browser for a couple of milliseconds, Next.js throws a couple of errors revolving around randomUUID not being a function.
Next Runtime Error with crypto.randomUUID()
I see that Webpack is somewhat mingling in there; haven't tried Turbopack. It's beyond the scope of this issue.
After commenting out the method invocation within the paragraph, the console.log(crypto) runs and prints twice, as usual, in the devtools as follows:
crypto method printed
Notice how one comes from "react devetools backend" and the other one from webkpack. That leads me to believe the error gets thrown server-side as the console.loglog is invoked before the UUID method.
Server-side, despite the errors thrown in the browser, the object gets printed by the Next CLI and it contains the method: Next CLI prints crypto object and randomUUID is listed
Client-side, within the printed object, the method randomUUID() is nowhere to be found:
Inside printed crypto object in devtools
This confirms the error message. My code is not getting access to the method. Also, a couple of methods are missing, when compared to the Node docs.
And yet if one console.log(crypto) directly from the devTools, it has indeed the method within its prototype:
randomUUID directly from devtools
Furthermore, because of the structure, I'm inclined to believe the crypto object being printed is somehow coming from Node, as the structure of the Chrome V8 crypto object is completely different. But why in the hell are those methods missing?
I tried console.loging the object server-side, client-side, and in-between. Somehow the method gets lost in-between. Webpack might be the culprit. Worst of all, albeit being for the blink of an eye, I can see the string rendered before the errors get thrown; and dismissing the error cards throws a blank body. The string disappears.
EDIT
The reason one imports/requires crypto is so it can run in Node. Next is a SSR framework; in a nutshell it is intended to run first on the server, get rendered and delivered as HTML as much as it can to the client. If not imported, Node throws an error when Next tries to invoke Crypto server-side.
Now then, I tell that piece of code to only run if the Window object is available (i.e. I'm in the Browser) and it runs with the native chromium V8 Crypto object.
// import crypto from 'crypto';
export default function Crypto() {
if (typeof window !== 'undefined') {
console.log('CLIENT: ', crypto.randomUUID());
return (
<p>
{crypto.randomUUID()}
</p>
);
}
return (
<h1>SERVER SIDE</h1>
);
}
The only downside is that is somehow still runs twice bc of Next magic, once server side and one client-side, which means it's not bc of React 18. It tells me accurately that which is to be expected as an UUID function always returns a different result.
Browsers restrict access to some crypto APIs when not running in a secure context (as defined here).
Set it to state in a useEffect hook when page initially loads so it persist and then render it from state.
const Crypto = () => {
const [randomUUID, setRandomUUID] = useState();
useEffect((
if (typeof window !== 'undefined' && !randomUUID) {
setRandomUUID(crypto.randomUUID());
}
),[]);
if(!randomUUID) <>No UUID</>;
return <>{randomUUID}</>
}
export default Crypto;

Can I prevent node_modules bundled with webpack from using window.postMessage?

For security reasons, I need to disallow 3rd party modules which are included in my bundle by webpack from using window.postMessage to communicate with other processes in my Electron app.
Is that possible?
A standard trick could help here: simply move the method to another variable on window, like this maybe:
window._postMessage = window.postMessage;
window.postMessage = () => {};
Run this first on your render script or with a <script> tag on your html and plugins that would use that can't send events anymore (in fact, they don't crash but never get a response).
Edit
If you want to make sure that only authorized user can use it, something like this could work:
function createSecurePostMessage() {
const _postMessage = window.postMessage;
return {
get() {return function(...args) {
if (isAuthorized(...args) {
_postMessage(...args);
}
}
}
}
window.postMessage = createSecurePostMessage().get();
Now the original postMessage is inside the function and inaccessible and you can implement a method, for example, that checks if a certain message can be sent. If someone calls create again, then the secured postMethod will just be 'secured' again.

Trigger client-side reload in next.js

Scenario
The index page uses "getInitialProps" to load data. Then we create a dialog which can create a new data. After creating a new data, the current page should be reloaded.
Problem
We use Router.replace('/') to reload the page. But it triggers a server-side rendering.
Question
What we need is a client-side reload. The "getInitialProps" function should be called in the browser. So, how to do the client-side reload?
Assume, a user is on the
http://www.example.com/profile
the user has edited the profile and for some reason, you need to reload the same page.
If your case is similar to this, you could use Router.reload();
Remember, you must import Router object like this import Router from "next/router";
For more information: https://nextjs.org/docs/api-reference/next/router#routerreload
A better option is to use router.replace(router.asPath)
replace does not create a new history item so Back button works as expected
Details explained in this article
https://www.joshwcomeau.com/nextjs/refreshing-server-side-props/
Didn't see an answer that was really what I was looking for,
this worked for me:
import Router from 'next/router'
Router.reload(window.location.pathname);
as of of NextJs 13 Being released the new router Object has the refresh() method, which allows you to refresh ( re-fetch ) the data client-side only without having to do a full page reload.
it can be used like the following :
import { useRouter } from "next/navigation";
export default function Component(){
const router = useRouter();
//this will reload the page without doing SSR
router.refresh();
}
Please keep in mind that this is feature of NextJs 13 Which is currently in beta.
check the beta docs here
credits to fireship for showing the feature
https://www.youtube.com/watch?v=__mSgDEOyv8
Running the following code
pages/index.js
import Router from 'next/router';
function Index({ isServer }) {
console.log('render', new Date());
return (
<div>
<h1>Home page. Is it on server? - {isServer ? 'Yes' : 'No'}</h1>
<button type="button" onClick={() => Router.push('/')}>
Reload me
</button>
</div>
);
}
Index.getInitialProps = async ({ req }) => {
return { isServer: !!req };
};
export default Index;
I can see that it console.logs render only once on the server even after clicking "Reload me". I can see that isServer equals to false after "reload" as well.
How do you exactly reload the page so you see it is rendered on server side?
PS
Here are screenshots:
initial load
after clicking reload
It may help someone, If you are using nextjs Link its actually preloades page if you need default reload you need to use a tag not a Link

How to use components that use `window` reference in React with server-side rendering?

An example of such component is Pikaday (react-pikaday) that contains in its code this line
hasEventListeners = !!window.addEventListener
but window is not defined on server so when I run the code it throws an error ReferenceError: window is not defined.
I tried to solve this issue by conditionally import Pikady component, something along these lines:
let Pikaday;
if (typeof window !== 'undefined' && window.document && window.document.createElement) {
import('./Pikaday').then(P => {
Pikaday = P.default;
});
}
In such a case it doesn't throw an error because the component is not loaded but I presumed that the initial HTML sent from server would not contain this component and then it would somehow "switch" to JS code on client side and the component would load. But this doesn't happen. I'm new to server-side rendering in general so I'm getting a bit lost.
How can I solve this? I have the same problem with Leaflet library that also contains window in its code.
Do a simple check for window.
if (typeof window !== 'undefined') {
// write your logic here
}
I eventually used this fork of Pikaday that introduces several small changes to check for window availability:
https://github.com/everdimension/Pikaday
I don't think there was any other way than edit the plugin itself.

view events are set twice when I instantiate view second time

This is my project architecture issue - its my first backbone project and I probably did something wrong.
In all my project in route callbacks I have:
myroute: function() {
this.currentView = new MyCustomView();
},
mysecondroute: function() {
this.currentView = new MySecondView()
},
//...
So in all route callbacks I instantiate some view. This view has initialze method which calls render method. It works except that all view events (declared in events: {}) are 'binded' every time same view is instantiated. so when I visit same route twice events for view corresponding to this route are fired twice...
Probably I shouldn instantiate new view on every route call - but how I can do this ? I mean what are the standards? Maybe I should just unload current view somehow - is there any method to do this?
I think you have to add a method to unbind all the events at the time to close the view
like this
close : function () {
//your code to clean everything before closing the view
this.remove();
this.unbind();
}
so the next time the view is called the events will be added during the initialization of the view, thats why you had events being called twice. the initialize method binds the events to the .el element. you need to make sure you unbind those at some point.

Resources