Postponed on #2453059: Set default render cache contexts: 'theme' + 'languages:' . LanguageInterface::TYPE_INTERFACE and #2888838: Optimize render caching.

Problem/Motivation

The language switcher block is currently not cacheable at all.

Proposed resolution

If we have a "language redirect" route, i.e. /language-redirect/<language code>, then e.g. "français" would link to /language-redirect/fr?destination=node/42. Then everything except the destination parameter could be cached globally. The destination parameter could be set in JS, just like contextual.js already does today:

    // Set the destination parameter on each of the contextual links.
    var destination = 'destination=' + Drupal.encodePath(drupalSettings.path.currentPath);
    $contextual.find('.contextual-links a').each(function () {
      var url = this.getAttribute('href');
      var glue = (url.indexOf('?') === -1) ? '?' : '&';
      this.setAttribute('href', url + glue + destination);
    });

To remain JS-less for anonymous users, we could still generate the entire block dynamically for anonymous users, because Drupal assumes that anonymous users get served cached pages anyway. This would then be in line with what we do for active link handling: we set the active class in PHP (on the server side) for anonymous users, but in JS (on the client side) for authenticated users.

That's the best of both worlds.

Remaining tasks

Blocked on #2107427: Regression: Language names should display in their native names in the language switcher block and #2335661: Outbound path & route processors must specify cacheability metadata and #2888838: Optimize render caching.

User interface changes

None.

API changes

None.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Wim Leers’s picture

Here's a very rough initial version that shows the direction this patch should take.

Gábor Hojtsy’s picture

Issue tags: +language-base

The block cache tags should also depend on language of the interface which was used to render the block.

Gábor Hojtsy’s picture

Gábor Hojtsy’s picture

To elaborate on that, thanks to #2107427: Regression: Language names should display in their native names in the language switcher block the switcher will be different per each language at least, so if the links are different, no help in doing it by JS, since the link text will also be different. Not much cached then, if you want to both inject the href and the text by JS. So is there a point in caching it NOT by language then? If we cache by language then it is the same as #2318437: Replace the hardcoded langcode key on blocks with the 'language' cache context AFAIS.

Berdir’s picture

@Gabor: The language texts will be the same everywhere, I don't see how that would be a problem? The problem with the URL is that it would be different on every page, that's what makes caching hard.

Gábor Hojtsy’s picture

Ha, right. I guess caching per language per page is not that much values / too many cache entries.

Wim Leers’s picture

Gábor Hojtsy’s picture

Status: Postponed » Needs work
Gábor Hojtsy’s picture

Issue tags: +sprint
kfritsche’s picture

Assigned: Unassigned » kfritsche
Wim Leers’s picture

Status: Needs work » Postponed

I strongly recommend against working on this. To fix this, we'll need outbound route processors and outbound path processors to return cacheability metadata. See #2335661: Outbound path & route processors must specify cacheability metadata.

You can probably already fix part of the problem, but definitely not the entire problem. At least not with full reliability/correctness.

kfritsche’s picture

Assigned: kfritsche » Unassigned
kfritsche’s picture

Posting at least to the point, what I did, till I read the comment, to not work on it ;)

It adds the Javascript part and the redirect URL, so the basic idea is working. Caching-Part I didn't touched.

Gábor Hojtsy’s picture

Issue tags: -sprint
Alan D.’s picture

Issue summary: View changes

Updated the summary as per comment #11

Wim Leers’s picture

Wim Leers’s picture

Gábor Hojtsy’s picture

Issue summary: View changes

Put that at the top of the summary.

Wim Leers’s picture

penyaskito’s picture

Assigned: Unassigned » penyaskito

I'm going to work on this @ drupaldevdays Montpellier

Wim Leers’s picture

Issue tags: +D8 Accelerate Dev Days

@penyaskito and I just discussed this. Thanks so much for taking this on btw, @penyaskito! :)

We concluded that the best approach was to apply the same strategy as the one we use for active links:

  • for the anonymous users, apply a #post_render_cache callback to insert the current path (see \Drupal\Core\Path\CurrentPathStack) in the redirect links
  • for the authenticated users, insert the destinations using JS
penyaskito’s picture

Status: Active » Needs review
FileSize
9.4 KB

Uploading work in progress:

* For anonymous users, we have a post_render_cache which performs a str_replace. Not sure if this is the best way.
* For authenticated users, we link to home page in the given language. If JS is enabled, we enhance this with the current path.

Contains a new IsAnonymousUserCacheContext.
We still lack to clear the caches if new language are added, and we need to handle the current language so it's considered the active one.

Sorry, no interdiff. Next steps would be clarifying those points, cleaning up and injecting services where needed.

Status: Needs review » Needs work

The last submitted patch, 22: 2232375-cache-block-switcher-22.patch, failed testing.

Wim Leers’s picture

This is definitely on the right track, great job! :)

A few nitpicks, but also a few actual bugs:

  1. +++ b/core/core.services.yml
    @@ -91,6 +91,11 @@ services:
    +  cache_context.user.is_anonymous:
    
    +++ b/core/modules/language/src/Plugin/Block/LanguageBlock.php
    @@ -99,21 +119,52 @@ public function build() {
    +      'user.is_anonymous'
    

    Oh, darn, sorry.We actually already have a cache context for this.

    See https://www.drupal.org/developing/api/8/cache/contexts.

    Instead of user.is_anonymous, you want to use the user.roles:anonymous cache context.

  2. +++ b/core/modules/language/src/Controller/LanguageController.php
    @@ -0,0 +1,33 @@
    +    $search_key_switch_link = 'data-language-switch-link-placeholder';
    +    $element['#markup'] = str_replace($search_key_switch_link, $context['path'], $element['#markup']);
    

    The use of str_replace() is fine.

    But the placeholder is not, because it's not dynamic/random. So if anybody writes a blog post about this functionality, for example, then any mention of 'data-language-switch-link-placeholder' would also be replaced :)

    Use drupal_render_cache_generate_placeholder()/RendererInterface::generateCachePlaceholder() to generate such a random placeholder.
    See \Drupal\comment\CommentPostRenderCache::renderForm() and \Drupal\comment\Plugin\Field\FieldFormatter\CommentDefaultFormatter::viewElements() for an example.

  3. +++ b/core/modules/language/src/Plugin/Block/LanguageBlock.php
    @@ -88,9 +101,16 @@ protected function blockAccess(AccountInterface $account) {
    +    if (\Drupal::currentUser()->isAnonymous()) {
    
    @@ -99,21 +119,52 @@ public function build() {
    +      if (\Drupal::currentUser()->isAuthenticated()) {
    

    You injected the current user service, but aren't using it yet :)

  4. +++ b/core/modules/language/src/Plugin/Block/LanguageBlock.php
    @@ -99,21 +119,52 @@ public function build() {
    +            'path' => \Drupal::routeMatch()
    +                ->getRouteName() ? Url::fromRouteMatch(\Drupal::routeMatch())
    +                ->getInternalPath() : '',
    +            'front' => \Drupal::service('path.matcher')->isFrontPage(),
    +            'language' => \Drupal::languageManager()
    +                ->getCurrentLanguage(LanguageInterface::TYPE_URL)->getId(),
    +            'query' => \Drupal::request()->query->all(),
    

    All of this information should be gathered in the #post_render_cache callback.

    Because we want to be able to cache this for all authenticated users, for use on any route. The #post_render_cache callback is executed on every request by an authenticated user. So we want the information for that request, not for the request that caused the initial version of the language switcher block to be generated.

  5. +++ b/core/modules/language/src/Plugin/Block/LanguageBlock.php
    @@ -99,21 +119,52 @@ public function build() {
    +    // The "Language switcher" block must be cached per language.
    ...
    +      'languages',
    

    Not per language, but per interface language. Since not very long ago, you can specify that. So not 'languages', but 'languages:' . LanguageInterface::TYPE_INTERFACE.

    See https://www.drupal.org/developing/api/8/cache/contexts.

  6. +++ b/core/modules/language/src/Plugin/Block/LanguageBlock.php
    @@ -99,21 +119,52 @@ public function build() {
    +    // @todo Ensure whenever language settings change, that appropriate cache
    +    //   tags are invalidated, that allows us to cache this block forever.
    

    We have an issue for that :) #2428837: Adding/updating interface translations should invalidate page & render caches, it's currently RTBC.

penyaskito’s picture

Thanks for reviewing!

1. Using that cache context now.
2. Now we generate the context placeholder dinamically. However, as it is parsed as an url we need to do some decoding magic. We need to clean that up in next iterations of the patch.
3. Used that, injected Render too.
4. Fixed that.
5. Actually I noticed that we can have different blocks per language negotiation method. Added the derivative id which contains the negotiation type.
6. Not only translations should invalidate this, but adding languages themselves.

Note:
I'm using \Drupal::routeMatch() instead of \Drupal::destination()->get() because destination comes with a prefix. We need the internal path. E.g (node/1, never /node/1 or /es/node/1). Maybe we need to figure out a better way.

We are still missing modifying existing tests, and we need to add the active class to the current language for the current negotiation this block instance cares about. As we use a redirect handler, the active-link won't work here unless we do something about it.

Status: Needs review » Needs work

The last submitted patch, 25: 2232375-cache-block-switcher-25.patch, failed testing.

Wim Leers’s picture

6. Good point!

While you're fixing those test failures, some additional feedback:

  1. +++ b/core/modules/language/js/language.switcher.js
    @@ -0,0 +1,25 @@
    +    // @todo: We need to add the active class to the active language.
    

    We can do this by manually re-invoking Drupal.behaviors.activeLinks() on the affected elements.

    Note that we also need to declare a dependency on the library that provides that behavior then.

  2. +++ b/core/modules/language/src/Controller/LanguageController.php
    @@ -0,0 +1,41 @@
    + * Contains \Drupal\image\Controller\LanguageController.
    

    s/image/language/

  3. +++ b/core/modules/language/src/Controller/LanguageController.php
    @@ -0,0 +1,41 @@
    +    $callback =  '\Drupal\language\Controller\LanguageController::setLanguageSwitchDestination';
    
    +++ b/core/modules/language/src/Plugin/Block/LanguageBlock.php
    @@ -88,9 +101,23 @@ protected function blockAccess(AccountInterface $account) {
    +      $callback = '\Drupal\language\Controller\LanguageController::setLanguageSwitchDestination';
    
    @@ -99,21 +126,44 @@ public function build() {
    +        $build['#post_render_cache']['\Drupal\language\Controller\LanguageController::setLanguageSwitchDestination'] = array(
    

    These can be simplified to 'language.redirect:setLanguageSwitchDestination'.

penyaskito’s picture

Status: Needs work » Needs review
FileSize
11.5 KB
9.63 KB
  1. We talked about this and that won't work. We need to add the active class for the active language, as active-links don't detect this as it is not the current route. We may want to fake data-drupal-link-system-path so active-links detects it, or do it ourselves in JS for registered + #post_render_cache callback.
  2. Good catch.
  3. Added as a service, which enables services injection.

Also renamed the controller to LanguageSwitcherController, which makes more sense.

Status: Needs review » Needs work

The last submitted patch, 28: 2232375-cache-block-switcher-28.patch, failed testing.

penyaskito’s picture

Status: Needs work » Needs review
FileSize
11.5 KB

Rerolled.

Status: Needs review » Needs work

The last submitted patch, 30: 2232375-cache-block-switcher-30.patch, failed testing.

penyaskito’s picture

Status: Needs work » Needs review
FileSize
14.42 KB

Another reroll.

Status: Needs review » Needs work

The last submitted patch, 32: 2232375-cache-block-switcher-32.patch, failed testing.

penyaskito’s picture

The @data-drupal-link-system-path now points to language-redirect. We were using that from the JS active-links, so we need to do:

a) Fake data-drupal-link-system-path so the active-links library works for the language switcher links.
b) Use our own js for settings active links.

Which is the preferred way?

Xano’s picture

The issue summary and #21 both mention a JS solution for authenticated users is the best approach. Why exactly is that and why wouldn't using #post_render_cache work here?

Gábor Hojtsy’s picture

@Xano: while I don't know the answer to that, it looks logical that service a static generated HTML fragment and a static JS file (as part of an aggregated JS file that is already locally cached) would be faster to serve from the server if there is no post-render PHP required?

Gábor Hojtsy’s picture

Xano’s picture

@Gábor Hojtsy: Thanks for taking the time to answer my question. I was always taught about graceful degradation or, more recently, progressive enhancement, so relying on JavaScript for this sounds like bad practice when I follow these approaches to review the patch. I'm really only trying to understand the reasoning, rather than criticize the chosen approach.

Gábor Hojtsy’s picture

@Xano: yeah the question is what to gracefully degrade to. The language switcher links without JS proposed by @Wim would degrade to switching to the front page of that language I guess. I am not saying I am fully content with that as a degradation target, but if the performance difference is significant, then it makes more sense then needing to hardcode frontpage language links instead on a site to avoid using this dynamic block AFAIS.

mgifford’s picture

Assigned: penyaskito » Unassigned

Unassigning stale issue. Hopefully someone else will pursue this.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

andypost’s picture

Version: 8.3.x-dev » 8.4.x-dev
Mirroar’s picture

So after a while of trying to find out why my pages were not being cached, I finally stumbled on the language switcher block and this issue in the comments.
The patch and direction from 3 years ago seem a bit complicated from my point of view, but I might be missing something. I feel we could just add the correct cache context to the render array of the cache block and remove the cache max-age to get the desired result.
I can see that you don't really want the language block to be cached for every language, page and url query values. But there is so much variance in the used links, which could also have been modified by hook_language_switch_links_alter. And I personally think the links should be output in the page's html code, not added via Javascript. But if you don't agree, consider my patch a workaround until there is a clean solution in core.

The thing here is that I really don't mind having a lot of cache entries (up to one per page per language), so long as the page itself has a usable max-age for varnish to cache it. But the way it is in core right now, max-age will always be 0. So far the attached patch seems to be working fine on my site, though I'm not sure I'm using all the correct cache contexts.

Mirroar’s picture

Status: Needs work » Needs review
Berdir’s picture

Page cache and the external cache status don't care about max-age, so this should not be the reason that your pages are not cached. And for authenticated users, it should use placeholders.

Status: Needs review » Needs work

The last submitted patch, 45: 2232375-45.patch, failed testing. View results

alexej_d’s picture

BTW @Mirroar returning a render array from getCacheMaxAge is invalid.

Mirroar’s picture

@alexej_d You must have misread the patch, it removes the getCacheMaxAge function.

@Berdir From my understanding the max-age bubbles up to the page, but retesting again without my patch, the Cache-Control headers seem to be fine all of a sudden. So I guess the current core solution simply doesn't render cache the language switcher block but doesn't affect the response's cache headers, which is what I was worried about.

Sorry for the confusion.

Berdir’s picture

Yes, see #2352009: [pp-3] Bubbling of elements' max-age to the page's headers and the page cache.

But I'll comment over there about this now, because once that issue is fixed/changed, what you expected/assumed is exactly what would happen.

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

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

mErilainen’s picture

Fixed the patch, but it doesn't seem to help, still getting Cache-Control: must-revalidate, no-cache, private in the response headers.

Berdir’s picture

Status: Needs work » Needs review
FileSize
723 bytes

@mErilainen: This problem does neither cause nor fix that problem, that must be something else, could be captcha or something else that calls the page cache kill switch.

I updated the patch and cleaned it up a bit. Note that those patches didn't work at all because it should be 'contexts' not 'context', so there were no contexts on that block.

I think instead of custom solutions here, we should look into my ideas in #2888838-11: Optimize render caching. If we'd prevent render caching of (small) parts that are cached per url/query args and instead use auto-placeholdering for that, then it would just work as far as I see.. I quickly tested with putting url.query_args into the auto-placeholder conditions and it worked as expected, but it is still getting render cached as far as I see.

Lets see what testbot thinks about it.

Status: Needs review » Needs work

The last submitted patch, 54: 2232375-54.patch, failed testing. View results

Berdir’s picture

claudiu.cristea’s picture

Needs IS update and probably a regression test.

Berdir’s picture

A test is tricky, there is no actual bug, it simply doesn't get cached. The only thing we could maybe test is that cache entries are created for it.

The other thing we could do in preparation of #2352009: [pp-3] Bubbling of elements' max-age to the page's headers and the page cache is adding explicit test coverage that a page with a language switcher is cached, but that will not fail in HEAD, it would only fail with that other issue without this patch.

Wim Leers’s picture

I haven't read the original work/patches from years ago, but #45/#56 seems feasible indeed :) My only question is why the user.permissions cache context is in there.

Wim Leers’s picture

Looking back at the original "this direction please"-patch I proposed in #1, the reason I had that extra complexity in there was to allow for fewer variants to be cached.

The patch in #45/#56 allows for many (MANY!) variations to be cached. There's not wrong, it just requires more cache space. But @Berdir is suggesting in #54 that if #2888838-11: Optimize render caching lands, we could just mark this block as being "cacheable but not worth caching". This would allow it to be cached as part of Dynamic Page Cache, but wouldn't cache the individual rendered block. That makes the approach in #45/#56 a lot more appealing of course!

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.

mpp’s picture

From a developers perspective I'd go for #56: It's the most straightforward implementation respecting the Cache API's cache contexts as it contains all possible variations. The fact that there are (way) too many variations and it may not be worth caching could be handled elsewhere or we could extend the API as suggested with a flag to indicate it is not worth caching.

Besides LanguageBlock I found these candidates where the flag would apply aswell:
- Drupal\book\Plugin\Block\BookNavigationBlock (see https://www.drupal.org/node/2483181)
- Drupal\form_test\Plugin\Block\RedirectFormBlock (see https://www.drupal.org/node/2351015)
- UncacheableDependencyTrait (I suppose this is a special case)

borisson_’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs issue summary update, -Needs tests

I agree with @mpp, this seems like a great solution. It is really hard to write extra tests for, so I'm going to remove the Need tests tag, see #58 for more information.

Also removing the Needs summary update based on #62.

This is issue is one of the blockers for #2352009: [pp-3] Bubbling of elements' max-age to the page's headers and the page cache.

The last submitted patch, 53: 2232375-53.patch, failed testing. View results

catch’s picture

I think this combination of this and one of the solutions from #2888838: Optimize render caching is good (i.e. what #60 says), but I'm not sure about committing this to a branch when #2888838: Optimize render caching is still pretty far from a committable patch.

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

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

larowlan’s picture

So should we postpone this on #2888838: Optimize render caching?

catch’s picture

Status: Reviewed & tested by the community » Postponed

Yes let's do that.

Anybody’s picture

Issue summary: View changes
Anybody’s picture

Updated summary accordingly. Lets RTBC this as soon as that issue is also fixed. All others are already committed.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

pcambra’s picture

Just an aside comment, this patch wasn't working for me OOTB, and what I had to do is in a custom block extending the LanguageBlock one.

Rather than using the render block, use the getCacheContexts method:

  /**
   * {@inheritdoc}
   */
  public function getCacheContexts() {
    return Cache::mergeContexts(parent::getCacheContexts(), [
      'user.permissions',
      'url.path',
      'url.query_args',
      'languages:language_content',
      'languages:language_interface',
    ]);
  }

And rather than removing the getCacheMaxAge method, override it by:

  /**
   * {@inheritdoc}
   */
  public function getCacheMaxAge() {
    return $this->cacheMaxAge;
  }

You need to include use CacheableDependencyTrait; in your custom block.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.