Follow-up to #2451411: Add libraries-override to themes' *.info.yml
Problem/Motivation
Sometimes you want to alter the assets of a library by adding in your own additional library assets whenever a library is attached.
The most common use case in core is the Classy base theme, see #2489460: [Meta] Move module.theme.css files to Classy or Seven.
Other use cases include:
- BigPipe (in core or contrib), where it is crucial because it means a theme's CSS extending other CSS is loaded not as part of the initial theme CSS, but as part of the CSS for the actual component. Remember that the component may be rendered *after* the initial page! So this ensures that we don't end up with 1. theme CSS, 2. component CSS, with 2 overriding 1, which is a problem in HEAD. With support for this, we completely avoid that problem.
- The last point also quite clearly shows how this makes Drupal 8 ready for a Web Component world.
Neither stylesheets-remove nor libraries-override meet this specific use case.
There is also a big front-end performance win: rather than loading all the CSS extending existing CSS all the time, this ensures it's only loaded when necessary.
Proposed resolution
Allow code like the following in a theme's (and potentially module's?) *.info.yml file so that libraries can extend other libraries:
# Extend drupal.user: add assets from classy's user libraries.
libraries-extend:
core/drupal.user:
- classy/user1
- classy/user2
Remaining tasks
Patch
Patch review
Commit
User interface changes
N/A
API changes
API additions.
Beta phase evaluation
| Issue category | Task because it is an API addition. Nothing is broken. |
|---|---|
| Issue priority |
|
| Prioritized changes | The main goal of this issue is TX, but there's also a strong front-end performance aspect, and an even stronger "unblock BigPipe" aspect. |
| Disruption | Unblocks much of the work in #2489460: [Meta] Move module.theme.css files to Classy or Seven, otherwise not disruptive. |
| Comment | File | Size | Author |
|---|---|---|---|
| #25 | libraries-extend-2497667-25.patch | 15.58 KB | wim leers |
Comments
Comment #1
jaxxed commentedYour initial proposed syntax should probably be an array format (or allow for an array format)
If you wanted to extend a library by adding more than one library, you'd need something like:
I am not sure what the Drupal YAML standards are for variable elements (can a node be a string OR an array of strings.)
Comment #2
star-szrGreat point, thanks @jaxxed. I can't remember who came up with that syntax originally, but we are having similar discussions on the libraries override issue.
Comment #3
almaudoh commentedHow about if we wanted to extend a library with just a component from a theme or elsewhere. We could do something like:
This allows to add some new css or js to the existing library, without having to necessarily define a new library.
Comment #4
star-szrYup that seems valid as well, worth considering at least :)
Comment #5
jaxxed commented@almaudoh
I still think that it needs to be an array per library:
I started by following the overrides code, but it diverges from our needs pretty quickly.
I'm not ready to patch for this deeper extension syntax, but right now I am playing with injecting library dependencies for an library-extensions. There would be some notable behaviour that would come with such an approach, the most significant being that dependencies are loaded before the library that they're attached to.
Is this something that we're thinking about just for one of the subthemes, or are we going right for the core? If it's the core then I can look at altering the library discoverer right away, but if it's not in the raw core, then it will require overloading or adding more code.
Comment #6
star-szrI don't think we want to add dependencies here, there are already ways to do that I'm pretty sure. By extending we want to add the opposite of dependencies.
@jaxxed what do you mean by right for the core/raw core? Just Drupal core? Used by core themes?
Comment #7
almaudoh commentedSo where do we stand on the syntax here. Considering that there is mention that this particular capability may be needed sooner rather than later, we could start work on a patch here.
Comment #8
davidhernandezSo why did we split this off into its own thing instead of making it part of libraries-override? It seems like override just needs an add asset syntax.
Comment #9
almaudoh commentedSo combining #1 and #5, we could have something like:
This looks sensible to me and easy for everyone to understand.
@davidhernandez: There is a slight difference to the
libraries-overridesyntax which doesn't specify attributes for the assets. But also it was to make the patches easier to review.Comment #10
wim leersBecause we wanted to keep the scope as small as possible over there, I think that was mostly discussed/agreed upon in IRC, but #2451411-37: Add libraries-override to themes' *.info.yml and #2451411-63: Add libraries-override to themes' *.info.yml suggest this at least.
Comment #11
fabianx commentedIf it were me I would keep it stupidly simple and just allow extending a library with another library for now.
The use case of directly adding CSS is very nice, but could internally be still be implemented as a hash over the contents of the definition.
core/autogenerated_[HASH]
and create a library on the fly.
Overall however I don't see much difference in:
vs.
While being way more flexible to work with.
e.g. another module or subtheme could decide to just add something to mytheme/foo - regardless if that is used in one or in several libraries as extension.
override is a different "beast" in that that should allow to override / remove or change specific CSS files.
This issue should IMHO be purely about libraries extending other libraries and nothing more - and hence keep things really simple.
Comment #12
star-szrAgreed with #11, that is in line with the original proposal in the issue summary and nicely keeps things inside the actual library definition rather than bloating the theme's .info.yml file. Overriding is indeed a different beast with different requirements which I don't think makes sense to try to incorporate into *.libraries.yml. I like how it's been implemented in the overrides issue.
Put differently, adding the ability to add individual CSS and JS files from the theme's *.info.yml kind of undoes https://www.drupal.org/node/2228783 and similar changes.
Comment #13
almaudoh commented+1 to #11. So basically we're looking at
libraries-extend:infoo.libraries.ymlinstead of foo.info.yml. But how do we explain to someone new to Drupal 8 whylibraries-extendis infoo.libraries.ymlwhilelibraries-overrideare infoo.info.yml.Comment #14
star-szrI actually completely missed that it was being proposed to add to libraries.yml. That does feel somewhat inconsistent.
I think the extends should be "mapped" in the info file similar to how you can add a library to every page, and the libraries to use as "extensions" declared normally in libraries.yml.
Comment #15
fabianx commented#13, #14: Yes, I was unclear there.
I meant:
- libraries to *.libraries.yml
- libraries-extend to *.info.yml
Modules can use the good ol' hook_library_info_alter() to do the same.
Comment #16
star-szrGood then, at least a few of us agree there! :)
Comment #17
almaudoh commentedOk. So #1, #11 and #15 makes the implementation relatively simple.
Here's a patch rolled on top of the latest patch at #2451411: Add libraries-override to themes' *.info.yml. The do-not-test.patch is the patch for this issue with one test. More tests still needed.
Some key points:
Comment #19
almaudoh commentedFixed the test fails and added some docs. Still needs more tests.
Comment #21
almaudoh commentedComment #22
fabianx commentedOverall looks great, one detail:
I thibk this should extend the libraries to extend and not override.
Or merge in other words.
I.e. if a base theme extends a component, why should the theme have to do the same and not just extend more?
Comment #23
almaudoh commented#22.1 Great point! Fixed. Also added some more tests. This should be ready now.
Comment #24
wim leersWow, great work here! :)
#2451411: Add libraries-override to themes' *.info.yml landed. Reuploading without that part, i.e. reuploading #23's "do-not-test" patch. Zero changes made.
Comment #25
wim leersThis looks excellent. I was only able to find nitpicks, fixed those myself.
s/libraries extend/libraries-extend/
s/libraries extend/libraries-extend definitions/
Libraries extensions (so it is consistent with the wording in the preceding code which says "libraries overrides").
Committer: no need to credit me for these language nitpicks.
Comment #26
wim leersFrom the beta evaluation:
We have strong +1 from Cottser.
Comment #28
fabianx commentedStrong RTBC + 1
Yes, this usage pattern is crucial for BigPipe, AJAX, ESI + Co and one of the big enablers.
No more !important in the theme for AJAX CSS loaded afterwards ...
Comment #29
almaudoh commentedMoved Wim's strong arguments in #26 up higher in the IS.
Comment #30
alexpottCan we get a quick followup to actually use this in Classy... the theme has an @todo on this issue.
We've got test coverage and this is an addition so less risky than a change. Committed b95d2c8 and pushed to 8.0.x. Thanks!
Comment #32
wim leersWOOOHOOO! Thank you!
Done: #2580255: Remove (classy|seven)_library_info_alter() in favor of libraries-extend.
Comment #33
davidhernandezThis should have a change record.
I'll see if I can work on one later, but anyone else can feel free to do so.
Comment #34
almaudoh commentedUpdated existing libraries-override CR https://www.drupal.org/node/2497313 to incorporate libraries-extend.
Comment #35
wim leersI also updated the CR to link to #2580255: Remove (classy|seven)_library_info_alter() in favor of libraries-extend, to point readers to the fact that Seven and Classy are now doing the right thing :)
Comment #37
donquixote commentedActiveTheme->librariesExtend was introduced here as an undeclared property.
Follow-up: #2959972: Undeclared property: ActiveTheme::$librariesExtend