Skip to content

Commit

Permalink
Bundle optimization (#5295)
Browse files Browse the repository at this point in the history
Co-authored-by: Martina Bustacchini <martina.bustacchini@redturtle.it>
Co-authored-by: Mauro Amico <mauro.amico@gmail.com>
Co-authored-by: Steve Piercy <web@stevepiercy.com>
Co-authored-by: Víctor Fernández de Alba <sneridagh@gmail.com>
  • Loading branch information
5 people authored Apr 19, 2024
1 parent 1596de2 commit 6f18663
Show file tree
Hide file tree
Showing 182 changed files with 1,898 additions and 1,830 deletions.
42 changes: 42 additions & 0 deletions docs/source/contributing/bundle-size-optimization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
myst:
html_meta:
"description": "Bundle size optimization in Volto"
"property=og:description": "Bundle size optimization in Volto"
"property=og:title": "Bundle size optimization"
"keywords": "Volto, Plone, frontend, React, Performance, guidelines"
---

(bundle-size-optimization-label)=

# Bundle size optimization

This document describes how to optimize the bundle size of components through {term}`lazy loading` to improve page load times.
Contributors to Volto core should follow the guidelines in this document.


## Lazy loading in core

Since Volto 18, several core components use lazy loading to keep the final build size under control.

For example, the `Form` components are lazy loaded, which means that the code for the form components is only loaded when the user navigates to a page that contains a form.
A new index file has been created at `packages/volto/src/components/manage/Form/index.tsx` that exports the form components with lazy loading.
The `export`s in the main components index (`packages/volto/src/components/index.js`) have been updated to export components from the new specific index.
The same goes for other components that have been lazy loaded, such as the control panels and widgets.

Several `import` statements have been updated to use the new lazy loaded components.
For example, the `Form` component is now imported from `@plone/volto/components/manage/Form` instead of `@plone/volto/components/manage/Form/Form`.
You should keep this in mind, and always import components from the specific component index files when available, while avoiding importing components from the main components index file, if possible.
This should also help to reduce circular dependencies, and help the overall build performance in the long run.


### Unit test components that use lazy loaded components

If you import a component from a lazy loaded index, you can have issues with rendering these in unit tests.
Mocks are provided for lazy loaded components and are available for you to use.
This can be done by using the `jest.mock` function to mock the specific component index.
For example, to mock the `Form` component and all other components in the `Form`-specific index, you can use the following code in your test file:

```javascript
jest.mock('@plone/volto/components/manage/Form');
```
3 changes: 3 additions & 0 deletions docs/source/contributing/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ The Volto Team reviews pull requests only from people with a GitHub account who
```{include} ./branch-policy.md
```


(contributing-install-volto-for-development-label)=

## Install Volto for development

For developing Volto, follow {doc}`developing-core`.


(contributing-translations-label)=

## Translations
Expand Down Expand Up @@ -125,6 +127,7 @@ redux
routing
icons
accessibility-guidelines
bundle-size-optimization
typescript
volto-core-addons
version-policy
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useIntl } from 'react-intl';
import { BlockDataForm } from '@plone/volto/components';
import { BlockDataForm } from '@plone/volto/components/manage/Form';
import type { BlockEditProps } from '@plone/types';

const TestBlockData = (props: BlockEditProps) => {
Expand Down
1 change: 1 addition & 0 deletions packages/volto-slate/news/5295.internal
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update imports to work with the new code split components in Volto. @pnicolli
3 changes: 2 additions & 1 deletion packages/volto-slate/src/blocks/Table/TableBlockEdit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import cx from 'classnames';
import { defineMessages, injectIntl } from 'react-intl';

import Cell from './Cell';
import { BlockDataForm, Icon, SidebarPortal } from '@plone/volto/components';
import { Icon, SidebarPortal } from '@plone/volto/components';
import { BlockDataForm } from '@plone/volto/components/manage/Form';
import TableSchema from './schema';

import rowBeforeSVG from '@plone/volto/icons/row-before.svg';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,8 @@ import {
validateFileUploadSize,
} from '@plone/volto/helpers';
import config from '@plone/volto/registry';
import {
BlockDataForm,
SidebarPortal,
BlockChooserButton,
} from '@plone/volto/components';
import { SidebarPortal, BlockChooserButton } from '@plone/volto/components';
import { BlockDataForm } from '@plone/volto/components/manage/Form';

import { SlateEditor } from '@plone/volto-slate/editor';
import { serializeNodesToText } from '@plone/volto-slate/editor/render';
Expand Down
3 changes: 2 additions & 1 deletion packages/volto-slate/src/elementEditor/PluginEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { isEqual } from 'lodash';
import React from 'react';
import { useDispatch } from 'react-redux';
import { ReactEditor } from 'slate-react';
import { Icon as VoltoIcon, BlockDataForm } from '@plone/volto/components';
import { Icon as VoltoIcon } from '@plone/volto/components';
import { BlockDataForm } from '@plone/volto/components/manage/Form';
import { setPluginOptions } from '@plone/volto-slate/actions';
import BaseSchemaProvider from './SchemaProvider';

Expand Down
2 changes: 1 addition & 1 deletion packages/volto-slate/src/widgets/HtmlSlateWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { MemoryRouter } from 'react-router-dom';
import { Provider, useSelector } from 'react-redux';
import { defineMessages, injectIntl } from 'react-intl';

import { FormFieldWrapper } from '@plone/volto/components';
import { FormFieldWrapper } from '@plone/volto/components/manage/Widgets';
import SlateEditor from '@plone/volto-slate/editor/SlateEditor';
import { serializeNodes } from '@plone/volto-slate/editor/render';
import { makeEditor } from '@plone/volto-slate/utils';
Expand Down
3 changes: 2 additions & 1 deletion packages/volto-slate/src/widgets/ObjectByTypeWidget.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { Menu, Tab } from 'semantic-ui-react';
import { Icon, ObjectWidget } from '@plone/volto/components';
import { Icon } from '@plone/volto/components';
import { ObjectWidget } from '@plone/volto/components/manage/Widgets';

export const ObjectByTypeWidget = (props) => {
const { schemas, value = {}, onChange, errors = {}, id } = props;
Expand Down
2 changes: 1 addition & 1 deletion packages/volto-slate/src/widgets/RichTextWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import React from 'react';
import isUndefined from 'lodash/isUndefined';
import isString from 'lodash/isString';
import { FormFieldWrapper } from '@plone/volto/components';
import { FormFieldWrapper } from '@plone/volto/components/manage/Widgets';
import SlateEditor from '@plone/volto-slate/editor/SlateEditor';

import { createEmptyParagraph, createParagraph } from '../utils/blocks';
Expand Down
5 changes: 1 addition & 4 deletions packages/volto/cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -702,10 +702,7 @@ Cypress.Commands.add(
'pasteClipboard',
{ prevSubject: true },
(query, htmlContent) => {
return cy
.wrap(query)
.type(' {backspace}')
.trigger('paste', createHtmlPasteEvent(htmlContent));
return cy.wrap(query).trigger('paste', createHtmlPasteEvent(htmlContent));
},
);

Expand Down
9 changes: 9 additions & 0 deletions packages/volto/cypress/support/e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ import './commands';
import { setupGuillotina, tearDownGuillotina } from './guillotina';
import { setup, teardown } from './reset-fixture';

Cypress.on('uncaught:exception', (err) => {
// We are getting this error in Cypress tests but we don't use ResizeObserver ourselves
if (/ResizeObserver loop/.test(err.message)) {
// returning false here prevents Cypress from
// failing the test
return false;
}
});

before(function () {
if (Cypress.env('API') === 'guillotina') {
tearDownGuillotina({ allowFail: true });
Expand Down
3 changes: 2 additions & 1 deletion packages/volto/cypress/tests/core/controlpanels/upgrade.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@ describe('Upgrade Site Tests', () => {
body: {
...getUpgradeNeedsUpgrade,
},
}).as('getSystemNeedsUpdate');
}).as('getUpgradeNeedsUpgrade');
cy.navigate('controlpanel');
cy.wait('@getSystemNeedsUpdate');

cy.findByText('Please continue with the upgrade.').click();
cy.wait('@getUpgradeNeedsUpgrade');
cy.get('.content-area').contains(
'The site configuration is outdated and needs to be upgraded.',
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ describe('Block Tests: Links', () => {
it('As editor I can add a link and pressing enter does not add another link in the next block', function () {
// https://github.com/plone/volto/pull/5186
cy.get('#toolbar').click();
cy.getSlate().type('Colorless green ideas sleep furiously');
cy.getSlateEditorAndType('Colorless green ideas sleep furiously');

cy.log('Create a Link');

Expand All @@ -111,8 +111,8 @@ describe('Block Tests: Links', () => {
'https://google.com{enter}',
);
cy.getSlate().should('have.descendants', 'a.slate-editor-link');
cy.getSlate().type('{rightarrow}').type('{enter}');
cy.getSlate().type('Hello').type('{enter}');
cy.getSlateEditorAndType('{rightarrow}').type('{enter}');
cy.getSlateEditorAndType('Hello').type('{enter}');

cy.toolbarSave();

Expand Down
1 change: 1 addition & 0 deletions packages/volto/news/5295.internal
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Reduced JavaScript bundle size of the production build. Code split several internal modules: Controlpanels, Form, Widgets among other small ones. @pnicolli @deodorhunter
1 change: 1 addition & 0 deletions packages/volto/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@
"@testing-library/react": "14.2.0",
"@testing-library/react-hooks": "8.0.1",
"@types/jest": "^29.5.8",
"@types/loadable__component": "^5.13.9",
"@types/lodash": "^4.14.201",
"@types/react": "^18",
"@types/react-dom": "^18",
Expand Down
Loading

0 comments on commit 6f18663

Please sign in to comment.