- Issue created by @ajeet_kumar
- 🇪🇪Estonia pjotr.savitski
The assumption about this having something to do with jQuery is incorrect as H5P uses custom versions of everything, at least within internal iframes.
This is the issue of createCachedPublicFiles method of the H5PDrupal class.
This line will throw an error as the second argument is required (at least with PHP 8.1):
$cachedAsset = $optimizer->optimize($assets);
The logic tells that it should be changed to:
$cachedAsset = $optimizer->optimize($assets, []);
Which fixes the exception being thrown, but the end result is not what it is expected to be. This line will fail as there is no data key or it is empty, instead items are set and those point to the original files provided:
return array_map(function($publicUrl){ return \Drupal::service('file_url_generator')->generateAbsoluteString($publicUrl); }, array_column($cachedAsset, 'data'));
I'm not sure about the inner workings of the new JsCollectionOptimizerLazy class (or the one before that) and why this new lazy approach and creation of those files at the first request fails, but this is what is causing the issue. I've tried proving a library name and that gets the expected data key returned, but the files themselves are never created and the logger reports The libraries to include are encoded incorrectly.
My guess is that something has changed and the data provided for optimization is formatted incorrectly, though I see no documentation on how that should be formatted or what changed with the move to the new lazy approach.
The only really quick fix is to always disregard the JS and CSS preprocess configuration option, but that makes the whole optimization step meaningless. Just change the aggregateAssets method from this (this still keeps aggregation functional for everything else but the H5P):
$jsAssetConfig = ['preprocess' => $systemPerformance->get('js.preprocess')]; $cssAssetConfig = ['preprocess' => $systemPerformance->get('css.preprocess'), 'media' => 'css'];
to this:
$jsAssetConfig = ['preprocess' => FALSE]; $cssAssetConfig = ['preprocess' => FALSE, 'media' => 'css'];
- 🇪🇪Estonia pjotr.savitski
I've checked the code and it seems that individual files are not really processed in any way, at least not with the type of file, unless at least one library is provided. This more or less means that the whole optimization code is useless, unless libraries are used, which is not really applicable in this case.
Not sure is this is the new internal logic or not, but providing any library prevents the aggregated file from being created. The other issue is that there is no cache busting logic present like it used to be with the previous approach and recreation of the combined file using fresh versions of the resources each time new cache file is generated.
- 🇪🇪Estonia pjotr.savitski
It seems that a few modifications can help with getting the old way of dealing with assets running again. It requires redefining and using old versions of collection optimizer services. A few modifications to the current code would also be required as there are some changes in how new approach works, including changes to the dependencies (mostly affects the CSS, at least it was like that for me).
First, a h5p.services.yml file needs to be added, having copies of services from Drupal version 9.5 with a legacy suffix:
services: asset.css.collection_optimizer_legacy: class: Drupal\Core\Asset\CssCollectionOptimizer arguments: [ '@asset.css.collection_grouper', '@asset.css.optimizer', '@asset.css.dumper', '@state', '@file_system' ] asset.js.collection_optimizer_legacy: class: Drupal\Core\Asset\JsCollectionOptimizer arguments: [ '@asset.js.collection_grouper', '@asset.js.optimizer', '@asset.js.dumper', '@state', '@file_system' ]
Secondyl H5PDrupal.php file has to be patched with changes to aggregatedAssets and createCachedPublicFiles methods:
/** * Aggregate assets. * * @param array $scriptAssets * JavaScript assets. * @param array $styleAssets * Stylesheet assets. */ public static function aggregatedAssets($scriptAssets, $styleAssets) { $jsOptimizer = \Drupal::service('asset.js.collection_optimizer_legacy'); // NB! Different service being used $cssOptimizer = \Drupal::service('asset.css.collection_optimizer_legacy'); // NB! Different service being used $systemPerformance = \Drupal::config('system.performance'); $jsAssetConfig = ['preprocess' => $systemPerformance->get('js.preprocess')]; $cssAssetConfig = ['preprocess' => $systemPerformance->get('css.preprocess'), 'media' => 'all']; // NB! Value of "media" changed from "css" to "all" $assets = ['scripts' => [], 'styles' => []]; foreach ($scriptAssets as $jsFiles) { $assets['scripts'][] = self::createCachedPublicFiles($jsFiles, $jsOptimizer, $jsAssetConfig); } foreach ($styleAssets as $cssFiles) { $assets['styles'][] = self::createCachedPublicFiles($cssFiles, $cssOptimizer, $cssAssetConfig); } return $assets; } /** * Combines a set of files to a cached version, that is public available * * @param string[] $filePaths * @param AssetCollectionOptimizerInterface $optimizer * @param array $assetConfig * * @return string[] */ private static function createCachedPublicFiles(array $filePaths, $optimizer, $assetConfig) { $assets = []; $defaultAssetConfig = [ 'type' => 'file', 'group' => 'h5p', 'cache' => TRUE, 'attributes' => [], 'version' => NULL, 'browsers' => [], 'license' => FALSE, // NB! Missing license key added to prevent missing key notices ]; foreach ($filePaths as $index => $path) { $path = explode('?', $path)[0]; $assets[$path] = [ 'weight' => count($filePaths) - $index, 'data' => $path, ] + $assetConfig + $defaultAssetConfig; } $cachedAsset = $optimizer->optimize($assets, []); return array_map(function($publicUrl){ return \Drupal::service('file_url_generator')->generateAbsoluteString($publicUrl); }, array_column($cachedAsset, 'data')); }
This seems to be making everything work as expected, at least my testing material looks the way it used to and has no JS errors. It might be able to work until Drupal version 11.
The best approach would be to use the new logic and somehow dynamically define a library for each of the material, thus making the new lazy approach work as expected. One way would be to pass a library called h5p-content- and then dynamically define that library with the hook if the current context is one of the controllers for JS and CSS asset optimizers and the query string has some custom keys present. There might be a better approach, but this is what has come to my mind. Another possibility would be to mimic the new lazy approach and have a custom controllers that create optimized asset files or serve already existing ones.
- 🇪🇪Estonia pjotr.savitski
Here is the patch that uses old versions of JS and CSS optimisation services with a few additional fixes for related problems of missing keys and warnings.
- Status changed to RTBC
over 1 year ago 11:11am 29 August 2023 - 🇺🇦Ukraine o_timoshchuk
+1 RTBC I applied patch #6 with the Drupal 10 compatibility patch. It is functioning correctly.
- 🇮🇳India StanleyFernandes Goa
Patch #6 failed with the latest D10 compatibility patch i.e
https://www.drupal.org/project/h5p/issues/3329297#comment-15218847 📌 Automated Drupal 10 compatibility fixes Needs reviewWith the help of patch #6 created a new patch.
Tested on Drupal 10.1.5 working as expected. - 🇫🇮Finland anaconda777
This #8 patch does not apply with the latest dev.
And with 2.0.0-alpha3 I am not able to get it working with D10 properly, cos I dont know which patches it is missinge compared to dev? - 🇬🇧United Kingdom SirClickALot Somerset
I can confirm too that, when using the latest dev version
"drupal/h5p": "2.0.x-dev@dev"
, that most, H5P creations DO NOT render when JavaScript aggregation is active.By contrast to @Anaconda777 → 's comment, mine DO all seem to work with CSS aggregation active; it is only the JavaScript aggregation.
- 🇩🇪Germany ammaletu Bonn, Germany
Against the current dev version patch #6 almost works. The changes in src/H5PDrupal/H5PDrupal.php in line 88, 89 and 94 don't apply, I think. After I changed these lines manually, displaying the H5P content worked again. Patch #8 contains a lot of the changes to get H5P to work with Drupal 10, which are in some way already part of the dev version, soon to be tagged as alpha4.
- Status changed to Needs work
about 1 year ago 4:34pm 7 November 2023 - Status changed to Needs review
about 1 year ago 8:56pm 7 November 2023 - 🇩🇰Denmark googletorp
Rerolled the patch from #8 by manual comparing what was required.
- 🇫🇮Finland anaconda777
@googletrop Thanks, that patch applies but now when viewing H5P content I get wsod and this:
Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: You have requested a non-existent service "asset.js.collection_optimizer_legacy". Did you mean one of these: "asset.css.collection_optimizer", "asset.js.collection_optimizer"? i Drupal\Component\DependencyInjection\Container->get() (rad 157 av /var/www/html/drupal10/web/core/lib/Drupal/Component/DependencyInjection/Container.php).
I have Drupal 10.1.6
Without this patch there is not error message, it just does not show the H5P content when js aggregation is on
- Status changed to Needs work
about 1 year ago 10:42am 9 November 2023 - 🇬🇧United Kingdom catch
The reroll is missing the two legacy services added in the previous patches.
- 🇺🇸United States SocialNicheGuru
Now that 📌 Automated Drupal 10 compatibility fixes Needs review has landed, the patch #6 should be re-rolled.
- Status changed to Needs review
about 1 year ago 5:39pm 9 November 2023 - Status changed to Fixed
about 1 year ago 4:37pm 10 November 2023 - 🇬🇧United Kingdom catch
Committed/pushed to 2.0.x so that this change is available with the dev release. Thanks!
- Status changed to Needs work
about 1 year ago 10:40pm 10 November 2023 - 🇬🇧United Kingdom catch
Actually no this isn't good either, it makes the H5P module only compatible with Drupal 10.1, not 9.5 or 10.0.x, because the legacy classes don't exist in those versions. Also using the legacy services is a stopgap anyway.
Two options:
1. Define the services in a service provider instead of YAML so it can check for the class existence first. Then in the actual logic, check the Drupal core version and only use the legacy services if we're on 10.1.x or higher. This adds more complexity and is still a stopgap.
2. Refactor this entirely to either not aggregate, or to not use the the Drupal core aggregation API at all and just concatenate the files together instead - or at least use more targeted bits of the API.
- 🇫🇮Finland anaconda777
can confirm, patch #17 works with D10.1.6 and latest H5P dev
Thanks / kiitos
- Status changed to Fixed
about 1 year ago 12:00pm 14 November 2023 - 🇬🇧United Kingdom catch
I was wrong in #20, because the 'legacy' classes are just the old one shipped with 9.5/10.0, then this approach works fine as a stopgap and should be compatible with both 9.5/10.0/10.1.
I opened 📌 Refactor asset aggregation to avoid using deprecated asset optimization classes Active to refactor things in time for Drupal 11 compatibility though. Moving this issue back to fixed.
Automatically closed - issue fixed for 2 weeks with no activity.
- Status changed to Fixed
5 months ago 9:01pm 26 July 2024 - 🇨🇦Canada maursilveira Windsor, ON
Hello,
I'm experiencing this issue even after applying the patch #17. I'm getting a
Uncaught TypeError: H5P.EventDispatcher is undefined
, most likely coming from one of the content libraries located in the public folder (/sites/default/files/h5p/libraries).Any ideas or recommendations? Any help is much appreciated!
Thank you!
- 🇨🇦Canada maursilveira Windsor, ON
Hello,
One thing I noticed that I believe can be the cause of the error I'm having is that the content libraries, located in /sites/default/files/h5p/libraries, are being loaded before the main libraries
h5p.js
andjquery.js
, located in the vendor directory in the module folder, ando also before the fileh5p-event-dispatcher.js
, which I believe is where the aforementioned function is defined and constructed. Please see the attached screenshot.Shouldn't the main libraries be loaded before, in order to ensure all the H5P core functionality is properly defined? Is this an issue you have experienced before? Any recommendations on how to solve this?
Please let me know if this sounds to you a different issue, and I can open a new one.
Thank you!
- 🇨🇦Canada maursilveira Windsor, ON
For visibility, I opened a new task https://www.drupal.org/project/h5p/issues/3464434 🐛 Errors due to content libraries being loaded before main H5P libraries Active .
Thank you