From 7a90bb38da044a5160d08edc59b93d22e0d4806d Mon Sep 17 00:00:00 2001 From: Tara Ojo Date: Mon, 5 Aug 2024 16:04:36 +0100 Subject: [PATCH 1/2] Update example to use createWorklet over addModule We want to show more uses of the createWorklet method, this example is a straight swap from addModule to createWorklet. In other examples I'll remove the use of the iframe. --- sites/content-producer/url-selection/ab-testing.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sites/content-producer/url-selection/ab-testing.js b/sites/content-producer/url-selection/ab-testing.js index 576fbe7..bf54113 100644 --- a/sites/content-producer/url-selection/ab-testing.js +++ b/sites/content-producer/url-selection/ab-testing.js @@ -42,7 +42,9 @@ function getRandomExperiment() { async function injectAd() { // Load the worklet module - await window.sharedStorage.worklet.addModule('ab-testing-worklet.js'); + const abTestingWorklet = await window.sharedStorage.createWorklet( + 'ab-testing-worklet.js' + ); // Set the initial value in the storage to a random experiment group window.sharedStorage.set('ab-testing-group', getRandomExperiment(), { @@ -56,7 +58,7 @@ async function injectAd() { const resolveToConfig = typeof window.FencedFrameConfig !== 'undefined'; // Run the URL selection operation to select an ad based on the experiment group in shared storage - const selectedUrl = await window.sharedStorage.selectURL('ab-testing', urls, { + const selectedUrl = await abTestingWorklet.selectURL('ab-testing', urls, { data: groups, resolveToConfig, keepAlive: true, @@ -71,7 +73,7 @@ async function injectAd() { } // Run the reporting operation - await window.sharedStorage.run('experiment-group-reporting') + await abTestingWorklet.run('experiment-group-reporting') } injectAd(); From 27247a695517a0de6faa99c11d8f158de7c3a630 Mon Sep 17 00:00:00 2001 From: Tara Ojo Date: Tue, 6 Aug 2024 17:44:00 +0100 Subject: [PATCH 2/2] Swap cross-origin iframe to cross-origin request I've picked the creative rotation example at random to try out the createWorklet function here. Unlike the previous commit where you can do a straight swap between addModule and createWorklet, in this commit I've removed the iframe completely. As we're relying on the data being managed by the script-origin I've also had to move the seedStorage function into the worklet so it is written into the storage for the content producer instead of the publisher. I've also set a new click handler for the demo controls, this also loads the worklet to ensure we write to Shared Storage with the script- origin. Whenever we request a worklet from a different origin we need to set the headers to allow cors and enable cross origin worklets. As I've removed the iframe, I've moved the controls of the demo into the invoking page directly (using hbs partials). For the sake of the demo I've added the global getContentProducerUrl function to make it easier to check the domain of the content producer within the JS files for getting the worklet and the ads. Also, as the demo is no longer being styled within the iframe I've copied the css styles to the publisher pages. --- firebase.json | 8 +++ functions/app/helpers/setup-view.js | 1 + functions/view/main.hbs | 13 +++- .../partials/creativeRotationDemoControls.hbs | 26 +++++++ .../view/publisher-a/creative-rotation.hbs | 3 +- .../view/publisher-b/creative-rotation.hbs | 3 +- .../creative-rotation-worklet.js | 21 ++++++ .../url-selection/creative-rotation.html | 69 ------------------- .../url-selection/creative-rotation.js | 34 ++++----- sites/publisher-a/index.css | 48 +++++++++++++ sites/publisher-b/index.css | 49 +++++++++++++ 11 files changed, 185 insertions(+), 90 deletions(-) create mode 100644 functions/view/partials/creativeRotationDemoControls.hbs delete mode 100644 sites/content-producer/url-selection/creative-rotation.html diff --git a/firebase.json b/firebase.json index 4d94824..198ef62 100644 --- a/firebase.json +++ b/firebase.json @@ -70,6 +70,14 @@ { "key": "Supports-Loading-Mode", "value": "fenced-frame" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Shared-Storage-Cross-Origin-Worklet-Allowed", + "value": "?1" } ] } diff --git a/functions/app/helpers/setup-view.js b/functions/app/helpers/setup-view.js index 5ab32af..5b9407d 100644 --- a/functions/app/helpers/setup-view.js +++ b/functions/app/helpers/setup-view.js @@ -25,6 +25,7 @@ module.exports = (app, viewName) => { hbs.engine({ extname: '.hbs', layoutsDir: path.join(__dirname + '/../../view'), + partialsDir: path.join(__dirname + '/../../view/partials') }) ); diff --git a/functions/view/main.hbs b/functions/view/main.hbs index 3c13b09..a872f06 100644 --- a/functions/view/main.hbs +++ b/functions/view/main.hbs @@ -31,9 +31,16 @@ diff --git a/functions/view/partials/creativeRotationDemoControls.hbs b/functions/view/partials/creativeRotationDemoControls.hbs new file mode 100644 index 0000000..e32cbd1 --- /dev/null +++ b/functions/view/partials/creativeRotationDemoControls.hbs @@ -0,0 +1,26 @@ +
+ +
+
Demo control
+
+ + + +
+
+
\ No newline at end of file diff --git a/functions/view/publisher-a/creative-rotation.hbs b/functions/view/publisher-a/creative-rotation.hbs index ae4853b..2098845 100644 --- a/functions/view/publisher-a/creative-rotation.hbs +++ b/functions/view/publisher-a/creative-rotation.hbs @@ -13,7 +13,7 @@

Shared storage - Creative rotation demo

- + {{> creativeRotationDemoControls}}

Description

@@ -55,6 +55,7 @@

+ diff --git a/functions/view/publisher-b/creative-rotation.hbs b/functions/view/publisher-b/creative-rotation.hbs index 4908500..249ed6b 100644 --- a/functions/view/publisher-b/creative-rotation.hbs +++ b/functions/view/publisher-b/creative-rotation.hbs @@ -13,7 +13,7 @@

Shared storage - Creative rotation demo

- + {{> creativeRotationDemoControls}}

Description

@@ -55,6 +55,7 @@

+ diff --git a/sites/content-producer/url-selection/creative-rotation-worklet.js b/sites/content-producer/url-selection/creative-rotation-worklet.js index d276d9c..2bb9ef1 100644 --- a/sites/content-producer/url-selection/creative-rotation-worklet.js +++ b/sites/content-producer/url-selection/creative-rotation-worklet.js @@ -16,6 +16,9 @@ class SelectURLOperation { async run(urls, data) { + // Initially set the storage to sequential mode for the demo + await SelectURLOperation.seedStorage(); + // Read the rotation mode from Shared Storage const rotationMode = await sharedStorage.get('creative-rotation-mode'); @@ -77,7 +80,25 @@ class SelectURLOperation { console.log(JSON.stringify({ index, randomNumber, rotationMode })); return index; } + + // Set the mode to sequential and set the starting index to 0. + static async seedStorage() { + await sharedStorage.set('creative-rotation-mode', 'sequential', { + ignoreIfPresent: true, + }); + + await sharedStorage.set('creative-rotation-index', 0, { + ignoreIfPresent: true, + }); + } +} + +class SetRotationModeOperation { + async run({ rotationMode }) { + await sharedStorage.set('creative-rotation-mode', rotationMode); + } } // Register the operation as 'creative-rotation' register('creative-rotation', SelectURLOperation); +register('set-rotation-mode', SetRotationModeOperation); diff --git a/sites/content-producer/url-selection/creative-rotation.html b/sites/content-producer/url-selection/creative-rotation.html deleted file mode 100644 index 0dcfd77..0000000 --- a/sites/content-producer/url-selection/creative-rotation.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - Shared storage demo - - - - - - - - - - - - -
-
Demo control
-
- - - -
-
- - diff --git a/sites/content-producer/url-selection/creative-rotation.js b/sites/content-producer/url-selection/creative-rotation.js index 845d90d..5f0db96 100644 --- a/sites/content-producer/url-selection/creative-rotation.js +++ b/sites/content-producer/url-selection/creative-rotation.js @@ -16,41 +16,43 @@ // For demo purposes. The hostname is used to determine the usage of // development localhost URL vs production URL -const contentProducerUrl = window.location.host; +const contentProducerUrl = window.getContentProducerUrl(); // Ad confg with the URL of the ad, a probability weight for rotation, and the clickthrough rate. const DEMO_AD_CONFIG = [ { - url: `https://${contentProducerUrl}/ads/ad-1.html`, + url: `${contentProducerUrl}/ads/ad-1.html`, weight: 0.7, }, { - url: `https://${contentProducerUrl}/ads/ad-2.html`, + url: `${contentProducerUrl}/ads/ad-2.html`, weight: 0.2, }, { - url: `https://${contentProducerUrl}/ads/ad-3.html`, + url: `${contentProducerUrl}/ads/ad-3.html`, weight: 0.1, }, ]; -// Set the mode to sequential and set the starting index to 0. -async function seedStorage() { - await window.sharedStorage.set('creative-rotation-mode', 'sequential', { - ignoreIfPresent: true, - }); +async function setRotationMode(rotationMode) { + // Load the worklet module + const creativeRotationWorklet = await window.sharedStorage.createWorklet( + `${contentProducerUrl}/url-selection/creative-rotation-worklet.js`, + { dataOrigin: 'script-origin' } + ); - await window.sharedStorage.set('creative-rotation-index', 0, { - ignoreIfPresent: true, + await creativeRotationWorklet.run('set-rotation-mode', { + data: { rotationMode } }); + console.log(`creative rotation mode set to ${rotationMode}`); } async function injectAd() { // Load the worklet module - await window.sharedStorage.worklet.addModule('creative-rotation-worklet.js'); - - // Initially set the storage to sequential mode for the demo - seedStorage(); + const creativeRotationWorklet = await window.sharedStorage.createWorklet( + `${contentProducerUrl}/url-selection/creative-rotation-worklet.js`, + { dataOrigin: 'script-origin' } + ); const urls = DEMO_AD_CONFIG.map(({ url }) => ({ url })); @@ -58,7 +60,7 @@ async function injectAd() { const resolveToConfig = typeof window.FencedFrameConfig !== 'undefined'; // Run the URL selection operation to determine the next ad that should be rendered - const selectedUrl = await window.sharedStorage.selectURL('creative-rotation', urls, { + const selectedUrl = await creativeRotationWorklet.selectURL('creative-rotation', urls, { data: DEMO_AD_CONFIG, resolveToConfig }); diff --git a/sites/publisher-a/index.css b/sites/publisher-a/index.css index 181a4a7..5bdb461 100644 --- a/sites/publisher-a/index.css +++ b/sites/publisher-a/index.css @@ -105,3 +105,51 @@ card { background-color: var(--orange-9); } } + +.demo__controls-section { + width: 300px; +} +#ad-slot { + height: 250px; + border: none; +} + +#button-slot { + height: 100px; + border: none; +} + +.demo__card, +.demo__controls { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--size-2); + background: var(--surface-3); + border: 1px solid var(--surface-1); + padding: var(--size-3); + margin: var(--size-3) 0; + border-radius: var(--radius-3); + box-shadow: var(--shadow-2); + margin-top: 0; +} + +.demo__controls h5 { + margin-bottom: var(--size-2); +} + +.demo__buttons-container { + display: flex; + flex-direction: column; + width: fit-content; +} + +.demo__button { + zoom: 90%; + /* max-width: var(--size-13); */ + --_bg: linear-gradient(var(--indigo-5), var(--indigo-7)); + --_border: var(--indigo-6); + --_text: var(--indigo-0); + --_ink-shadow: 0 1px 0 var(--indigo-9); + margin: 5px; +} diff --git a/sites/publisher-b/index.css b/sites/publisher-b/index.css index 6ef5157..ce7a9f5 100644 --- a/sites/publisher-b/index.css +++ b/sites/publisher-b/index.css @@ -101,3 +101,52 @@ card { background-color: var(--orange-9); } } + +.demo__controls-section { + width: 300px; +} + +#ad-slot { + height: 250px; + border: none; +} + +#button-slot { + height: 100px; + border: none; +} + +.demo__card, +.demo__controls { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--size-2); + background: var(--surface-3); + border: 1px solid var(--surface-1); + padding: var(--size-3); + margin: var(--size-3) 0; + border-radius: var(--radius-3); + box-shadow: var(--shadow-2); + margin-top: 0; +} + +.demo__controls h5 { + margin-bottom: var(--size-2); +} + +.demo__buttons-container { + display: flex; + flex-direction: column; + width: fit-content; +} + +.demo__button { + zoom: 90%; + /* max-width: var(--size-13); */ + --_bg: linear-gradient(var(--indigo-5), var(--indigo-7)); + --_border: var(--indigo-6); + --_text: var(--indigo-0); + --_ink-shadow: 0 1px 0 var(--indigo-9); + margin: 5px; +}