-
-
Notifications
You must be signed in to change notification settings - Fork 728
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
Lazy loading components #967
Conversation
Also, there are now warnings during testing that say it would be better to upgrade React to 16.9^, is it something that's already planned? |
@pnicolli thank you for your work on this! This is a major step for the bundle optimization and highly appreciated! I guess upgrading to React 16.9 is on our todo list. Though, we should do so in a separate PR. |
src/components/index.js
Outdated
@@ -5,65 +5,65 @@ | |||
*/ | |||
export Anontools from '@plone/volto/components/theme/Anontools/Anontools'; | |||
export Breadcrumbs from '@plone/volto/components/theme/Breadcrumbs/Breadcrumbs'; | |||
export ContactForm from '@plone/volto/components/theme/ContactForm/ContactForm'; | |||
// export ContactForm from '@plone/volto/components/theme/ContactForm/ContactForm'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pnicolli @sneridagh @robgietema this is technically a breaking change, correct? Do we have to assume ppl rely on those imports already? This has nothing to do with this PR really. We just have to somehow define our Volto API for semantic versioning/releases and upgrade guides.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tisto It is, but for code splitting work as expected, we need to remove them which kind of sucks... Unless we find a better/elegant way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's a breaking change :( Also, my current implementation is absolutely non-elegant, it would be awesome to find a better one. One components index per split bundle, for example, but that would mean having a better idea of what bundles we will split.
@pnicolli I'm a bit scared if the component overriding will continue working using loadable components, since we are removing the one single import point. We will have to experiment with it too. I used the plane time home to play with it (I can't helped it!) and I've solved a problem in Html.jsx, can I push things there to improve it? Also, I couldn't get the routes working (it just do not create the chunk), did it for you? I will test your branch asap. I thought it's because how we use the routing (because of redux async in SSR, we should use react-router-config). Thanks! Good work!! |
@pnicolli I played around with this a bit (couldn't help even if I have some really urgent tasks on my todo list :)). The lazy loading works! The bundle size is not significantly smaller yet (2.2 mb vs 2.3 mb non-gzipped). Though, that's fine for now. I'd be also totally ok with just adding the lazy loading infrastructure first, merge it into master and then look into which parts we actually want to lazy load. I think the main target for this optimization is the Volto editor part (/edit /add routes). Maybe we should focus on this first and go step by step. What do you think? |
@sneridagh Of course you can push things here. Also, from tomorrow to tuesday 5th I will be out of town and I'm not sure I will be able to contribute, so feel free to push stuff here even if I don't answer to comments during these days. @tisto The bundle size is not dramatically reduced as you said. I like the idea of merging the configuration and basic implementation and iterate on that, though. My gut feeling is that most of the things are reusing the same components, therefore webpack bundles most of the components in the main bundle anyways, so basically we only split the root components of routes, not everything under them. For example, I would love to try and lazy load every semantic-ui component inside the views and see what happens. A good analysis tool would probably be a graph of the components and how they're tied to each other. The more it looks like a tree, the more it will be easy to reduce bundle size. |
* master: (34 commits) Back to development Release 4.0.0-alpha.12 Amend changelog Change to official Plone docker image in the docs Add loading animation for save and edit buttons. (#956) Set Cypress viewport width to 1280px. (#968) Move Body class depending on content type to App component in order to make it available everywhere, Add root class name to Tags component (#1006) Update last remainings of the old image Update versions Update README and docs Small i18n fixes (#1003) Improve upgrade guide Back to development Release 4.0.0-alpha.11 Slight fix on OB improvement (#1002) Improved ObjectBrowser API to allow arbitrary field names and a custo… (#1000) Fix ability to develop Volto itself (as and addon with a mrs.developer checkout) inside a Volto project (#1001) Add internationalization section to docs. (#964) improve documentation for Icon component (#996) Fix icon in TextWidget (#974) ...
…serlist in package.json (#1007)
@sneridagh w00t! Seriously? That's so awesome!!! |
…it kind of loose sync after `cy.request` request on Cypress tests
@pnicoli @tisto @cekk @giuliaghisini @nzambello 🎉 aaaaaaand it's green!! 🎉 @pnicolli I will amend your suggestion code might be a merge issue. |
@sneridagh awesome! 🎉 |
@pnicolli BTW, I don't see how we can improve the test story :( I think that we have no other way to do it. The worse part is that we need to document it properly and that the overall DX complexity is raised one level. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's ready.
@avoinea I would like to know your opinion on the current shape of this one. |
@robgietema if you could take a look too before merging, it would be great! |
@tiberiuichim raised some concerns about lazy load everything in Volto. I have to admit that I do have some concerns too about the final shape (raising complexity) of the current state and that it will lead to worsen the DX. What about to have a meeting to discuss this before merging? /cc @pnicolli @tiberiuichim @tisto @robgietema @nzambello @giuliaghisini @avoinea |
Okay, I made some research, and I think I found something. Let me know what do you think: The gist is here: import React from "react";
import { render } from "@testing-library/react";
import App from "./App";
import { Component1, Component2 } from "./components";
describe("CustomComponent", () => {
it("rendered lazily", async () => {
const { container, getByText } = render(<App />);
await Component1;
await Component2;
expect(container.firstChild).toMatchSnapshot();
expect(getByText("Component1"));
expect(getByText("Component2"));
});
}); The key is await for the loadable components in the tests. Yes, we will have to revisit all the tests, but might pay its price, since we will detect the ones that rely (unnecessarily) in child components. Then in the future we will be able to improve them bit by bit. /cc @pnicolli @tiberiuichim @avoinea @giuliaghisini @nzambello @cekk @robgietema @tisto |
Yes, that's exactly what I meant by "I feel like the only other solution would be to rewrite all the tests" 😁 I tried something very similar in the very first draft of the PR, that's why I added testing-library in the first place 😛 Regarding what to code-split, I actually kind of agree with @tiberiuichim. I said something similar on slack earlier, I thought I posted it here as well but actually I didn't 😞 I can see the benefit of having an entry point (the We could probably try to lazy load only the external libraries, the cms views (edit, controlpanels, etc), and probably the content-type views, even if it's probably not necessary since they reuse components already used in the other parts of the interface (mostly Semantic UI components and nothing more). I would be careful, though, to test a couple things properly:
Should we try to branch from here, change the lazy loading story like this (views and libraries) and manually try it? |
Yeah, kind of missed that :) I mixed things :( I was referring to rewrite to not rely solely on snapshots and alike.
Yeah, the more I see it, the more I also think it. However, it can be hard to make
Maybe we should not allow core components to use it? Then Webpack will "see" only the specific imported components...
+1
I tried it the lazy branch with a project and works well... In my projects I usually use the import {x} from '@plone/volto/components' way.
Outside core, I guess you can test your own components the same way as before, as long you do not require a Volto component that is lazy loaded...
I would do that, and play a bit more with it. At least to know what results we can get from it. My proposal:
if it goes well...
then, from here, we can slowly lazy load components as we find it useful to do so, refrain if it does not make sense. What do you think? |
In fact, if from the user point of view, nothing changes... then we could live without marking it as breaking, right? |
time to do a 😄 : import this +1 on the idea to use lazy loading just in the most important places if code gets more difficult do deal (debug and implementation) |
100% love the plan :) |
Closing this one, although we should remember it as reference for further improvements. |
First working draft. I left several comments that still need to be cleaned up, but I think they help to see what needs to be done to make a component load lazily.
At the moment, all of the main routes are split. In addition to those, also che Toolbar, ModalForm and Toast component are, as well as the File, Image and News Item views.
There are implementation issues that might lead to quite a lot of refactoring to add lazy loading to core volto components. See for example how many things I had to change in the
src/components/index.js
file. Every time a component has an import likeimport { Comp } from './components'
webpack actually bundles all components in, so I had to refactor that to make it work. Many things in Volto core are grouped in an index file like that, therefore the refactoring issue I was talking about. Maybe we need to come up with a different approach for grouping components, for example for each split bundle we want.For the same reason, I feel like current split bundles could be optimized by checking what actually is being split. Still, I believe we have a good starting point.
First things to do that come to mind: