diff --git a/modules/refreshless_turbo/js/drupal_settings.js b/modules/refreshless_turbo/js/drupal_settings.js
index ae0bedb21d4e2e70f97e5acd0d764efc264e0358..27820af33053de213187055e06c59ebebcc9433a 100644
--- a/modules/refreshless_turbo/js/drupal_settings.js
+++ b/modules/refreshless_turbo/js/drupal_settings.js
@@ -7,6 +7,115 @@
    */
   class DrupalSettings {
 
+    /**
+     * Zero more Drupal settings JSON elements found in the DOM.
+     *
+     * @type {HTMLScriptElement[]}
+     */
+    #foundElements = [];
+
+    /**
+     * <script> element MutationObserver.
+     *
+     * @type {MutationObserver}
+     */
+    #scriptObserver;
+
+    constructor() {
+
+      /**
+       * Reference to the current instance.
+       *
+       * @type {DrupalSettings}
+       */
+      const that = this;
+
+      /**
+       * Reference to our #scriptObserverCallback private method.
+       *
+       * @type {Function}
+       */
+      const scriptObserverCallback = this.#scriptObserverCallback;
+
+      this.#scriptObserver = new MutationObserver(function(mutations) {
+        scriptObserverCallback.call(that, mutations);
+      });
+
+      /**
+       * Reference to our <script> element MutationObserver.
+       *
+       * @type {MutationObserver}
+       */
+      const scriptObserver = this.#scriptObserver;
+
+      document.documentElement.addEventListener('turbo:visit', function(event) {
+
+        // Reset the array of found script elements before starting the
+        // MutationObserver.
+        that.#foundElements = [];
+
+        // Start observing when a Turbo visit starts. This event is triggered
+        // before any changes are made to the DOM, including the <head>, so no
+        // new <script> elements will have been merged in yet.
+        //
+        // Also note that while this <script> element can be rendered by Drupal
+        // in the <body>, we explicitly move JavaScript to the <head> which also
+        // causes Drupal to render this <script> in the <head> as well, so we
+        // don't observe the <body>.
+        scriptObserver.observe(document.head, {
+          childList:  true,
+          // Important: do *not* use subtree: true as that will open up
+          // potential XSS exploits.
+          //
+          // @see core/misc/drupalSettingsLoader.js
+          //   Explains the need for XSS hardening.
+        });
+
+      });
+
+    };
+
+    /**
+     * <script> element MutationObserver callback.
+     *
+     * @param {MutationRecord} mutations
+     */
+    #scriptObserverCallback(mutations) {
+
+      for (let i = 0; i < mutations.length; i++) {
+
+        if (!('addedNodes' in mutations[i])) {
+          continue;
+        }
+
+        /**
+         * Nodes added as part of this mutation record.
+         *
+         * @type {NodeList}
+         */
+        const addedNodes = mutations[i].addedNodes;
+
+        for (let j = 0; j < addedNodes.length; j++) {
+
+          // Ignore any non-<script> element nodes or <script> elements not
+          // matching the selector for the drupalSettings JSON element.
+          if (
+            !(addedNodes[j] instanceof HTMLScriptElement) ||
+            addedNodes[j].getAttribute(
+              'data-drupal-selector',
+            ) !== 'drupal-settings-json'
+          ) {
+            continue;
+          }
+
+          this.#foundElements.push(addedNodes[j]);
+
+        }
+
+      }
+
+    };
+
     /**
      * Find the Drupal settings JSON element(s).
      *
@@ -39,13 +148,36 @@
      *   merging?
      *
      * @throws Error
-     *   If the settings element text could not be parsed into JSON.
+     *   If no new settings elements were added, if more than one element was
+     *   added, or if the new settings element text could not be parsed into
+     *   valid JSON.
      *
      * @return {Promise}
      *   A Promise that fulfills when drupalSettings has been updated.
      */
     update() {
 
+      // Stop observing for new <script> elements at this point because our job
+      // is done and we don't want to do unnecessary work, potentially
+      // affecting performance.
+      this.#scriptObserver.disconnect();
+
+      if (this.#foundElements.length === 0) {
+
+        console.error(Drupal.t(
+          'Could not find a Drupal settings script element added during the visit!',
+        ));
+
+      }
+
+      if (this.#foundElements.length > 1) {
+
+        console.error(Drupal.t(
+          'More than one Drupal settings script element seems to have been added!',
+        ), this.#foundElements);
+
+      }
+
       /**
        * One or more settings elements.
        *
@@ -53,10 +185,10 @@
        */
       const $elements = this.#findElements();
 
-      // Remove all but the last settings element.
-      $elements.not($elements.last()).remove();
+      // Remove all but the newest settings element.
+      $elements.not(this.#foundElements[0]).remove();
 
-      const $element = $elements.last();
+      const $element = $(this.#foundElements[0]);
 
       /**
        * New drupalSettings values or null if they can't be read.