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

[DatePicker] Use only path imports from @material-ui/core #24146

Closed
oliviertassinari opened this issue Apr 14, 2020 · 20 comments · Fixed by #24147
Closed

[DatePicker] Use only path imports from @material-ui/core #24146

oliviertassinari opened this issue Apr 14, 2020 · 20 comments · Fixed by #24147
Labels
component: date picker This is the name of the generic UI component, not the React module!

Comments

@oliviertassinari
Copy link
Member

Material-UI forbid imports over two levels as it can lead to duplication in people bundles. Meaning, if somebody does:

import { Modal } from '@material-ui/core'; // 1.
import TrapFocus from '@material-ui/core/Modal/TrapFocus'; // 2.

It will bundle 1. and 2.:

  1. https://unpkg.com/browse/@material-ui/core@4.9.10/esm/Modal/TrapFocus.js
  2. https://unpkg.com/browse/@material-ui/core@4.9.10/Modal/TrapFocus.js

Now, given we do:

https://github.com/mui-org/material-ui-pickers/blob/7bed283699ef768936a3ec7c5dc89571492dddd4/lib/src/wrappers/DesktopPopperWrapper.tsx#L6

in the codebase, we very likely cause this double bundling quite often. For instance:

import { Dialog } from '@material-ui/core';
import { DateRangePicker } from '@material-ui/pickers';
@dmtrKovalenko
Copy link
Member

dmtrKovalenko commented Apr 14, 2020

Hmm, I am not really sure about why? In theory, webpack should understand that we are importing the same file.

P.S. I'd like not use @material-ui/core/Button imports because of typescript autoimport. I am not writing imports manually at all. Is there any preference of using path imports instead of index?

By the way, is there any eslint plugin that will automatically change the import. If no – I can write one

@TrySound
Copy link
Contributor

@dmtrKovalenko @material-ui/core/Modal/TrapFocus.js and @material-ui/core/esm/Modal/TrapFocus.js is not the same file

@dmtrKovalenko
Copy link
Member

dmtrKovalenko commented Apr 14, 2020

ohh god, really... thanks @TrySound then its definitely a problem
Moreover, I think we need to provide more clear esm build.

@oliviertassinari
Copy link
Member Author

It can be verified with this sandbox https://codesandbox.io/s/wonderful-yonath-5cted?file=/src/App.js I have deployed for production in https://csb-5cted.netlify.com/.

Duplication 🔽
Capture d’écran 2020-04-14 à 15 42 32

@TrySound
Copy link
Contributor

unstable_TrapFocus export is a good way to go for internal usage.

@dmtrKovalenko
Copy link
Member

