Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix undefined window in Resizable-box tooltip #38400

Conversation

kuuak
Copy link

@kuuak kuuak commented Feb 1, 2022

Description

Following the refactor and transformation of the resisable-box to typescript (PR #35062) the window object were not anymore tested to be undefined. (exactly here)

This PR revert this single line of code to verify wether window is undefined and sets default to clearTimeout and
setTimeout to avoid any crash of the app using @wordpress/components packages

We use @wordpress/components in the frontend of our app built in nextjs. Therefore when building the app or generating a static version on the server, the window object is not accessible. Hence the bug encountered when updating the package to its latest version which removed the undefined test of the window object.

Types of changes

  • Bug fix

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • [ ] My code follows the accessibility standards. not relevant as no changes made on displayed component
  • [ ] I've tested my changes with keyboard and screen readers. not relevant
  • [ ] My code has proper inline documentation. not relevant
  • [ ] I've included developer documentation if appropriate. not relevant
  • [ ] I've updated all React Native files affected by any refactorings/renamings in this PR (please manually search all *.native.js files for terms that need renaming or removal). not relevant
  • [ ] I've updated related schemas if appropriate. not relevant

@kuuak kuuak requested a review from ajitbohra as a code owner February 1, 2022 10:05
@github-actions github-actions bot added the First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository label Feb 1, 2022
@github-actions
Copy link

github-actions bot commented Feb 1, 2022

👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @kuuak! In case you missed it, we'd love to have you join us in our Slack community, where we hold regularly weekly meetings open to anyone to coordinate with each other.

If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information.

@kuuak kuuak force-pushed the fix/resizablebox-tooltip-utils-window-undefined branch from 778ecea to 8768922 Compare February 1, 2022 14:42
Copy link
Member

@p-jackson p-jackson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm having the same issue where @wordpress/components can not longer be imported from within Node environments. Thanks for contributing the fix!

@@ -9,7 +9,8 @@ import useResizeAware from 'react-resize-aware';
*/
import { useEffect, useRef, useState } from '@wordpress/element';

const { clearTimeout, setTimeout } = window;
const { clearTimeout = () => undefined, setTimeout = () => undefined } =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once this PR is rebased the noop function will no longer be imported from lodash but this file will define its own. If we change the noop definition from () => {} to () => undefined then you'll be able to set the fallback values for clearTimeout and setTimeout to the shared noop function.

Copy link
Contributor

@lsl lsl Jul 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jsnajdr suggested we could use globalThis here instead of window.

e.g. something like:

Suggested change
const { clearTimeout = () => undefined, setTimeout = () => undefined } =
const { clearTimeout, setTimeout } = globalThis;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently we can't use the globalThis trick in cases where we need to use the return of the setTimeout call, because in Node it returns NodeJS.Timeout instead of number.

moveTimeoutRef.current = setTimeout( unsetMoveXY, fadeTimeout );

In this code it won't ever actually run in a SSR context because the call is inside a useEffect, but the TypeScript checker doesn't know that, so it kindly throws an error 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would something like this work?

const moveTimeoutRef = useRef< ReturnType< typeof setTimeout > >()

Potentially might need some nulls.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just refactor the code so that we can write window.setTimeout and window.clearTimeout inline inside the setTimeout ?

Copy link
Member

@mirka mirka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for contributing, and sorry this took so much time to get onto our radar! I proposed #42248 to prevent further regressions, and to fix up the remaining issues.

@kuuak If you are still available to move forward with this PR, it'd be great if you could rebase and add a changelog. Just let us know if you don't have time, and we can batch fix it in #42248 👍

@@ -9,7 +9,8 @@ import useResizeAware from 'react-resize-aware';
*/
import { useEffect, useRef, useState } from '@wordpress/element';

const { clearTimeout, setTimeout } = window;
const { clearTimeout = () => undefined, setTimeout = () => undefined } =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently we can't use the globalThis trick in cases where we need to use the return of the setTimeout call, because in Node it returns NodeJS.Timeout instead of number.

moveTimeoutRef.current = setTimeout( unsetMoveXY, fadeTimeout );

In this code it won't ever actually run in a SSR context because the call is inside a useEffect, but the TypeScript checker doesn't know that, so it kindly throws an error 😄

@mirka mirka requested review from chad1008 and ciampo July 7, 2022 19:50
@mirka
Copy link
Member

mirka commented Jul 12, 2022

We fixed this issue along with the other existing SSR issues, so we could merge eslint rules to prevent further regressions (#42248). Apologies again for letting this sit so long!

@mirka mirka closed this Jul 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository [Package] Components /packages/components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants