Problem/Motivation

Steps to reproduce:

  • Checkout beta 12
  • Install
  • Checkout HEAD
  • Hit update.php directly
  • Problem: JS doesn't work, as its still aggregated, see
    js_QM6eTWWfVdmRmLKWmEL6T9u6dxQmFW3TjOahudJ9S54.js:669 Uncaught ReferenceError: drupalSettings is not defined

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dawehner created an issue. See original summary.

plach’s picture

I'm not sure the problem is aggregation. I tried disabling it and I got the same problem. The whole theme seems to be broken in that case.

catch’s picture

Issue tags: +D8 upgrade path, +beta target
catch’s picture

dawehner’s picture

FileSize
2.14 KB

Well yeah the reason is that again ...

Steps I did

* Disabled aggregation
* Disabled assert caching
* But we still don't render core/drupalSettings before active-link.js

    <script type="application/json" data-drupal-selector="drupal-settings-json">{"path":{"baseUrl":"\/update.php\/","scriptPath":null,"pathPrefix":"","currentPath":"update.php\/selection","currentPathIsAdmin":false,"isFront":false,"currentLanguage":"en"},"pluralDelimiter":"\u0003","user":{"uid":"1","permissionsHash":"fae6b6b48a8f68d08ae466382401a6eea3b1f4e044e04ed76b0c427bd45a7b69"}}</script>
<script src="http://d8.dev/core/assets/vendor/domready/ready.min.js?v=1.0.8"></script>

<!--[if lte IE 9]>
<script src="http://d8.dev/core/assets/vendor/classList/classList.min.js?v=2014-12-13"></script>
<![endif]-->
<script src="http://d8.dev/core/assets/vendor/jquery/jquery.min.js?v=2.1.4"></script>
<script src="http://d8.dev/core/assets/vendor/jquery-once/jquery.once.min.js?v=2.0.2"></script>
<script src="http://d8.dev/core/misc/drupal.js?v=8.0.0-beta12"></script>
<script src="http://d8.dev/core/misc/active-link.js?v=8.0.0-beta12"></script>
<script src="http://d8.dev/core/misc/debounce.js?v=8.0.0-beta12"></script>
<script src="http://d8.dev/core/assets/vendor/jquery.cookie/jquery.cookie.min.js?v=1.4.1"></script>
<script src="http://d8.dev/core/misc/form.js?v=8.0.0-beta12"></script>
<script src="http://d8.dev/core/misc/details-aria.js?v=8.0.0-beta12"></script>
<script src="http://d8.dev/core/misc/collapse.js?v=8.0.0-beta12"></script>
<script src="http://d8.dev/core/themes/seven/js/mobile.install.js?v=8.0.0-beta12"></script>

 

So yeah cache.discovery is the issue

Wim Leers’s picture

But we still don't render core/drupalSettings before active-link.js

I'd say "then dependencies must be wrong", but this has been the library definition since Feb 2014:

drupal.active-link:
  version: VERSION
  js:
    misc/active-link.js: {}
  dependencies:
    - core/drupal
    - core/drupalSettings
    - core/classList
jhedstrom’s picture

The file missing from the list of js files in #5 is core/misc/drupalSettingsLoader.js, which was introduced in #2510104: Convert drupalSettings from JavaScript to JSON, to allow for CSP in the future. The fix may be to just clear css/js cache (or disable completely) on the update.php route.

dawehner’s picture

Status: Active » Needs review
FileSize
637 bytes

Yeah we went with discussing about blackholes to this approach.

Wim Leers’s picture

<WimLeers> dawehner: the downside is that the rest of the site, with potentially thousands of users hitting the maintenance page, they will continuously rebuild those caches. The beauty of selective amnesia/partial blackhole is that it ONLY affects update.php

Wim Leers’s picture

So dawehner is concerned that simply emptying all cache backends will cause nasty side-effects. I agree with his concern/caution.

But… to really solve all manifestations of this problem, shouldn't we actually be ensuring we never use any cached data in update.php? Aren't there other parts of the update.php responses that in part or full come from some cache?

Shouldn't we decorate all caches during update.php, and then invalidate all caches after update.php? i.e. shouldn't we make update.php map the cache_factory service to \Drupal\Core\Cache\NullBackendFactory?

dawehner’s picture

Just to be clear, this patch certainly just fixes update.php, so we are kinda more save

