Problem/Motivation

Adding new CSS assets to the page by appending a rendered HTML snippet conflicts with a Content-Security-Policy that does not include style-src 'unsafe-inline' #3100151: Adding JS/CSS assets in AJAX responses requires 'unsafe-inline' Content Security Policy

Drupal 9.5 / 10.0 added a new AddJsCommand for JavaScript assets, in order to resolve issues with out-of-order execution of new JS files, but the loadjs library also adds assets to the page in a way that does not conflict with CSP inline code restrictions and can be used for CSS files as well.

Drupal\Core\Ajax\AddCssCommand was introduced for IE <= 9, because they didn't support @import statements if they were in a PrependCommand.
Drupal 8 no longer uses @import statements (#2897408: Remove IE9 support from CssCollectionRenderer and provide it in contrib instead), and has now also removed the IE9 support code from AddCssCommand (#3100147: Remove @import parsing from Drupal.AjaxCommands.prototype.add_css), so AddCssCommand now effectively operates the same as PrependCommand.

Proposed resolution

Alter \Drupal\Core\Ajax\AddCssCommand to accept an array of CSS assets in addition to a rendered HTML string (retained for backwards compatibility until Drupal 11.0.0), adding the assets to the page with the loadjs library.

Remaining tasks

User interface changes

None

API changes

Passing a rendered HTML string to Drupal\Core\Ajax\AddCssCommand is deprecated.

Data model changes

None

Release notes snippet

Passing a string to AddCssCommand is now deprecated, instead an array of attributes is expected like for AddJsCommand. CSS files added with Ajax commands are now loaded with loadjs and Ajax commands wait for all CSS files to load before executing the next commands.

Issue fork drupal-3110517

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

gapple created an issue. See original summary.

gapple’s picture

Also worth noting that prepending / appending HTML that includes script or style elements isn't compatible with Content Security Policy.

A CSP-compatible alternative for adding assets in an AJAX response is in this issue: #3100151: Adding JS/CSS assets in AJAX responses requires 'unsafe-inline' Content Security Policy

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.

gapple’s picture

Status: Active » Needs review
StatusFileSize
new3.21 KB

Here's a patch that adds deprecation notices, and replaces the one use of AddCssCommand. Corresponding tests will need to be updated.

gapple’s picture

StatusFileSize
new4.65 KB

I think this should address the test changes needed

gapple’s picture

Issue tags: +IE9

The last submitted patch, 4: drupal-3110517-4.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 5: drupal-3110517-5.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

gapple’s picture

Status: Needs work » Needs review
StatusFileSize
new6.25 KB
new1.71 KB

Move functional test of add_css to a separate, legacy, test method

Status: Needs review » Needs work

The last submitted patch, 9: drupal-3110517-9.patch, failed testing. View results

gapple’s picture

Status: Needs work » Needs review
StatusFileSize
new6.43 KB
new736 bytes

Test fix

gapple’s picture

StatusFileSize
new6.91 KB
new1.39 KB

Added @expectedDeprecation annotations to tests

Status: Needs review » Needs work

The last submitted patch, 12: drupal-3110517-12.patch, failed testing. View results

gapple’s picture

Status: Needs work » Needs review
StatusFileSize
new6.88 KB
new874 bytes
gapple’s picture

@expectedDeprecation annotation is deprecated, ExpectDeprecationTrait::expectDeprecation() method should now be used instead

https://www.drupal.org/node/3176667

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.

gapple’s picture

An alternative to complete deprecation could be to deprecate passing a rendered HTML string, but allow passing an array of URLs similar to #3228352: Add an add_js ajax command that uses promises. The loadjs library might not be necessary, but would allow returning a promise so that actions could be deferred until all CSS is loaded.

wim leers’s picture

Assigned: Unassigned » nod_

#3228352: Add an add_js ajax command that uses promises is adding the JS sibling command.

IMHO it's actually a conceptually different action, and the fact that it's abstracted into a specific command keeps the door option for interesting capabilities in the future.

So IMHO it's fine as-is.

Assigning to @nod_ for feedback.

gapple’s picture

Title: Deprecate Drupal\Core\Ajax\AddCssCommand » Improve Drupal\Core\Ajax\AddCssCommand to accept an array of CSS assets
Version: 9.3.x-dev » 9.4.x-dev
Issue summary: View changes
Issue tags: +Content Security Policy
Related issues: +#3100151: Adding JS/CSS assets in AJAX responses requires 'unsafe-inline' Content Security Policy

My approach to #3100151: Adding JS/CSS assets in AJAX responses requires 'unsafe-inline' Content Security Policy (and currently implemented in csp_extras module) was to introduce a new AddAssetsCommand that handled both CSS and JS, but I see the benefit of dedicated commands for each asset type.

The current implementation of AddCssCommand prepending a rendered HTML string still has the issue of requiring a page's content security policy include style-src 'unsafe-inline', reducing the protection that csp can offer to any page using the drupal.ajax library. Updating it to accept an array of assets in the same manner as the proposed add_js command would allow it to add the assets to the page in a CSP-compatible manner.

gapple’s picture

Title: Improve Drupal\Core\Ajax\AddCssCommand to accept an array of CSS assets » 3110517-improve-addcsscommand

Merge Request retains support for passing a rendered HTML string which is appended to the document head, but will trigger a deprecation warning.

In order to retain support for IE Conditional Comments, which won't be removed until Drupal 10.0.0, if any assets have a #browsers attribute specified the whole array of assets is rendered to HTML - selectively rendering only those assets and passing the rest to AddCssCommand as an array could introduce issues with asset reordering.

gapple’s picture

Title: 3110517-improve-addcsscommand » Improve Drupal\Core\Ajax\AddCssCommand to accept an array of CSS assets

oops, fixing title.

wim leers’s picture

#20: TIL! Yes, improving AddCssCommand makes a ton of sense!

Posted an initial review :)

