Page Caching
Caching for Page Designer pages is similar to other pages, with some nuances.
Controller Pagecache Lifecycle
The rendering or serialization of a page starts with a top-level request from the web
adapter that invokes a custom controller, such as Page-Show
, on the
application server. For example, the Page.js
controller from the
SFRA Page Designer reference implementation uses the following snippet to check if
the page is visible. Only pages with no visibility rules are pagecached.
server.get('Show', cache.applyDefaultCache, consentTracking.consent, function (_req_, res, next) {
...
var page = PageMgr.getPage(req.querystring.cid);
if (page != null && page.isVisible()) {
if (page.hasVisibilityRules()) {
res.cachePeriod = 0; // pages with visibility rules should not be cached
res.cachePeriodUnit = 'hours';
}
res.page(page.ID, {}); // invokes PageMgr.renderPage()
} else {
...
}
next();
}, pageMetaData.computedPageMetaData);
Deciding if you want to apply pagecaching in your controller, and how to do so, is effectively a case by case decision. Donโt create pagecache conditions in your code that are subject to the request context, thus not pagecacheable in a global manner.
Page Rendering Using Nested Remote Includes to Handle Visibility Rules
Parallel to the first pagecache lifecycle constructed around the controller, thereโs a second pagecache lifecycle constructed around the actual contents of the page that is initiated by two nested remote includes.
When PageMgr.renderPage()
renders or
PageMgr.serializePage()
serializes a page:
- The first-level remote include is the system controller
__SYSTEM__Page-Include
. This remote include determines a visibility fingerprint of the page and its components, which are visible for the current request context (based on schedules, customer groups, or other visibility settings). Due to this context evaluation, this remote include is never going to be pagecached - or in other words, any page rendering or serialization only hits this remote include one time. It then passes the visibility fingerprint to the second-level remote include. - The second-level remote include is the system controller
__SYSTEM__Page-Render
(rendering) or__SYSTEM__Page-Serialize
(serialization), which is pagecachable based on the attached visibility fingerprint. This remote include invokes the custom scripts of the render function to render the page, or the serialize function to serialize the page. The response created is configured with pagecache settings through the previously mentioned scripts that are invoked for the page and all its processed visible components.
If you check caching for the first-level remote include,
__SYSTEM__Page-Include
, all invocations appear uncached. The
second-level remote include, __SYSTEM__Page-Render
or
__SYSTEM__Page-Serialize
, maintains caching statistics for Page
Designer pages but those caching statistics track caching for all Page Designer
pages. If you have several Page Designer pages, such as a home page and a Product
Detail page, you can't track caching separately per page.
Page and Component Pagecache Lifecycle
The pagecache lifecycle of the page contents is induced through a separate request.
This isnโt tied to the first pagecache lifecycle of the top-level request or
controller (for example, Page-Show). If you configure pagecaching for the page
itself, or any component within that page, the setting is applied for the response
of the __SYSTEM__Page-Render
and
__SYSTEM__Page-Serialize
request. Thus this setting affects the
pagecaching for the whole page, and anything within it, but doesnโt affect anything
outside of it like the controller that initiated the rendering.
If different pagecache settings are supplied for different components of the page, the response takes on the shortest of the pagecache settings. For example, if you have a page where:
- Component A has a 1-minute relative pagecaching.
- Component B has a 1-hour relative pagecaching.
- Component C has a 1-day relative pagecaching.
The final calculated relative pagecaching is the minimum of these three values (1 minute).
Letโs look at an excerpt of the component type implementation that corresponds to component B to see how it instruments the response for a 1-hour pagecaching. Assuming this component presents personalized information (for example, based on a combination of pricebook, promotion, sorting rule, and A/B test segments), then you must account for that by instrumenting the response with the corresponding vary-by. For more information, refer to the B2C Commerce Script documentation in the Commerce Cloud Infocenter.
module.exports.render = function(context) {
// do your business logic
...
// instruct 1 hour personalized relative pagecache
var expiry = new Date();
expiry.setHours(expiry.getHours() + 1);
response.setExpires(expiry);
response.setVaryBy('price_promotion');
// create markup
return ...;
}
If you use dw.util.Template.render()
to produce your markup, as SFRA
does, then you must not use <iscache>
in your template. Use
response.setExpires()
, as shown above, because the
dw.util.Template
class is suited only for string or markup
generation and not response modification.
If you donโt supply any pagecache setting for your page and none of its components (for example, neither the page type implementation itself nor component A, B, or C related component type implementations configure a pagecache setting) then the page isnโt going to be pagecached at all. As soon as at least one of these building blocks within a page supplies a pagecache setting, pagecaching happens.
Because the visibility fingerprint is also factored in to the pagecache key of a page
rendering or serialization (in shape of a query parameter vf
of the
cachable __SYSTEM__Page-Render
and
__SYSTEM__Page-Serialize
), thereโs no need for the page or
component type implementation to care about page or component visibility rules, that
take for example customer groups into consideration, as this is already
automatically handled for you.
Best Practices
If your page or component requires a minimum pagecache setting, supply it in your page or component type implementation. Component types require extra care as this pagecache setting is affecting the pagecache of the entire page and not just the component alone.
For a page type that doesnโt supply a pagecache setting, carefully think about this decision as this means that a pageโs components determine if the page is pagecached or not.
If the content of a component canโt be affected by the pagecache settings of the page, other components, or must not be pagecached at all, you must move such content into a remote include to separate it from the rest of the page. The remotely included controller (and its respective template) can then use a pagecache setting as it fits its business purpose. For example, a product tile component that renders the productโs inventory would likely want to include this inventory state in a remote include manner so that the current inventory can always be shown while the remainder of this component can still be pagecached.