Shouldn't we decorate all caches during update.php, and then invalidate all caches after update.php? i.e. shouldn't we make update.php map the cache_factory service to \Drupal\Core\Cache\NullBackendFactory

We invalidate all caches after update.php already ... but well, don't use any cache is highly problematic given that this could invoke more subsystems again. Just imagine the entity type definition as we deal with maybe users somewhere.

Wim Leers’s picture

don't use any cache is highly problematic given that this could invoke more subsystems again

… if that's problematic, then any site can run into that if those caches just happen to be empty already.

dawehner’s picture

… if that's problematic, then any site can run into that if those caches just happen to be empty already.

Well, right, I would just try for now to remove the common case surface area. Just imagine if in the middle of one to the next batch we clear the cache. I just fear that this would make the system more fragile than before

Wim Leers’s picture

Status: Needs review » Reviewed & tested by the community

Just imagine if in the middle of one to the next batch we clear the cache. I just fear that this would make the system more fragile than before

Fair.

catch’s picture

Status: Reviewed & tested by the community » Needs work

We could decorate caches to return FALSE from get and getMultiple() all the time - that way every update run gets the 'worst case' of caches being empty.

Caches will only get populated if something accesses them - which is either update.php itself or a specific update.

This seems less risky than a rebuild, but reducing surface area of update.php as we go along (so it doesn't load the cache items at all) will improve things. Then as discussed in irc we could try to hard-code the libraries update.php uses so it doesn't rely on library discovery at all.

I think that can probably all happen in a follow-up, patch needs to explain the fact that new code can make the library cache invalid and that update.php is relying on the new definitions though, 'make it work' doesn't quite get that across :P

catch’s picture

Also I think we could add a regression test for this:

- database that does not have aggregation on
- visit update.php
- confirm the drupal settings js file is in the markup.

Wim Leers’s picture

Issue tags: +Needs tests

And dawehner pointed out that it's in fact possible to test update.php.

dawehner’s picture

We could decorate caches to return FALSE from get and getMultiple() all the time - that way every update run gets the 'worst case' of caches being empty.

Well, while I think we should explore that, its tricky, because

a) We want the cache entries have the most up to date information
b) We want the cache rebuild entries not to call out to the entirety of the world, which I fear could actually happen easily.
Just imagine ECK having to rely on something in order to rebuild the entity type definitions. This would increase the surface area A LOT, so I'm not entirely sure its the right thing to do.
Especially for this issue we want to first fix the JS side of things. Having to press f5 multiple times (its amazing that it though works) is kinda of a nogo.

Xano’s picture

Status: Needs work » Needs review
FileSize
2.39 KB

@lauriii and I were hacking on this a bit. This patch simply disables caching for the asset resolver during update.php runs.

larowlan’s picture

Assigned: Unassigned » larowlan

working on a test

larowlan’s picture

Something like so for the test @catch?

The last submitted patch, 19: drupal_2560521_18.patch, failed testing.

jhedstrom’s picture

My understanding of the issue is that sites which have library_info cached don't pick up the new javascript file. If we manually populate that particular cache during the database load in the test, this would mimic such a site (all of the db dump files have empty cache tables).

Status: Needs review » Needs work

The last submitted patch, 21: javascript-2560521.fail_.patch, failed testing.

jhedstrom’s picture

However, that test fails, so it may be good as-is.

lauriii’s picture

Status: Needs work » Needs review
FileSize
5.59 KB

Fixed the exceptions and combined the patches.

Status: Needs review » Needs work

The last submitted patch, 26: javascript_does_not-2560521-26.patch, failed testing.

larowlan’s picture

Assigned: Unassigned » larowlan
larowlan’s picture

Assigned: larowlan » Unassigned

Yeah so the test is dud, as per #23
The doPreUpdateTests needs to be after the ->continue link click.

dawehner’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
FileSize
5.81 KB
6.69 KB

Fixed a couple of things:

  • Removed the global hack
  • Ensured that library.discovery.collector also gets the NULL backend, I have seen that as a problem of my previous debug attemps
  • Moved the service provider from /Updater to /Update which is the right namespace
  • Updated the tests to no longer disable aggregation. We want to ensure the case in which actual sites run into, which is having aggregation at least enabled in the settings.
    Just to be sure, this caused that no JS is loaded for that initial page, ... so yeah I changed DBUpdateController to always include it. I think this should be fne.