I mean overall. Does import from the core for the current build is somehow worse than path import?
I`d like to open another issue to clarify imports

@oliviertassinari
Copy link
Member Author

oliviertassinari commented Apr 14, 2020

By the way, is there any eslint plugin that will automatically change the import. If no – I can write one

We have this eslint plugin for internal usage of the mono-repository: https://github.com/mui-org/material-ui/blob/master/packages/eslint-plugin-material-ui, It could be great to publish it on npm for external users. If this is something you want to work on 👍.
For the date picker components, there is no much need to worry about it, we will get it for free with a merge of the git repository.

I am not really sure about why?

Regarding, the why. Let's take my repository and expand the resolution, using equivalences:

import { Dialog } from '@material-ui/core';
import { DateRangePicker } from '@material-ui/pickers';

<=>

import Dialog from '@material-ui/core/esm/Dialog.js';
import TrapFocus from '@material-ui/core/Modal/TrapFocus';

<=>

import Modal from '@material-ui/core/esm/Modal.js';
https://unpkg.com/browse/@material-ui/core@4.9.10/Modal/TrapFocus.js

<=>

https://unpkg.com/browse/@material-ui/core@4.9.10/esm/Modal/TrapFocus.js
https://unpkg.com/browse/@material-ui/core@4.9.10/Modal/TrapFocus.js

@dmtrKovalenko
Copy link
Member

dmtrKovalenko commented Apr 14, 2020

I figured out why. But another question of why do we need an esm folder – it is confusing and easily can lead to duplicates in developers bundle. And do we need path imports at all, if core exports are treeshakable.

@oliviertassinari
Copy link
Member Author

oliviertassinari commented Apr 14, 2020

Ok great

why do we need an esm folder? Do we need path imports at all?

It explained in https://material-ui.com/guides/minimizing-bundle-size/. Adding @eps1lon to the loop.

@dmtrKovalenko
Copy link
Member

⚠️ The following instructions are only needed if you want to optimize your development startup times or if you are using an older bundler that doesn't support tree-shaking.

So I suppose we need to just use core imports on core documentation overall.

@eps1lon
Copy link
Member

eps1lon commented Apr 14, 2020

Allowing certain path imports by convention is definitely a brittle approach. In the future we likely leverage export maps so that it's obvious what's allowed and what isn't.

But another question of why do we need an esm folder

Because it would require rewriting file extensions instead. We use relative imports without extensions throughout the codebase and it's not clear to me that all bundlers (during v4 development) were capable of figuring out which files is meant when importing './TrapFocus': TrapFocus.mjs or TrapFocus.js.

The goal is definitely to publish a correct ES modules build at some point but we need to know if this works across bundlers and need to implement this as well. The /esm folder is a simple solution that is used throughout the ecosystem. In hindsight we should've moved all source files into /dist to make it obvious that you're in dangerous territory.

Either way

unstable_TrapFocus export is a good way to go for internal usage.

seems like good tradeoff. We definitely don't want to add more exceptions to what kind of path imports are allowed.

So I suppose we need to just use core imports on core documentation overall.

Not really following what you mean. We shouldn't use path imports deeper than @material-ui/core/FirstLevelModuel in the documentation. If you find deeper imports please let us know.

@dmtrKovalenko
Copy link
Member

dmtrKovalenko commented Apr 14, 2020

@eps1lon thanks for description. I am not 100% sure why we cannot use@material-ui/core imports now? Or at least make it the recommended way to import? Is there some performance issue, because they are properly treeshaking by all bundlers as for now.

@eps1lon
Copy link
Member

eps1lon commented Apr 14, 2020

I am not 100% sure why we cannot use@material-ui/core imports now?

Tree-shaking is by default a production-only feature in webpack 4 and earlier (not sure about 5). This means that webpack will parse the full /core module even if you only import a single part of it. This means that you have a slower cold-start of your webpack dev server. By importing from /core/Button webpack will only parse /core/Button and its imports which is far less than the full module.

It doesn't affect user code at all. It's a dev-only optimization. I haven't followed the discussion around this so this might've changed in new versions of webpack.

@dmtrKovalenko
Copy link
Member

Thanks, got it @eps1lon
Ok, so we need to actually change all the imports for pickers. Only one pain in the ass left – is auto imports.

For now, I`ll just copy and enhance the rule from the https://github.com/mui-org/material-ui/tree/master/packages/eslint-plugin-material-ui

@dmtrKovalenko dmtrKovalenko changed the title Import /unstable_TrapFocus instead of /Modal/TrapFocus Use only path imports from @material-ui/core Apr 14, 2020
@eps1lon
Copy link
Member

eps1lon commented Apr 14, 2020

Ok, so we need to actually change all the imports for pickers. Only one pain in the ass left – is auto imports.

We should probably bite the bullet and publish a babel plugin for that. Having different approaches floating around in "userspace" is pretty dangerous. The only problem is how we make it compatible with any (minor v4) version of Material-UI.

@NMinhNguyen
Copy link
Contributor

It could be great to publish it on npm for external users. If this is something you want to work on 👍.

I ended up needing it recently so I just copied and pasted it. But I was wondering what's left to do and why it can't just be published? Seems to be working fine? Sorry if this isn't the right repo to discuss.

@oliviertassinari
Copy link
Member Author

@mbrookes Could you extend the number of people that have the publish rights on https://www.npmjs.com/package/eslint-plugin-material-ui? I think that it could be interesting to publish a new version, at least for internal usage.

@mbrookes
Copy link
Member

image

😱(Has it been that long?!)

Could you extend the number of people that have the publish rights

Done.

@oliviertassinari
Copy link
Member Author

oliviertassinari commented Apr 23, 2020

@mbrookes Thanks, yeah wow.

@mbrookes
Copy link
Member

I can't now remember why it was published in the first place, considering it's only used internally... 🤔

@oliviertassinari oliviertassinari changed the title Use only path imports from @material-ui/core [DatePicker] Use only path imports from @material-ui/core Dec 27, 2020
@oliviertassinari oliviertassinari transferred this issue from mui/material-ui-pickers Dec 27, 2020
@oliviertassinari oliviertassinari added the component: date picker This is the name of the generic UI component, not the React module! label Dec 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: date picker This is the name of the generic UI component, not the React module!
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants