Skip to content

Javascript bundle optimization #5419

Description

@pnicolli

PLIP (Plone Improvement Proposal)

Responsible Persons

Piero Nicolli (@pnicolli)

Proposer

Piero Nicolli (@pnicolli)

Seconder

Victor Fernandez de Alba (@sneridagh)
Tiberiu Ichim (@tiberiuichim)

Abstract

This PLIP aims at optimizing the main javascript bundle that is downloaded by the client for every page load. It got quite big (~580kb gzipped) and most of it is really not needed, most of it is actually only needed by logged in users (e.g. controlpanels).

Motivation

Web vitals, as measured by Lighthouse for example, are becoming more and more important as a selling point. Some clients reportedly required specific scores. We need to provide a good starting point with Volto core and better examples for client projects.

Assumptions

The first assumption made here is that this will result in a breaking change for Volto, therefore only targeting version 18. We will definitely try to find a way to avoid a breaking change, but we should assume that it is for now, for release planning purposes.

Proposal & Implementation

There is a PR with a proposal of how to load parts of the code lazily #5295

A brief explanation of a the implementation details:

We should try to avoid "just lazy loading", we should group javascript chunks into appropriate ones. For example, all widgets will be lazy-loaded but it would be better if only one javascript chunk is downloaded with all the widgets.
Example code:

import loadable from '@loadable/component';

export const Field = loadable(
  () =>
    import(
      /* webpackChunkName: "Form" */ '@plone/volto/components/manage/Form/Field'
    ),
);
export const InlineForm = loadable(
  () =>
    import(
      /* webpackChunkName: "Form" */ '@plone/volto/components/manage/Form/InlineForm'
    ),
);
export const ModalForm = loadable(
  () =>
    import(
      /* webpackChunkName: "Form" */ '@plone/volto/components/manage/Form/ModalForm'
    ),
);
export const UndoToolbar = loadable(
  () =>
    import(
      /* webpackChunkName: "Form" */ '@plone/volto/components/manage/Form/UndoToolbar'
    ),
);

By specifying the magic comment webpackChunkName, webpack knows that we are asking to put those things in the same javascript chunk and it actually does IF this is the only way that these components are imported elsewhere.
In other words, every time a component is lazy-loaded, a check should be done to see if it is actually split and if the split chunk is the only way it is used.
The command yarn analyze helps with that: after changing the import and adding lazy loading, the web page of the report allows to search. Searching "Form" for example highlights every occurrence of the word Form in the javascript chunks and we are able to see if a single copy of the Form component is there and if it is in its own new chunk or if is left in the main chunk for some mistake that we made or some fix that we need to do.

Deliverables

  • lazy loading things is a lot of work because of all the bundle analysis checks that need to be done, so multiple incremental PRs will be proposed towards this goal in order to have short term results to show and also a longer term major improvement
  • due to the specifics of how web vitals work, we cannot have a specific goal for those, in numbers, and it would not be super important to have one since the final numbers in client projects depend on the theme that is built on top of volto
  • documentation on how to properly lazy load components in order to guide integrators in creating their themes with better web vitals results

Risks

If a solution is not found for keeping the main src/components/index.js index, a big breaking change would happen. If it happens, we could discuss an addition to the deliverables, which is a codemod tool to update the affected imports in client projects.

Participants

@plone/volto-team
@plone/documentation-team

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions