Regression after #3500386: import map scope mismatch when auto-saved code component's JS sends a 307

Created on 25 February 2025, 3 months ago

Overview

@balint.kleri and I determined the root cause for code components failing to render in the XB preview since #3500386.

@larowlan, @effulgentsia and I decided last night that passing an $inPreview=TRUE flag ๐Ÿ“Œ Code Components should render with their auto-saved state(if any) when rendered in the XB UI Active should cause the auto-saved XB code components + asset libraries to be loaded.

But, if thereโ€™s no changes to the JS yet, then Drupal\experience_builder\Controller\ApiConfigAutoSaveControllers::getJs() returns a 307 pointing to the original, that causes the _import map scope to change from the draft/auto-saved component URL (component-url="/xb/api/autosaves/js/js_component/another") to the live/saved component URL (component-url="sites/default/files/astro-island/pKL_OwLDMlNxnBnBYIsn9BSu349KEpkBmq26qw_z8EQ.js").

And apparently this makes browsers not treat the originally requested URL as the scope, but the redirected URL.

Proposed resolution

This actually just points to a single innocent missing if-statement:

diff --git a/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php b/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php
index a81f561b0..8690a4ed3 100644
--- a/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php
+++ b/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php
@@ -119,6 +119,8 @@ final class JsComponent extends GeneratedFieldExplicitInputUxComponentSourceBase
         \assert($autoSave->data !== NULL);
         $component = $component->forAutoSavePreview($autoSave->data);
       }
+      // Do NOT consider this a preview if there's no auto-saved draft version.
+      $isPreview = FALSE;
     }
 
    $access = $component->access('view', return_as_object: TRUE);

(Which will ensure that the JS URL that is used is only the auto-save one if an auto-save actually exists. Same for the component's CSS asset library.)

โš ๏ธ Before arriving at that realization, I thought that the auto-save version of the code component was correctly being loaded. But I thought that \Drupal\experience_builder\Controller\ApiConfigAutoSaveControllers::getJs() was only returning a 307 because there wasn't a modification to the JS yet.
That was wrong. The above was the real bug.

A race condition remains AFAICT

But even then โ€ฆ I think there's still a race condition ๐Ÿ˜ฌ:
loading an XB preview, and there is an auto-save/draft version of a code component
then while I'm using XB, somebody else publishes the auto-save/draft version
so then with exactly the right timing, I could be fetching an XB preview using the auto-save draft version of the code component, but by the time the browser requests the component's JS, it's been published, which then again results in a 307, and would still trigger the original problem!

Solution for this: don't perform a 307 redirect, but instead just serve the stored JS. That way, we can guarantee there's no scope mismatch.

โš ๏ธ But โ€ฆ is the browser behavior here actually correct? ๐Ÿค” Maybe we're hitting a pretty esoteric edge case that browsers aren't handling correctly yet? (Because import maps are fairly new.)

User interface changes

None.

๐Ÿ› Bug report
Status

Active

Version

0.0

Component

Theme builder

Created by

๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Production build 0.71.5 2024