Material-ui: Expose `@material-ui/core/utils` from top-level `@material-ui/core`

Created on 31 Mar 2020  路  19Comments  路  Source: mui-org/material-ui

  • [x] I have searched the issues of this repository and believe that this is not a duplicate.

Summary 馃挕

// packages/material-ui/src/index.js
+ export * from './utils';

Examples 馃寛

import { useForkRef } from '@material-ui/core'

Motivation 馃敠

I may be mistaken, but from what I gather, @material-ui/core/utils is probably safe to import since it has typings, is a 2nd level import, and is imported by another package, @material-ui/lab, although strictly speaking there's no docs. There's also mention of making setRef private, which suggests that utils are currently public.

The main motivation to export it from the top-level @material-ui/core is UMD bundles - we have a design system where we'd like to externalise @material-ui/core but we're currently importing a few things from utils and thus we can't just do e.g. import { useForkRef } from '@material-ui/core'. There are a few userland workarounds like copying and pasting the utils, or somehow still bundling in nested imports like @material-ui/core/utils (as in, not externalising), but we'd like to avoid that if possible. Another module we're currently relying on is @material-ui/core/styles/zIndex but that one we should be able to retrieve by calling createMuiTheme and extracting it from there instead, so not that much of a problem.

Presumably, if @material-ui/lab was to provide a UMD bundle, it would run into this constraint as well.

core enhancement

All 19 comments

Sounds reasonable. @oliviertassinari did we reach a conclusion how we want to consolidate utils or do we stick with the current "put utils as low as possible" approach?

"put utils as low as possible" approach

What does this mean? For someone not too familiar with the approach 馃檪

We have @material-ui/utils as well as each package as its own utils module. We usually start out with having utils even lower e.g. in @material-ui/core/SomeComponent/helpers (or utils). If we need it somewhere else we move it up (here @material-ui/core/utils. Once a lab component (or @material-ui/styles) needs it we move it to @material-ui/utils.

Basically to prevent exposing potentially poor abstractions too early. But I wouldn't be surprised if it's totally random in the end.

Edit: State in react is a good analogy. You don't put state directly into your redux store at first. You start out low until that doesn't work anymore.

I think that's fair! And very sane. Would you say @material-ui/core/utils are currently public though?

Would you say @material-ui/core/utils are currently public though?

Yes. Any first and second level path import.

Be aware that we only support first and second level imports. Anything deeper is considered private and can cause issues, such as module duplication in your bundle.

-- https://material-ui.com/guides/minimizing-bundle-size/#option-1

Shall I raise a PR to re-export them then?

Sure, Olivier can chime in if I missed something.

I think that the only public modules are the ones exported in the barrel index, so as we are speaking @material-ui/core/utils is private. I think that we can put @material-ui/utils in the same category: private (because not documented).

@oliviertassinari would your suggestion be to copy & paste the utils in my project then?

I think that we can put @material-ui/utils in the same category: private (because not documented).

That one is definitely not private. Though breaking changes aren't a problem there since we can be more liberal with version bumps.

That one is definitely not private.

@eps1lon I think that it's up to us to decide what's public and what's private. We could very say it's private, as long as we didn't document it. The only exception would be the barrel index of @material-ui/core that we have repeatedly committed, in the past, to considering public if exported.


@NMinhNguyen Ok, so that was for the current state of affair, regarding the target we should have. I think that we should make modules public based on the value it can potentially bring to users. We have on the verge of a v5, so we will be able to make plenty of BCs anyway.

I would propose the following public modules

  • capitalize
  • createSvgIcon
  • deprecatedPropType
  • unsupportedProp
  • useForkRef
  • useEventCallback
  • useControlled
  • isMuiElement
  • @material-ui/utils
  • ownerWindow
  • debounce
  • ownerDocument

Which leaves us with these modules private

  • useIsFocusVisible
  • setRef
  • scrollLeft
  • createChainedFunction
  • getScrollbarSize

I would propose the following public modules

@oliviertassinari would you like me to explicitly enumerate the public modules vs exporting * from './utils'?

@eps1lon What do you think?

I think that it's up to us to decide what's public and what's private

Nope. The minimal consensus is that the main entry in a public package in the npm registry is public (and should follow SemVer). It's not up to us to deviate from that (unless we want to break peoples code).

The minimal consensus is that the main entry in a public package in the npm registry is public

@eps1lon Agree, assuming the package is considered public. We could very-well consider it a private package we have for the sake of sharing internal logic.

Whatever you decide regarding @material-ui/utils, just make sure that if a breaking change is made to it, then you bump the major version. You can choose not to document it, and have it as private, but you wouldn't want ^1.2.3 of utils to suddenly resolve to ^1.3.0 that contains a breaking change :) Still gives you the flexibility to make frequent breaking changes to it because it's private and shouldn't cause any churn for the community, but just gotta remember to bump the version accordingly. Can also consider adding a similar disclaimer to the package's README: https://github.com/facebook/fbjs

How should I move forward with the PR? https://github.com/mui-org/material-ui/issues/20353#issuecomment-606563659

Just had a chat with Olivier on Twitter, and he said:

Hey, it seems that the simplest will be to export the utils from the top level.
I think that we can expose them all
Solve that [making setRef private] later for v5

@NMinhNguyen Yes, I believe it's what @eps1lon was proposing initially.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

revskill10 picture revskill10  路  3Comments

rbozan picture rbozan  路  3Comments

mb-copart picture mb-copart  路  3Comments

activatedgeek picture activatedgeek  路  3Comments

ericraffin picture ericraffin  路  3Comments