Decide where the pages of a Core dna site are composed before writing code: on the platform, in your own application, or on the platform with a few pieces filled in by the browser. The decision tree, each shape in depth, multi-brand and languages, and a table and case studies to make the call.
L2
Unit 04 · Hybrid, the common case
A personalisation bundle that loads only when it is on
Hybrid, the common casePage 18 of 29Updated
Gate a whole JavaScript bundle on a site setting, so visitors download it only when the feature is switched on; let the bundle announce itself with an event; and fetch the personalised block as a fragment whose parameters reach the cache key.
Who this is for. The JavaScript developer adding personalisation, recommendations or any feature an administrator should be able to switch off. After this page the feature costs nothing when it is off, page code works whether or not it is on, and the personalised block is never cached for the wrong visitor.
The switch: a site data entry
Keep the switch in site data, under a key such as personalisation-settings, holding {"enabled": true}. Templates read it with _siteData; an administrator changes it without a deploy. The template loads the bundle only when the switch is on, and the placeholder for the personalised block is always there, so the page works either way. The setting is the same for every visitor, so reading it is safe in a cached page:
The bundle is its own webpack entry, so the main bundle does not carry it (Splitting bundles). The ?v= built from the deploy's commit hash makes browsers fetch the new file after each deploy.
The bundle announces itself
Page code must not assume the bundle is there: when the switch is off, it is not. So the bundle fires an event once it knows what it knows about the visitor, from the pages they have viewed and the region it has worked out, and page code listens for it. When the bundle is absent the event never fires, and the placeholder keeps its default content.
JavaScriptsrc/js/personalisation.js and the page's script
// In the bundle, once the visitor's profile is ready
document.dispatchEvent(new CustomEvent('site:personalisationReady', {
detail: { region: profile.region, recent: profile.recentIds },
}));
// In page code: does nothing unless the bundle is loaded
document.addEventListener('site:personalisationReady', async (event) => {
const slot = document.getElementById('recommended');
if (!slot) return;
const query = new URLSearchParams({
region: event.detail.region,
recent: event.detail.recent.join(','),
});
const response = await fetch('/fragments/recommended?' + query, { credentials: 'same-origin' });
if (response.ok) slot.innerHTML = await response.text();
});
The fragment it fetches
The recommendations are a fragment like any other (Dynamic fragments), with one difference: its answer depends on the query string. It must either switch caching off or make its parameters part of the cache key; with neither, the first visitor's recommendations are stored and shown to everyone. Reading the parameters with $_request->getParameter() adds them to the key; switching the cache off is the safer choice when the parameters are as varied as a visitor's history:
{% do _response.preventCaching() %}
{% set region = _request.getParameter('region')|default('') %}
{% set recent = (_request.getParameter('recent')|default(''))|split(',') %}
{{ include('includes/recommendations.html', {region: region, recent: recent}) }}
In practice
A touring company's site in the case studies works this way: a site data switch an administrator toggles from a tool in the admin, a separate bundle that tracks recent visits and the visitor's region in the browser, an event when it is ready, and server-rendered recommendation blocks fetched with the profile in the query string. Its members' top bar and exclusives are fragments too, each switching caching off, on pages that stay cached for everyone else.