Implementing access requirements on library definition level

Created on 4 September 2023, over 1 year ago
Updated 23 October 2023, over 1 year ago

Problem/Motivation

Consider the following situation...
Users of a website(non-admin) would never interact with the core's toolbar module. Yet, those assets are always served as there is no way to serve css/js files variations based on specific access rules, like a specific permission, role, access callback.
Same is valid for CKEditor, diff, ... libraries. In my case, I need none of the libraries provided by drupal core and drupal modules.

We can't achieve above with `HOOK_library_info_alter()` because if we for example unset a library for a specific role, and if the aggregation is turned ON, the generated aggregated file will serve the asset which was generated on the first request.

Proposed resolution

Create a subsystem for drupal libraries, which would allow defining access requirements to libraries, similar to access requirements on routes.

✨ Feature request
Status

Closed: works as designed

Version

11.0 πŸ”₯

Component
Asset libraryΒ  β†’

Last updated 1 day ago

No maintainer
Created by

πŸ‡¬πŸ‡§United Kingdom hugronaphor

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @hugronaphor
  • πŸ‡ΊπŸ‡ΈUnited States bkosborne New Jersey, USA

    I think your premise is a bit incorrect - Drupal's library system works by modules/core attaching only the libraries that are needed by the page. So if you visit a page, and the CKEditor JS files are added to the JS aggregates, it's because CKEditor was loaded on the page. Same with Toolbar.

    But I think the nature of your question (what you're getting at) is that there are too many unique combinations of library assets, leading to dozens or more of JS/CSS aggregates created. I just witnessed this my self by clicking through a bunch of admin pages on my site (cold cache) and observing 24 JS aggregate files created.

    At a certain point, I suspect there's so many unique combinations that it's not worth the overhead of generating all these aggregate files.

  • Status changed to Closed: duplicate over 1 year ago
  • πŸ‡¬πŸ‡§United Kingdom catch

    #3 is correct.

    We need ✨ [PP-1] Allow setting aggregation groups for js files in library definitions Postponed and the issue blocking it
    to reduce the number of aggregates.

    Marking duplicate of those two.

  • Status changed to Active over 1 year ago
  • πŸ‡¬πŸ‡§United Kingdom hugronaphor

    Don't think I've been understood here.
    I might have confused you by relating to aggregation but let's take out of equation the aggregation completely.

    What I'm saying is that Drupal core and it's modules comes with a bunch of its libraries which in my case, non-admin users make no usage of them because Tailwindcss and AlpineJS is used.

    Drupal allows you to unset libraries completely but not conditionally while what I would want to achieve is e.g:

    if user has permission to use toolbar, serve the toolbar related libraries if not, there is no need for any of those.

    Basically, I would want to be able to declare access requirements similar to how we define routes on library level, e.g:

    toolbar:
      version: VERSION
      js:
        # Core.
        js/toolbar.js: {}
        # ...
      css:
        component:
          css/toolbar.module.css: {}
        theme:
          css/toolbar.theme.css: {}
          css/toolbar.icons.theme.css: {}
      dependencies:
        - core/jquery
        - core/drupal
        # ...
      requirements:
        _permission: 'access toolbar'
  • πŸ‡«πŸ‡·France nod_ Lille

    I'm not sure I understand the issue, in your exemple if the user doesn't have access to the toolbar then the libraries won't be loaded since the toolbar is not added to the page right?

  • πŸ‡¬πŸ‡§United Kingdom hugronaphor

    _nod you're right. Bad example from my side. I was trying to be generic...

    Let's look at "system.libraries.yml" in "system" module. The "system/base" library is attached via "system_page_attachments()" on every page while what I'm trying to achieve is to only serve this library for authenticated users only and not anonymous users.

    If attempting to conditionally remove the library as bellow, after clearing the cache via cli and visiting a page as authenticated user first, subsequent request to a page as an anonymous user, all assets of "system/base" would still be served.

    function HOOK_library_info_alter(&$libraries, $extension): void {
    
      iif (!Drupal::currentUser()->isAuthenticated()) {
        if ($extension === 'system') {
          unset($libraries['base']);
        }
      }
    
    }

    So, adding access requirements to libraries is a way i was thinking this can be tackled.

  • πŸ‡¬πŸ‡§United Kingdom catch

    @hugronaphor you could use hook_page_attachments_alter() to undo what system module does for that use case.

    The library definitions are deliberately decoupled from the context those libraries are used in, in some cases it's 1-1, in other cases they could show up potentially anywhere for any type of user depending on site configuration.

  • πŸ‡¬πŸ‡§United Kingdom hugronaphor

    @catch OK, fair enough hook_page_attachments_alter() does achieve what I was asking. Thank you for this.

    I'll go one step further with another example:

    function HOOK_library_info_alter(array &$libraries, $module) {
      if ($module == 'core' && !Drupal::currentUser()->isAuthenticated()) {
        $libraries = [];
      }
    }

    I understand that this might be unethical to do but I'm in a situation, where my app can live without Drupal and related JS objects.
    I would want to remove everything because of performance and because the internet crawlers can detect the Drupal backend based on these JS objects.

    Talking about Drupal's composability, I feel like there should be a way to not include Drupal assets.

    For now, looks like decorating LibraryDiscoveryCollector is the way to do it as described in https://drupal.stackexchange.com/a/276800/13633

  • Status changed to Closed: works as designed over 1 year ago
  • πŸ‡¬πŸ‡§United Kingdom hugronaphor

    Closing as overriding library discovery Cache ID does give a way to achieve what has been asked.

Production build 0.71.5 2024