Populate companion preserved_js from runtime islands (+ fix silent JS loss in generated blocks)#273
Closed
chubes4 wants to merge 2 commits into
Closed
Populate companion preserved_js from runtime islands (+ fix silent JS loss in generated blocks)#273chubes4 wants to merge 2 commits into
chubes4 wants to merge 2 commits into
Conversation
Populate CompanionPluginPayload.preserved_js[] from the runtime-island feed so runtime-island JS rides the SSI companion plugin, scoped to the generated block that owns it. The island->generated-block association did not previously exist: runtime islands and generated custom blocks are produced from disjoint elements, and a generated block consumes its source subtree wholesale while stripping <script> bodies, so any behavior script inside a generated subtree was silently lost. Capture those scripts at the one sound association point — custom-block generation — recording each as a script runtime island tagged with the owning block's fully-qualified name via a generic `owner_block` field. RuntimeIslandPackageBuilder carries the field through product-neutrally; CompanionPluginPayload owns the SSI-named projection. The mapping is gated by preserve-vs-rebuild (#224): only disposition=preserve / js_handling=preserve_verbatim islands carry JS, and telemetry/droppable and external-unmaterialized scripts contribute nothing. Each entry emits content (verbatim JS), handle (handle_hint), and src (islands/<handle>.js). An island with a sound owner_block that matches a packaged block is scoped (block=ssi-<slug>/<name>); a free-standing island with no sound owner is surfaced in preserved_js_deferred[] with a reason rather than scoped by guess or dropped silently (the consumer drops unscoped entries). Replaces the "preserved_js stays empty" contract assertion with coverage that asserts a populated, correctly-scoped entry, the deferral path, and that telemetry JS is never carried. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Free-standing behavior islands (no generated-block owner) were parked in preserved_js_deferred with reason=no_generated_block_owner, deferring their verbatim JS to nowhere. Promote them to real site-wide preserved_js entries (scope='site', no `block` key, deterministic order from the package index) so the companion-plugin consumer enqueues them for the whole site. The block-scoped path (#488) is unchanged: owned islands keep their `block` key and carry no `scope`. The owner_block_not_packaged anomaly (a named owner block that did not ship) is still deferred rather than guessed into a site-wide scope. Telemetry/droppable and external-unmaterialized scripts still contribute nothing. RuntimeIslandPackageBuilder stays product-neutral; this projection lives in the product-named producer. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Author
|
Parking as superseded. End-to-end verification showed the companion-plugin / preserved-JS path is the wrong mechanism for interactivity: custom-block generation is structurally inert across all 72 website fixtures (0 generated — the generation gate at the html_unsupported_element tail is unreachable), and generated blocks strip <script>/on* via wp_kses_post anyway. The real interactive behavior is delivered deterministically by native conversion (core/navigation responsive overlay, core/details + core/accordion). Closing; branch retained for reference. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Populates
CompanionPluginPayload.preserved_js[]from runtime-island data so behavior JS embedded in generated custom blocks is carried into the SSI companion plugin (scoped per block), instead of being lost. The consumer already merged (SSI #496); this builds the producer half (#488).Notable: fixes a silent JS-loss bug
While building the island→block association (which did not exist — generated blocks and runtime islands came from disjoint elements, and
sanitizeHtmlStringstripped<script>bodies from generated content), I found inline behavior scripts inside generated custom blocks were being silently dropped. The fix mints the association at generation time.Change (
php-transformer)FallbackEmitter::maybeGenerateCustomBlock()now scans the generated subtree for runtime<script>s and records each as ascriptisland tagged with the owning block's FQN via a genericowner_blockfield (sharedscriptIslandMetadata()helper).RuntimeIslandPackageBuildercarriesowner_blockthrough (stays product-neutral).CompanionPluginPayload::preservedJs()projects islands →preserved_js, gated by Feature parity: explicit preserve-vs-rebuild decision per interactive region (verbatim JS only on verbatim markup) #224: onlydisposition=preserve+js_handling=preserve_verbatim, skipping telemetry/droppable. Per entry:content(verbatim JS),handle,src. Islands with a matchingowner_blockare scoped (block=ssi-<slug>/<name>); preserve-worthy islands with no sound owner go topreserved_js_deferred[]with areason— never scoped by guess, never silently dropped.Scope (honest)
reason: no_generated_block_owner), the #488 follow-up.content). Materialized external: carried.Verification
composer test+composer parity→ 144 fixtures green; new contract coverage asserts the populated scoped entry, the deferral path, and that telemetry JS never reaches the payload. Parity unaffected (only adds source-report data; serialized output unchanged).AI assistance