Problem

JavaScript injected via the Asset Injector module does not reliably execute when BigPipe is enabled, particularly for authenticated users.

On a Drupal 11 site using the Olivero theme, JavaScript injected through Asset Injector worked correctly for anonymous users but failed for authenticated users. Core behaviors such as primary navigation dropdowns and custom menu positioning logic did not initialize. Disabling BigPipe immediately restored correct behavior.

This creates inconsistent behavior between anonymous and logged-in users and makes the issue difficult to diagnose.

Cause

Asset Injector injects JavaScript as raw <script> tags that execute once on initial page load. When BigPipe replaces page regions after load, injected scripts do not re-run and are not attached through Drupal’s behavior system (Drupal.attachBehaviors).

As a result:

  • Injected JS does not execute on BigPipe DOM replacements
  • Errors or timing issues can prevent later core behaviors from attaching
  • Behavior differs depending on cache state and user role

Expected behavior

JavaScript injected via Asset Injector should provide a BigPipe-safe option that:

  • Executes on initial page load
  • Re-executes when Drupal behaviors are attached (BigPipe, AJAX, Layout Builder)
  • Aligns with Drupal best practices

Proposed solution

Add an optional “Attach as Drupal behavior” mode for JavaScript injectors.

When enabled, injected JavaScript is wrapped as a Drupal behavior and executed via Drupal.attachBehaviors, ensuring compatibility with BigPipe and AJAX-driven DOM updates.

Patch plan

  1. Add a checkbox to JS injector configuration:

    “Attach as Drupal behavior (BigPipe/AJAX safe)”
  2. When enabled, wrap injected JavaScript in a Drupal behavior:
(function (Drupal, once) {
  Drupal.behaviors.assetInjector_&lt;ID&gt; = {
    attach(context) {
      once('assetInjector_&lt;ID&gt;', '&lt;scope&gt;', context).forEach(() =&gt; {
        // Injected JS
      });
    }
  };
})(Drupal, once);
  • <ID> is a unique identifier per injector
  • <scope> defaults to html or is user-configurable
  • once() prevents duplicate execution
  1. Automatically attach required dependencies when behavior mode is enabled:
    • core/drupal
    • core/once
  2. Preserve current behavior for existing injectors:
    • No automatic wrapping
    • No breaking changes
  3. Update documentation to explain:
    • BigPipe interaction
    • When to use behavior mode
    • Limitations of raw JS injection

Notes

This issue is reproducible on Drupal 11 with BigPipe enabled and affects authenticated users most consistently. The proposed solution aligns Asset Injector with Drupal’s established behavior system and avoids workarounds such as MutationObserver-based reinitialization.

Comments

w01f created an issue. See original summary.

w01f’s picture

Issue summary: View changes
w01f’s picture

Issue summary: View changes
pookmish’s picture

Status: Active » Closed (won't fix)

It is the expectation that if the JavaScript should use Drupal behaviors, those should be included in the JS injector code directly. This is the same way behaviors are used when adding JavaScript via a module or a theme.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.