Page tree
Skip to end of metadata
Go to start of metadata

Problem

We need to have the CSS and JS resources loaded on each page which are required by any of the components that are on the page.

A common solution for this is to bundle all the CSS and JS resources needed on the entire site, and to reference those bundles on every page of the website.

However if the bundle is large, this can cause page loads to be too slow.

We want an approach which:

  • Ensures that all requried resources are present for each page.
  • Has fast loading speeds - by not including unnecessary resources on every page.
  • Has a good/easy development experience and authoring experience.

Note: This is closely related to the "code-splitting" topic which is hot in frontend framework discussions. Here we are specifically discussing server rendered pages which can contain css and js.


Ideas

Special page templates

In some cases, the very heavy resources are only required on certain pages. For example, you may have a "product configurator". Its only used on 1 or 2 pages. Then do not include its resources in the bundles. Specifically include the resources in only those page templates where the component can be used.

Cons

  • Only relevant in the case of a few heavy components that only can appear on certain pages.

Component template script references its resources

Each component (Or maybe only the components with truly heavy resources) simply references its required JS and CSS directly in the html of the template script.

Cons

  • The css tag is not in the header as you would like.
  • The js tag is not in the header or at the bottom of the page as you would like.
  • The resources might be referenced multiple times. (But the browser would only load it once I believe.)

Loop through components on page

In ftl you can loop through the tree of child areas and components (mgnl:component) of the page.  Then based on child templateId, get its template definition, and render its specific resources. The component template definition (definition parameters) would need to include which resources that componenent needs.

The FTL could use this technique once at the top of the page for CSS and once at the bottom of the page for JS.

Question:s

  • Can you keep a resource from being included more then once? ie what if page has two instances of "fancy carousel". How?

Cons

  • The resources might be referenced multiple times. (But the browser would only load it once I believe.)
  • May decrease performance of page rendering. (Which can be mitigated by caching.)


IncludeThisResource templating function

Imagine creating some additional features to the resfn (https://documentation.magnolia-cms.com/display/DOCS62/resfn) which would enable a component template to request a resource to be included in a "slot" in the head or at the base of the page. The functions in the page would be smart and only render each resource one time. Somehow the system would have to "retroactivly" put the desired resources in the head.

Example API....

${resfn.createSlot("head")} <!-- In the page template. -->

${resfn.cssToSlot("/foobar/heavy.css", "head")} <!-- In the component template. -->

${resfn.jsToSlot("/foobar/heavy.js", "base")} <!-- In the component template. -->

${resfn.createSlot("base")}<!-- In the page template. -->

Cons

  • Probably non-trivial to develop. 

Loop through all resources

Make a freemarker function on page level to loop through all resources (list of resources must be registered somewhere), and check if their component is on a page and add the resources only then.


Client-side Library - MOM

This library is designed to solve this problem. But it is a small project.

"Dynamic Loading of Javascript based on DOM elements."

https://mom.js.org


Client-side Library - requireJS

requireJS has been used in the past to accomplish this. But I don't think its used  very actively now.

https://requirejs.org/




  • No labels