Document BuildJsScope model and split tracking scripts - #601
Document BuildJsScope model and split tracking scripts#601promptless-for-oss wants to merge 2 commits into
Conversation
Documents the JS build scope model from mautic/mautic#16660: the BuildJsScope enum, BuildJsEvent::appendJsForScope()/acceptsScope(), the /mautic-essential.js and /mautic-tracking.js endpoints, client-side runtime globals, and the backward-compatibility impact on legacy appendJs() subscribers.
patrykgruszka
left a comment
There was a problem hiding this comment.
The scoped extension API and appendJs() migration guidance are useful additions. Before merging, the essential script’s capabilities should be narrowed to match the tested DWC fallback and form behavior, RUNTIME should not be presented as interchangeable with ESSENTIAL, and the readiness example should clearly state that mauticEssentialReady depends on the shipped consent-managed loader rather than the endpoint itself. With those reductions, this documentation will provide useful and accurate plugin guidance.
| Mautic generates its JavaScript under a scope model defined by ``Mautic\CoreBundle\Event\BuildJsScope``, an ``enum`` with three cases: | ||
|
|
||
| * ``RUNTIME`` - the anonymous bootstrap runtime that the other scopes depend on. It performs no tracking. | ||
| * ``ESSENTIAL`` - pre-consent features that need no identity, such as Dynamic Content rendering and Form injection. |
There was a problem hiding this comment.
The essential script's capabilities are narrower than "Dynamic Content rendering and Form injection." Essential-only mode preserves existing DWC fallback content without making a DWC request (tests/acceptance/MauticScriptSplitCest.php:190-221), and standalone forms are explicitly independent of all tracking scripts (app/bundles/FormBundle/Tests/Controller/PublicControllerFunctionalTest.php:18-38). Please describe this as DWC fallback handling and initialization of forms already embedded in fallback content. The same wording should be corrected in the endpoint table below.
|
|
||
| .. warning:: | ||
|
|
||
| A subscriber that only calls the legacy ``appendJs()`` now contributes ``TRACKING`` scoped code and is therefore excluded from ``/mautic-essential.js``. If a Plugin's code must run in the essential, pre-consent context, the subscriber must call ``appendJsForScope()`` with ``BuildJsScope::ESSENTIAL`` - or ``BuildJsScope::RUNTIME`` - and/or gate on ``acceptsScope()``. |
There was a problem hiding this comment.
RUNTIME should not be presented as interchangeable with ESSENTIAL for plugin features. The implementation uses RUNTIME only for the core bootstrap (CoreBundle/EventListener/BuildJsSubscriber.php:225-229) and classifies pre-consent DWC functionality as ESSENTIAL (DynamicContentBundle/EventListener/BuildJsSubscriber.php:118-132). Please remove the RUNTIME alternative, or limit it explicitly to bootstrap code required by other scopes.
| * ``MauticJS.requestWithCredentials`` - ``false`` by default in the essential or runtime build and ``true`` once tracking loads. | ||
| * ``mauticEssentialReady`` - a convention event, not something the generated runtime emits on its own. The authoritative readiness flag is ``MauticJS.runtimeReady``; the consent-managed essential loader snippet - the copy-paste snippet that loads ``/mautic-essential.js`` - dispatches ``mauticEssentialReady`` once ``MauticJS.runtimeReady === true`` by calling ``MauticJS.dispatchEvent('mauticEssentialReady')``. That helper builds a native ``CustomEvent`` and dispatches it on ``document``, so browser-side code following the split-script loader pattern can rely on it as a readiness hook and listen with ``document.addEventListener('mauticEssentialReady', ...)``. | ||
|
|
||
| Because the essential script may have finished loading before your code runs - in which case the event has already fired and a late listener would never run - guard on ``MauticJS.runtimeReady`` first and run immediately when it's already ``true``, falling back to the listener only when the runtime isn't ready yet. The shipped tracking add-on snippet follows this same dual path. This handles both cases safely: |
There was a problem hiding this comment.
This is safe only when the shipped consent-managed loader is used. /mautic-essential.js does not emit mauticEssentialReady; the Configuration-page loader snippet emits it from its load callback (PageBundle/Resources/views/FormTheme/Config/_config_trackingconfig_widget.html.twig:38-39). With a custom loader, this fallback listener may never run. Please make the condition explicit and tell custom loaders to use their script's load callback or dispatch an equivalent event.
…lt, clarify mauticEssentialReady loader dependency
|
Thanks for the detailed review, @patrykgruszka — all three points are addressed and pushed to PR #601:
All claims were re-verified against the PR #16660 source, and no new Vale issues were introduced. Ready for another look. |
patrykgruszka
left a comment
There was a problem hiding this comment.
Good to go from my perspective 👍
Updates the MauticJS tracking script developer page (
docs/mauticjs_api/tracking_script.rst) to document the JS build scope model introduced in mautic/mautic#16660 ("Split mtc.js into essential and tracking scripts", MTC-11100).New developer-facing surface documented:
Mautic\CoreBundle\Event\BuildJsScopeenum (RUNTIME,ESSENTIAL,TRACKING).BuildJsEvent::appendJsForScope($js, BuildJsScope $scope, $section = '')andacceptsScope(BuildJsScope $scope): bool, with plugin-style PHP subscriber examples.appendJs()now delegates toappendJsForScope()withBuildJsScope::TRACKING, plus a backward-compatibility warning (with argument-position migration guidance) thatappendJs()-only subscribers are excluded from/mautic-essential.js./mautic-essential.js,/mautic-tracking.js,/mtc.js) and their scope mappings.MauticJS.runtimeReady,trackingEnabled,requestWithCredentials) and themauticEssentialReadyevent, with a safe dual-path readiness guard example.Source PR: mautic/mautic#16660
Review response (@patrykgruszka)
Thanks for the review. All three comments applied:
ESSENTIALscope bullet and the/mautic-essential.jsendpoint-table row no longer say "Dynamic Content rendering and Form injection." They now describe it as preserving existing Dynamic Content fallback content without making a new request, and initializing Forms already embedded in that fallback content — matchingMauticScriptSplitCest.php(essential-only mode keeps the DWC fallback without a DWC request) andPublicControllerFunctionalTest.php(standalone forms are independent of all tracking scripts).RUNTIMEno longer offered as a plugin target — applied. Removed the "orBuildJsScope::RUNTIME" alternative from the migration warning; plugin pre-consent code is now directed toappendJsForScope()withBuildJsScope::ESSENTIAL(with optionalacceptsScope()gating).RUNTIMEremains described only as the core bootstrap the other scopes depend on, consistent with its single use inCoreBundle/EventListener/BuildJsSubscriber.php.mauticEssentialReadydependency on the shipped loader made explicit — applied. A dedicated paragraph after the readiness example now states the event is dispatched by the shipped consent-managed loader snippet, not by/mautic-essential.jsitself, and tells custom-loader users to run their code from their own script tag'sload/onloadcallback onceMauticJS.runtimeReady === true, or dispatch an equivalent event themselves.All edits applied verbatim to intent; the only deviations from the literal comment wording were style-driven (dropped the
(DWC)abbreviation in favor of "Dynamic Content" per the Mautic ValeFeatureListrule, replaced an "and/or" with an explicit required-action/optional-gate split, and moved the custom-loader caveat into its own paragraph after the code block for findability). No new Vale errors introduced; the one pre-existing baseline finding on unchanged content remains.This documentation update was prepared by Promptless.