I've encountered a race condition when using a lazy builder that renders an element with an attached script that includes dependencies.

In this case I'm using a library like this:

editor:
  version: "1.0.0"
  js:
    js/editor.js: {}
  dependencies:
    - core/ckeditor

The issue is that dynamically added scripts are loaded asynchronously by default (see async). As a result in my example above it is possible for editor.js to be processed before ckeditor.js despite them being added to the page in the correct order resulting in a JS error.

This issue can be mitigated by attaching the libraries used by the lazy builder to the page after the lazy builder element so that it does not need to be added when replacing the placeholder.

$output['form'] = $lazy_builder;
$output['#attached']['library'][] = 'my_module/editor';
return $output;

Proposed Resolution

This should be preventable by adding an async="false" to all script tags loaded through the Drupal AJAX api from libraries.

Steps to Reproduce

I was able to reproduce this issue with and without JS aggregation, however with aggregation it was necessary to force my 2 JS files to load simultaneously by adding 10-20 image requests at the top of the page. CKEditor is a useful example dependency because of it's 550KB filesize.

Comments

malcolm_p created an issue. See original summary.

Wim Leers’s picture

Thanks for reporting this! :)

  1. Isn't this a duplicate of #2903614: Race condition results in same CSS+JS being loaded twice: race between BigPipe's server-side dynamic asset loading and Quick Edit's client-side dynamic asset loading?
  2. If it isn't, could you transform your steps to reproduce to a test? That'd help me enormously :)
malcolm_p’s picture

It's actually not related to either big_pipe or quickedit, it also occurs using the AJAX api. The issue is that scripts added to a the page programmatically (ex AJAX api, big_pipe, quickedit) will be loaded asynchronously (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-async). So if we are loading 2 scripts, the second of which depends on the first, a race condition can occur where the 2nd script finishes loading before the 1st.

This is hard to reproduce consistently as it depends on the specific load time of the scripts and what else is being loaded on the page before these scripts. I'll try and work on a test to reproduce it more consistently though.

Wim Leers’s picture

Thanks for clarifying!

We have an issue for that too: #1988968: Drupal.ajax does not guarantee that "add new JS file to page" commands have finished before calling said JS. Can you confirm that that issue (which has lots of prior discussion!) indeed covers the same problem?

malcolm_p’s picture

Ah, interesting. Yes that's definitely related. Using a dependency manager will definitely be a more robust solution as well. I can't yet tell if the case of dependencies is currently handled though as I don't think dependency information is currently passed to the AddJsCommand.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Wim Leers’s picture

Status: Postponed (maintainer needs more info) » Closed (duplicate)