On the longrun though we really maybe want to implement our cache backend decorator

larowlan’s picture

One minor observation, but other than that I think this is RTBC

+++ b/core/lib/Drupal/Core/Update/UpdaterServiceProvider.php
@@ -0,0 +1,42 @@
+    $definition->replaceArgument(5, $argument);
...
+    $definition->replaceArgument(0, $argument);

Should we use constants here instead of ints? less magic, self documenting etc

dawehner’s picture

Should we use constants here instead of ints? less magic, self documenting etc

Well, unlike other cases where we use ints for the fact that PHP does not have ENUMs here we are clearly using ints as ints.

dawehner’s picture

One quick additional rename.

Status: Needs review » Needs work

The last submitted patch, 33: 2560521-33.patch, failed testing.

larowlan’s picture

Well, unlike other cases where we use ints for the fact that PHP does not have ENUMs here we are clearly using ints as ints.

True - I think this is ready then

dawehner’s picture

Status: Needs work » Needs review
FileSize
5.68 KB

Quick reroll

dawehner’s picture

Tried to do an actual update and this problem is fixed by that particular patch.

larowlan’s picture

Status: Needs review » Reviewed & tested by the community
Wim Leers’s picture

Status: Reviewed & tested by the community » Needs review
  1. +++ b/core/lib/Drupal/Core/Update/UpdateKernel.php
    @@ -29,6 +29,33 @@ class UpdateKernel extends DrupalKernel {
    +    // Always force a container rebuild.
    

    It'd be great if this said why.

  2. +++ b/core/lib/Drupal/Core/Update/UpdateKernel.php
    @@ -29,6 +29,33 @@ class UpdateKernel extends DrupalKernel {
    +    // Don't save this particular container to cache.
    

    I guess this is why: to build a fresh container for every request to update.php. An @see to this in point 1 would be great.

  3. +++ b/core/lib/Drupal/Core/Update/UpdateServiceProvider.php
    @@ -0,0 +1,42 @@
    +    $definition = $container->getDefinition('asset.resolver');
    +    $argument = new Reference('cache.null');
    +    $definition->replaceArgument(5, $argument);
    +
    +    $definition = $container->getDefinition('library.discovery.collector');
    +    $argument = new Reference('cache.null');
    +    $definition->replaceArgument(0, $argument);
    

    … so that these overrides always take effect.

    An @see to this in point 1 would be great.

  4. +++ b/core/modules/system/src/Controller/DbUpdateController.php
    @@ -186,6 +186,9 @@ public function handle($op, Request $request) {
    +    // Ensure that at least the drupalSettings js is loaded.
    +    $output['#attached']['library'][] = 'core/drupalSettings';
    

    Why? This should not be necessary.

dawehner’s picture

Why? This should not be necessary.

Let me quickly explain that ... as you remember quite hard we don't have any JS enabled for anonymous users by default ... so meh, the test fails because we don't add any JS (beside the HML5 shim). Not sure exactly what to do though. The JS file is just added in case you have logged in first, but for running /update.php with update_free_access the test doesn't work without it.

dawehner’s picture

There we go.

larowlan’s picture

+++ b/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
@@ -275,11 +275,12 @@ protected function replaceUser1() {
+    //update.php environment before running update.php can override this
+    //method and implement their required tests.

can be fixed on commit

Wim Leers’s picture

Status: Needs review » Reviewed & tested by the community

Much better.

plach’s picture

This looks great, only a couple of nitpicks :)

  1. +++ b/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
    @@ -273,4 +274,13 @@ protected function replaceUser1() {
    +    // No-op. Tests wishing to do test the selection page or the general
    +    //update.php environment before running update.php can override this
    +    //method and implement their required tests.
    

    Missing spaces after the double slashes.

  2. +++ b/core/modules/system/src/Tests/Update/UpdatePathTestJavaScriptTest.php
    @@ -0,0 +1,57 @@
    +        $found = TRUE;
    

    Can we add a break here? :)

plach’s picture

Fixing my own nits. Btw, I manually tested this and it worked great!

lauriii’s picture

Changes look good!

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

It's nice to see really good test coverage for this. Thanks everyone. Committed ffeb4a7 and pushed to 8.0.x. Thanks!

  • alexpott committed ffeb4a7 on 8.0.x
    Issue #2560521 by dawehner, plach, larowlan, lauriii, Xano, Wim Leers,...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.