gapple’s picture

I've rebased to 9.4, and updated the JS function to use the loadjs library, based on the changes for add_js, though the deferred may not be necessary for CSS.

gapple’s picture

Issue tags: -Needs tests

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.

nod_’s picture

Assigned: nod_ » Unassigned
Issue tags: +JavaScript

left a couple of minor comments, This is a good idea +1 to it.

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.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new150 bytes

The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

gapple’s picture

Status: Needs work » Needs review

Did a rebase & squash, since merge conflicts were pretty significant, and addressed remaining comments.

I changed the jQuery Deferred to a native Promise, matching add_js. I'm still not sure that it is actually necessary - there isn't a concern about out-of-order execution like with new JS files that was the reason for introducing the add_js command.

gapple’s picture

Issue summary: View changes

Tests are now passing, and I've updated the draft Change Record

andypost’s picture

It looks nice and ready except legacy test for JS deprecation message

gapple’s picture

Added a test for a the JavaScript deprecation message

andypost’s picture

Thanks 👍 last mossing brick is follow-up to remove deprecation in 11.x - todo needs link to issue

andypost’s picture

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +Needs Review Queue Initiative

Change record makes sense (to me)
Test coverage of deprecation is there
New tests for new way to do the call is there
No remaining tasks
All remaining threads closed

This looks good to me.

nod_’s picture

Issue summary: View changes
Issue tags: -JavaScript +JavaScript

updated release notes.

I was about to commit this but have a question, with this change it's not possible to add inline CSS with the addCss command. It's easy enough to add a new append/prepend command with the styles to do the same but just wondering if we're all good with that.

  • nod_ committed 8496c2c3 on 10.1.x
    Issue #3110517 by gapple, andypost, nod_, Wim Leers, smustgrave: Improve...
nod_’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Fixed

There is an easy workaround, let's move forward and fix if/when necessary

Committed 8496c2c and pushed to 10.1.x. Thanks!

wim leers’s picture

Very nice!

Status: Fixed » Closed (fixed)

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

acbramley’s picture

dieterholvoet’s picture

I was about to commit this but have a question, with this change it's not possible to add inline CSS with the addCss command. It's easy enough to add a new append/prepend command with the styles to do the same but just wondering if we're all good with that.

This broke the Critical CSS module: #3389128: Appending inline critical CSS is broken in AJAX requests since Drupal 10.1.0

jonmcl’s picture

Previous behavior was to prepend the CSS:
$('head').prepend(response.data);

I think the new code is appending to <head> which can cause order of precedence issues. A module might have CSS component assets (weight of 0) which are added into <head> after our theme's CSS_THEME assets (weight of 200).

This might not be an issue for most situation, but I just noticed it with some quick D10 testing in advance of an upgrade. Maybe it was just a coincidence that we were able to have our theme CSS override the module's component CSS?

Any known workarounds for this (potential) issue?

yonailo’s picture

We are experiencing an issue with z-index in the media library widget related to this CSS sorting change.

It seems that https://www.drupal.org/project/drupal/issues/3396505 fixes our issue.

Hope this helps.

yonailo’s picture

vincent.hoehn’s picture

We also have a problem with the z-index and the media-library-widget. It occurred after the update from 10.1.7 to 10.2.0.