首页 > 解决方案 > What might cause the same exact code to behave differently in a published npm package vs yarn link?

问题描述

A colleague and I maintain some internal libraries at my work. It's fairly standard TypeScript React UI component stuff. A lot (but not all) of our components use the Material UI library under the hood, with some style changes and additional props to meet our needs.

Earlier this week, a product manager messaged us and said, "hey, whenever I open a menu, the page scrolls up to the top." So we did a little investigation and found that removing a forwarded ref from the Material-UI Popper component fixed it locally, when using yarn link to use our library code in a local instance of the same front-end application.

Success, you might think, right? We were able to reproduce the problem on our local, then we were able to make the problem go away on our local. One would assume that would mean that we were ready to publish a patch.

Except that publishing a patch didn't fix it.

We've somehow ended up in a situation where the same exact code behaves as expected when run locally via yarn link, but does not behave as expected when run either locally or in a hosted environment from a published npm package.

My question to you is: Have you ever had a problem like this? Did you ever figure out what caused it? I'm racking my brain to try to figure out what could be the difference. It's the same exact code, it's just running from a local build artifact in one case (where it works as expected), from an installed node_modules package in the other (where it does not work as expected).

for reference, here's a slightly modified version of the source code for the component in question:

import ClickAwayListener from '@material-ui/core/ClickAwayListener'
import Grow from '@material-ui/core/Grow'
import MuiMenuList from '@material-ui/core/MenuList'
import Paper from '@material-ui/core/Paper'
import Popper from '@material-ui/core/Popper'
import React from 'react'
import FocusLock from 'react-focus-lock'

import withTheme from '../hoc/withTheme'

import {MenuProps} from './Menu.model'
import style from './Menu.style'

export const Menu = withTheme(
  React.forwardRef((props: MenuProps, ref: React.Ref<HTMLDivElement>) => {
    const menuRef = React.useRef<HTMLDivElement>(null)

    const {
      children,
      classes,
      id,
      menuButton,
      open = false,
      placement,
      requestToggle,
      testID,
      transformOrigin,
    } = props

    const handleClose = (event: any) => {
      if (menuRef.current && menuRef.current.contains(event.target)) {
        return
      }

      requestToggle()
    }

    const tabEvent = (event: any) => {
      const key = event.keyCode ? event.keyCode : event.which

      if (key === 9 || key === 27) {
        requestToggle()
      }
    }

    return (
      <div className={classes?.container} ref={ref}>
        <div
          ref={menuRef}
          aria-owns={open ? id : undefined}
          aria-haspopup='true'
          onClick={requestToggle}
          role='button'
        >
          {menuButton}
        </div>
        <Popper
          open={open}
          anchorEl={menuRef.current}
          transition
          className={classes?.popperRoot}
          role='menu'
          disablePortal
          placement={placement}
        >
          {({TransitionProps, placement: p}) => {
            const transformOriginStyle = (() => {
              if (transformOrigin) {
                return `${transformOrigin.horizontal} ${transformOrigin.vertical}`
              }
              if (p === 'bottom') {
                return 'center top'
              }
              return 'center bottom'
            })()
            return (
              <Grow
                {...TransitionProps}
                style={{
                  transformOrigin: transformOriginStyle,
                }}
              >
                <Paper
                  className={classes?.paperRoot}
                  id={id}
                  data-testid={testID}
                >
                  <FocusLock>
                    <ClickAwayListener onClickAway={handleClose}>
                      <MuiMenuList onKeyDown={tabEvent}>{children}</MuiMenuList>
                    </ClickAwayListener>
                  </FocusLock>
                </Paper>
              </Grow>
            )
          }}
        </Popper>
      </div>
    )
  }),
  style,
)

Menu.displayName = 'Menu'

Menu.defaultProps = {
  requestToggle: () => undefined,
} as Partial<MenuProps>

export default Menu

Using dev tools to manually toggle the open prop that's passed through to the internal use of Popper causes the scroll to top bug I'm experiencing to happen when I use the published version of the package, but not when using a yarn linked version.

标签: reactjstypescriptmaterial-uiyarnpkg

解决方案


推荐阅读