If you're here to provide feedback: please read the issue summary and then jump to #49!

Problem/Motivation

  1. This is a blocker for #2368797: Optimize ajaxPageState to keep Drupal 8 sites fast on high-latency networks, prevent CSS/JS aggregation from taking down sites and use HTTP GET for AJAX requests. There, we want to make Drupal sites as fast as possible, and the changes there especially have a big effect on high-latency (mobile) connections. We want to do that by only using libraries for "AJAX page state", which allows us to send far less metadata. But if we want to do that, we should no longer allow attaching individual CSS and JS assets (that's what #2382533: Attach assets only via the asset library system is for). But if we don't allow them, then we can no longer attach JS settings, because we currently consider JS settings as regular JS assets.
  2. Also, the DX of adding JS settings is absolutely terrible, awful, fragile. You must add a JS asset with a very specific array structure that is extremely easy to get wrong. (Wim Leers has personally run into this problem dozens and dozens of times in the >8 years he uses Drupal.)

Proposed resolution

We want to do that by only using libraries for "AJAX page state", which allows us to send far less metadata. But if we want to do that, we should no longer allow attaching individual CSS and JS assets (that's what #2382533: Attach assets only via the asset library system is for). But if we don't allow them, then we can no longer attach JS settings, because we currently consider JS settings as regular JS assets.

Hence this issue proposes a new asset type to deal with that, and at the same time vastly improve the DX of attaching JS assets:

Before
$build = array(
  …,
  '#attached' => array(
    'js' => array(
      array(
        'type' => 'setting',
          'data' => array('ckeditor' => array(
            'hiddenCKEditorConfig' => $config,
          )),
        ),
      ),
    ),
  ),
);
After
$build = [
  …,
  '#attached' => [
    'drupalSettings' => [
      'ckeditor' => ['hiddenCKEditorConfig' => $config],
    ]
  ],
];

Remaining tasks

Review.

User interface changes

None.

API changes

  1. Vastly improved DX for attaching JS settings: no longer $build['#attached']['js'][] = ['data' => ['mysetting' => 'foo'], 'type' => 'setting'], but $build['#attached']['drupalSettings']['mysetting'] = 'foo';, hence matching how JS settings are used on the front-end.
  2. Accompanying asset type alter hook: hook_js_settings_alter().
  3. Removes drupal_merge_js_settings().

Beta phase evaluation

-->

Reference: https://www.drupal.org/core/beta-changes
Issue priority Critical because it blocks #2368797: Optimize ajaxPageState to keep Drupal 8 sites fast on high-latency networks, prevent CSS/JS aggregation from taking down sites and use HTTP GET for AJAX requests.
Prioritized changes The main goal of this issue is performance (in the blocked issue), but at the same time vastly improving the DX. The principal JS maintainer, a core committer, Fabianx, myself, and hence surely many others, still struggle after many years with adding JS settings. The current DX is *that* atrocious.
Disruption Disruptive for contributed and custom modules/themes because it requires JS settings to be attached in a different way: a much simpler way. The long-term benefits are considered to outweigh the API change this late in the game. See #27 and #28.
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Wim Leers’s picture

Also, a long, long, long time ago, we introduced

drupalSettings:
  version: VERSION
  settings: {}

plus

      // @todo Introduce drupal_add_settings().
      if (isset($library['settings'])) {
        $library['js'][] = array(
          'type' => 'setting',
          'data' => $library['settings'],
        );
        unset($library['settings']);
      }

This issue basically just finishes what was started there.

catch’s picture

Issue tags: +API change

Yes please.

I also get the array structure wrong for js settings wrong nearly every time I try to add them, and having to declare js settings in libraries doesn't work since js settings are nearly always dynamic.

Wim Leers’s picture

Status: Active » Needs review
FileSize
52.34 KB
nod_’s picture

Done, consensus built. I don't think anyone would lobby to keep the current DX.

One comment is that naming this $element[#attached][settings] might be confusing. Before you had the information that is was about JS. Some might end up thinking it's some kind of $form_state for render elements. Might not be an issue but from a distance it can look like that.

It's longer and somewhat uglier but how would you feel about: [#attached][drupalSettings].

Wim Leers’s picture

I've also considered ['#attached']['js_settings'].

I don't care if it's settings, js_settings or drupalSettings. I actually like drupalSettings because it's identical to how you use it on the front-end. But I don't care because no matter what the name ends up being, it's going to be vastly simpler to use than what we have now.

catch and nod_, core committer and JS maintainer, the two of you can decide IMHO.

nod_’s picture

I'll go with drupalSettings then, at least they have a clue where to find that stuff in their JS.

Wim Leers’s picture

#6: one consequence of that is that we'll end up with

drupalSettings:
  version: VERSION
  drupalSettings: {}

in core.libraries.yml.

So: are you sure?

I'll wait for consensus between you and catch :)

nod_’s picture

Not a problem for me. It's just an artifact of explicitness, in all the other places it'll look good.

Fabianx’s picture

FWIW, I also always get the syntax wrong, the first time I researched this for 2 hours until I found a good blog post that made it out as being a big secret ...

So BIG +1, my vote would be for drupalSettings as well.

Wim Leers’s picture

Issue tags: +Needs tests
FileSize
57.92 KB
44.72 KB

Did the rename (s/settings/drupalSettings/). Still needs tests for the newly added hook_js_settings_alter().

One thing I want to call out: ['#attached']['drupalSettings'] versus hook_js_settings_alter() — "drupal settings" versus "js settings" — that is less than ideal, but hook_drupal_settings_alter() would be much, much worse. So I think this would still be preferable for the reasons mentioned above, because hook_js_settings_alter() would be necessary very, very rarely, and ['#attached']['drupalSettings'] is used very commonly.
Thoughts?

catch’s picture

The #attached key vs. hook name mismatch isn't great, but I also think drupalSettings and hook_js_settings_alter() are the best names individually, so fine with me.

Status: Needs review » Needs work

The last submitted patch, 10: js_settings_asset_type-2382557-10.patch, failed testing.

Wim Leers’s picture

FileSize
58.46 KB
934 bytes

I had only run unit tests before posting #10, I should've just loaded a page (any page!) as well.

This should make it green. Next: tests.

Wim Leers’s picture

Status: Needs work » Needs review

Such n00b.

Status: Needs review » Needs work

The last submitted patch, 13: js_settings_asset_type-2382557-13.patch, failed testing.

Wim Leers’s picture

Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs tests
FileSize
63.35 KB
5.95 KB

Fixed existing test failures.

Ensured needed tests exist:

  1. LibraryDiscoveryParserTest::testLibraryWithCssJsSetting() (which uses css_js_settings.libraries.yml) already tests parsing drupalSettings from a library. So that's already taken care of.
  2. JavaScriptTest::testHeaderSetting() is expanded to also test hook_js_settings_alter().

Updated IS. Created CR.

Wim Leers’s picture

Issue summary: View changes

Status: Needs review » Needs work

The last submitted patch, 16: js_settings_asset_type-2382557-16.patch, failed testing.

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
64.09 KB
1.72 KB
Fabianx’s picture

Status: Needs review » Reviewed & tested by the community

RTBC, it would be great to show an example from the tests for hook_js_settings_alter() in the change record :).

nod_’s picture

$variables[#attached][drupalSettings] is so much win. Rtbc++

Wim Leers’s picture

Wim Leers’s picture

Status: Reviewed & tested by the community » Needs work

Alex Pott and I discovered there are still remaining 'type' => 'setting' JavaScript assets that should be converted.

Wim Leers’s picture

Issue summary: View changes
Status: Needs work » Needs review
FileSize
75.99 KB
15.5 KB

Thanks to working on #23, I discovered one mistake I made in the patches above: I was using drupalSettings incorrectly. And in fact, the example in the IS (and hence also the CR) is subtly wrong, and contains the same mistake … since I used the one case with a mistake in it as my example!

You see, we've always listed an *array* of settings. I.e. we used to do:

$build = array(
  …,
  '#attached' => array(
    'js' => array(
      array(
        'type' => 'setting',
          'data' => array('foo' => TRUE),
        ),
      ),
      array(
        'type' => 'setting',
          'data' => array('bar' => FALSE),
        ),
      ),
    ),
  ),
);

And now we'd do

$build = [
  …,
  '#attached' => [
    'drupalSettings' => [
      ['foo' => TRUE],
      ['bar' => FALSE],
    ]
  ],
];

But the example in the IS and CR before this comment, as well as in two places in CKEditor.php (but not anywhere else) did:

$build = [
  …,
  '#attached' => [
    'drupalSettings' => [
      'foo' => TRUE,
      'bar' => FALSE,
    ]
  ],
];

A subtle, but important difference!


I'd argue the latter is actually easier to use, but that'd make this API change more painful. If we want to do that though, I'm fine with going that way, if people think we should do that.


I must've been very distracted while working on CKEditor.php, because not only is it the only place where I used JS settings incorrectly, it's also the place where I did this:

     $fake_editor = entity_create('editor', array(
       'format' => $editor->id(),
       'editor' => 'ckeditor',
-      'settings' => array(
+      'drupalSettings' => array(

… which is obviously wrong. Rectified that too. Manually tested the drag-and-drop CKEditor toolbar config UI to make sure it still works. Confirmed that it was broken in the patches above, and is working with this patch.

Status: Needs review » Needs work

The last submitted patch, 24: js_settings_asset_type-2382557-24.patch, failed testing.

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
75.19 KB
1.87 KB

Oops.

nod_’s picture

Status: Needs review » Needs work

About the DX, when it's like this:
$element['#attached']['drupalSettings'][] = ['machineName' => …]

It's cool it makes sense. But when it's

'drupalSettings' => [[
        'batch' => [
          'errorMessage' => $current_set['error_message'] . '<br />' . $batch['error_message'],
          'initMessage' => $current_set['init_message'],
          'uri' => $url,
        ],
      ]],

It's kinda not obvious. I have an issue with the shorthand syntax for arrays so it might come from there. Conceptually though, while [library][] = ''; makes sense because it's a list of dependency, drupalSettings is less obvious. I don't see that we attach a list of settings but it's mainly about attaching a setting object and have all of them aggregated in the background.

Tried it out, it seems to work well (no idea about tests though). In common.inc around 1835:

  // Convert every JavaScript settings asset into a regular JavaScript asset.
  // @todo Clean this up in https://www.drupal.org/node/2382533
  if (isset($elements['#attached']['drupalSettings'])) {
    _drupal_add_js($elements['#attached']['drupalSettings'], ['type' => 'setting']);
    unset($elements['#attached']['drupalSettings']);
  }

I will never write this: 'drupalSettings' => [['foo' => TRUE], ['bar' => FALSE]]. I know it's example code but I expect(ed) the DX to be: 'drupalSettings' => ['foo' => TRUE, 'bar' => FALSE]
because that just makes more sense.

I'm for changing the API around this piece of cruft, we're already changing API anyway might as well make it as nice as possible.

Other than that, patch looks good.

catch’s picture

I'm also tempted by the change to the array structure here, that's not any additional breakage for modules, and it'll be easier in the long run.

Wim Leers’s picture

I'm for changing the API around this piece of cruft, we're already changing API anyway might as well make it as nice as possible.

I'm also tempted by the change to the array structure here, that's not any additional breakage for modules, and it'll be easier in the long run.

JS maintainer + core committer giving the thumbs up, hence I'll change this :)

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
76.01 KB
Wim Leers’s picture

Issue summary: View changes
FileSize
89.58 KB
62.97 KB

Made the changes proposed in #24 and agreed upon in #27 & #28. Lots of snippets of code became much simpler :)
Updated the IS and CR accordingly.
Consequently, it became easy/logical to move the particularly tricky logic to generate the default drupalSettings out of _drupal_add_js(), into system_js_settings_alter()
Another absolute requirement for #24/#27/#28 to be implemented, is that drupal_merge_attached() be updated to handle the 'drupalSettings' key differently when it comes to merging. As a direct consequence, I was able to simplify some of the tests.

Status: Needs review » Needs work

The last submitted patch, 31: js_settings_asset_type-2382557-31.patch, failed testing.

dawehner’s picture

Great work, this looks really solid.

  1. +++ b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
    @@ -123,8 +123,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
    -    $js = array('copyFieldValue' => array('edit-site-mail' => array('edit-account-mail')));
    -    $form['#attached']['js'][] = array('data' => $js, 'type' => 'setting');
    +    $form['#attached']['drupalSettings']['copyFieldValue']['edit-site-mail'] = ['edit-account-mail'];
     
    

    This is lightyears easier to read.

  2. +++ b/core/modules/history/history.module
    @@ -193,16 +193,7 @@ function history_user_delete($account) {
    +  $node_id = $context['node_id'];
    +  $element['#attached']['drupalSettings']['history']['lastReadTimestamps'][$node_id] = (int) history_read($context['node_id']);
    

    Nitpick: Now that you have extracted the $node_id into a variable you can also use it on the right hand side.

  3. +++ b/core/modules/system/src/Tests/Common/MergeAttachmentsTest.php
    @@ -202,48 +198,95 @@ function testJsSettingMerging() {
    +    $expected_settings_two['moduleName']['magical flag'] = 3.14;
    

    Just in case you ever need a more precice number, you can also call pi() or use M_PI :)

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
89.35 KB

#32 was broken by #2300817: Remove path_is_admin() as it is deprecated, straight reroll. Not yet addressing #33.

Wim Leers’s picture

FileSize
90.62 KB
7.54 KB

#33: Thanks for the review!

  1. :)
  2. Hah, fixed!
  3. Oh, thanks, that's good to know :)

One of the broken hunks was the one in BlockController::demo(), where drupalSettings.path.currentPath is being overridden. I wondered if there was any test coverage to ensure it still works. There isn't. And surely, it was broken. So, fixed that and added test coverage for it.

I also noticed I could easily remove drupal_merge_js_settings() from JsCollectionRenderer, so I did (it only ever received one setting with the above patches), and it's now consistent with how ['drupalSettings'] works everywhere else.

The last submitted patch, 34: js_settings_asset_type-2382557-34.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 35: js_settings_asset_type-2382557-35.patch, failed testing.

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
93.19 KB
3.65 KB

The failed test duplicates the test coverage in MergeAttachmentsTest (verifying that drupal_process_attached() correctly merges JS settings, i.e. the data in the 'drupalSettings' key), so rather than fixing it, I removed it.

nod_’s picture

Status: Needs review » Reviewed & tested by the community

Reviewed the patch tested the UI and everything looks good. The DX is so nice to work with.

The only detail I was unsure of is the fact that drupalSettings get it's default values in system_js_settings_alter, but we get some of the drupalSettings values in the library file so it helps with discovery. Anyhow I never had to use js settings value from PHP before so I don't feel like setting those values a bit later is any problem.

RTBC for me, let's finish this :)

jhodgdon’s picture

Status: Reviewed & tested by the community » Needs review

I think there is some documentation that needs to be updated here, some in the patch and some on drupal.org documentation pages, right?

So we need to make sure all topics and other documentation on api.drupal.org that references JS settings is updated for this change, as part of the patch. And in the issue summary, we need to add a section that lists pages on drupal.org that will need to be updated if this patch goes in.

Also before this issue can be marked RTBC it needs a "Beta Evalualuation" section added to the summary. See https://www.drupal.org/contribute/core/beta-changes

jhodgdon’s picture

Wim Leers’s picture

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

This patch already updates documentation. It updates very little, because $build['#attached']['js'][] = ['type' => 'setting', …] is utterly undocumented, hence there isn't much to update.
You link to https://api.drupal.org/api/drupal/core!modules!system!theme.api.php/grou... and https://api.drupal.org/api/drupal/core!includes!common.inc/function/drup..., but there's not a single mention of "setting" on either page!

I've now updated the asset documentation for themers at https://www.drupal.org/node/2216195.

That being said, I totally agree #attached documentation should be much better. But this is not the right issue to do so. #2382533: Attach assets only via the asset library system is going to bring the much-needed clarity code-wise, the one we've been working towards for well over a year. Therefore, we can only clearly document all this once the implementation/usage are actually clear. This issue blocks that issue. Please don't hold up this issue on documentation changes that we'd mostly need to redo for #2382533 anyway.

Added the beta evaluation section.

jhodgdon’s picture

Issue summary: View changes

We shouldn't have updated the drupal.org pages until *after* the patch went in... oh well, hopefully it will go in.

Wim Leers’s picture

FileSize
95.48 KB
8.16 KB

#43: that's not true for change records (they must be updated before commit), so I assumed the same approach was required for documentation pages also. Our tools in these areas sadly are lacking :(


Alex Pott and I were talking about another issue in IRC. Then he started just sending me his remarks in IRC instead of posting them here. I'll repeat them:

  1. drupal_merge_js_settings docs changes look wrong: $page['#attached']['drupalSettings'][] = ['foo' => ['a', 'b', 'c']]; should be $page['#attached']['drupalSettings']['foo'] = ['a', 'b', 'c'];

    This is correct, I failed to update that one in the last reroll. Fixed.

  2. In one place, we have drupal_merge_js_settings(['drupalSettings'], …, in another we have drupal_merge_js_settings(['drupalSettings']['data'], … — which is right? Or was the 'data' key dropped?

    The 'data' key only exists in one place: where drupal_merge_js_settings() is called inside _drupal_add_js(), due to internal implementation details of _drupal_add_js(). Hence it's not something any developer will ever see. Developers will only ever see ['#attached']['drupalSettings'], without the 'data' key.

  3. So I think we should remove usages of drupal_merge_js_settings and just use NestedArray::mergeDeepArray($blah, TRUE) with a comment.

    Now that the number of usages is much, much lower, that's entirely possible, yes. Only 3 places remain: drupal_process_attached(), _drupal_add_js(), WebTestBase. Nobody should ever have to manually merge JS settings anymore anyway (previously, custom responses like AjaxResponse would have had to call this, but not anymore, since _drupal_add_js() already does all the merging that's ever necessary).
    So: removed!

  4. I think I've spotted a problem: testDrupalRenderChildrenPostRenderCache - 'common_test' is a duplicated array key

    Great catch, now fixed.

  5. "drupalSettings.path.currentLanguageis" - missing a space

    Fixed.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 44: js_settings_asset_type-2382557-44.patch, failed testing.

Wim Leers’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
95.5 KB
748 bytes

HAHAHA, how stupid!

Wim Leers’s picture

FileSize
95.46 KB
1.02 KB

Alex Pott came back to me on IRC with one more question: whether we could optimize drupal_merge_attached() to avoid first merging the values for the 'drupalSettings' key the wrong way, and then redoing it the right way.

This does that.

Wim Leers’s picture

Issue summary: View changes
yched’s picture

Great move !

Not a fan of the 'drupalSettings' key, that is not explicitly related to JS and which, seen in PHP code, doesn't reflect what the code does - pass stuff for the JS side. ["#attached']['js_settings'] would be more telling IMO.

corbacho’s picture

IMHO drupalSettings key is consistent with the name of the core library, with the global variable window.drupalSettings, and it's widely used in all core javascript files. It makes sense fast, once that people start to work with D8.
The lower camel case format used, and being inside ['#attached'] already hints you that it must be JavaScript settings.
It's not totally clear, I agree, but better to be consistent than adding a new exception.

Wim Leers’s picture

#49: see comments #4#11 for the reasoning. corbacho explains it quite well also, though :)

yched’s picture

The *lower camel case* format used, and being inside ['#attached'] already hints you that it must be JavaScript settings

camelCase is used in lots of non-JS contexts in Drupal 8, so camelCase is no hint for JS. Neither is #attached ?

But well, I see the patch also changes the 'settings' key in *.libraries.yml entries to 'drupalSettings'. Even there, it's not fully clear that those end up in JS, but well, consistency++.

Would be clearer IMO if window.drupalSettings was a jsSettings entry in the existing Drupal object, that way all code referring to 'jsSettings', including on the PHP side or in YAML files, would be pretty self-explanatory. Much larger change, though.

[edit: also, would keep hook_js_settings_alter() in touch with what it actually works on]

In short, still not fully convinced, but I'll shut up if it's just me :-)

nod_’s picture

We have to split drupalSettings and Drupal object because we want settings values available ASAP, we don't want settings depending on either jQuery or drupal.js and sometimes we want the JS settings but not the drupal.js file. See JavaScript settings moved from Drupal.settings to global drupalSettings variable.

And copying drupalSettings in Drupal.settings is just asking for trouble :p

corbacho’s picture

@yched you have a point. My argument there was invalid. I made a regex search \["[a-z]+[A-Z0-9][a-z0-9]+[A-Za-z0-9]* in D8 code base and there is many times (about 50% of the times) where camelCase associative keys are used, and it's not related to JS.

Still, I will go for consistency, drupalSettings is quite memorable and easier to identify as global object in the JS side. Not so much in PHP/YAML side true.

yched’s picture

[edit: crosspost with #54]

@nod_: OK, thanks for the explanation.

The hiatus of "the hook to alter 'drupalSettings' is hook_js_settings_alter()", which is the only name that makes sense for that hook, is IMO exactly symptomatic of the fact that from the POV of PHP code, what you do is "place settings for the JS side", not just "place settings" or "place Drupal settings".

So ideally we'd need something that :
- on the JS side, is namespaced to "drupal" somehow, but cannot be in the Drupal global
- on the PHP side, is namespaced with "js" somehow, since that's how PHP code sees it.

Just trying to reformulate the problem space in case this sparkles something with someone, but yeah, atm I must confess I have no better suggestion than the current patch...

almaudoh’s picture

FWIW, not trying to bikeshed, but I agree with @yched in #49 and #52. It's just for the record though and shouldn't hold up this patch.

Great work @WimLeers.

WimLeers++

Wim Leers’s picture

Issue tags: +TX (Themer Experience)

#55: I feel (and share) your pain, but it's the lowest pain we can choose :)

IMHO the fact that we can tell themers they can do this in their fluffiness theme trumps everything:

function fluffiness_page_attachments_alter(&$page) {
  $page['#attached']['library'][] = 'fluffiness/cuddly-slider';
  $page['#attached']['drupalSettings']['fluffiness']['cuddlySlider']['foo'] = 'bar';
}

Where 'bar' is some calculated value.

Then cuddly-slider.js will be able to access drupalSettings.flufiness.cuddlySlider.foo (and it will === 'bar').

(Copied verbatim from the themer asset docs at https://www.drupal.org/node/2216195.)

That super simple, crystal clear, 1:1 mapping, is what makes this worthwhile.

almaudoh’s picture

#55: How about drupalJsSettings?

yched’s picture

@Wim : sure, I totally see the other consistency benefits, no questions here :-)

drupalJsSettings / hook_drupal_js_settings_alter() - yeah, wouldn't that work ?

Having a JS variable say "I'm about JS" might seem redundant, but IMO it's in fact accurate, if you consider that Drupal is a PHP-first tool, and is thus completely entitled to have a "component for passing settings to the JS side, that is implemented by code in both PHP and JS working hand in hand". When seen from JS code, well yeah, it's the JS part of "the drupal system handling JS settings".

Wim Leers’s picture

drupalJsSettings in PHP <> drupalSettings in JS.

This is a mismatch. The clear 1:1 mapping is lost.

To make it a bit clearer again, it'd need to be something like jsDrupalSettings. But the 1:1 mapping would definitely be lost. That's AFAICT the main reason nod_, Fabianx, catch and corbacho are on board.


On the JS side "Drupal settings" makes sense, but in PHP you'd think it's settings.php- or CMI-related. So perhaps all of this points to the fact that "settings" is actually a misnomer. Often, the data in drupalSettings are not so much settings as it's state data (current request info, current user), metadata (about entities/fields), or specific configuration for a generic feature (slideshows).
But no matter what, I think you'd always need to clarify on client side that it's coming from the server and on the server you'd need to clarify that it's for the client. At least I can't think of a word/description that'd be usable on both sides without mentioning the other side.

catch’s picture

@Wim I think yched means using drupalJsSettings both in PHP and JavaScript - so renaming drupalSettings.

That's even more of an API change here - but also JavaScript is far from frozen at this point and any module setting it's own settings will have to update after this lands anyway.

I don't have a strong opinion on the naming. I do agree that drupalSettings is definitely the least worst option until #59 so would be fine doing that if we eventually decide on it, and also think it's worth discussing this a bit longer so we don't regret missing an option later.

nod_’s picture

The constraints on the JS side are:

  1. Not in the global Drupal object (or we'd need to change what the Drupal is, not a fan).
  2. Has to be obvious the object is not part of some other JS library and won't conflict. Some have messed up names so it can be hard to find
  3. Ideally, has to be recognizable as coming from Drupal (with drupal in the name somewhere)

drupalSettings isn't great but to me better than backendJsSettings, drupalJsSettings is even longer and uglier with a capitalization on th "JS" that kinda make my eyes bleed. But if consistency win, so be it. It all get minified anyway.

Wim Leers’s picture

Issue summary: View changes

If you're here to provide feedback: please read the issue summary and then jump to #49! Everything before you can ignore (the relevant comments are linked to from #49 and later).

Wim Leers’s picture

lauriii’s picture

That's a really nice change and as a themer I can say this definitely improves the experience. Adding JS settings has been pita since forever. I think this doesn't only make it easier to use but also easier to understand. Also hook_js_settings_alter() seems to be a good improvement at least from my perspective.

I'm not 100% happy with the name drupalSettings because it's not the most descriptive. However I couldn't find or figure out anything better for this so I don't have any suggestions.

Good job everyone!

corbacho’s picture

There is no much freedom to choose names. Although it's verbose, I think drupalJsSettings is accurate and explicit. It:
* Must contain word Drupal (nod_ #62)
* Must contain a reference to JavaScript or JS
* will be nice that is "settings",(no 'config' for example) because then will make sense when using hook_js_settings_alter ( yched #52 )
So drupalJsSettings seems to be the only candidate that ticks all the boxes. Or jsDrupalSettings (ugly)

Repeating the code from Wim at #57:

function fluffiness_page_attachments_alter(&$page) {
  $page['#attached']['library'][] = 'fluffiness/cuddly-slider';
  $page['#attached']['drupalJsSettings']['fluffiness']['cuddlySlider']['foo'] = 'bar';
}

In JS:
drupalJsSettings.flufiness.cuddlySlider.foo

star-szr’s picture

+1 to making it a separate asset type, I've felt the pain as well. I like that the proposed name (drupalSettings) is the same on both ends.

To me the greater problem with regards to naming may actually be with render arrays and the difficulty documenting them. If there was a standard way to document the possible sub-keys of #attached then to me the array key name on the PHP side is much less of a concern, as long as the asset types are easy to look up.

Fabianx’s picture

What about:

  $page['#attached']['js.drupalSettings']['fluffiness']['cuddlySlider']['foo'] = 'bar';

window.drupalSettings.flufiness.cuddlySlider.foo

I think with the prefix "js." we do not confuse too much, say it is JS related and still keep the namespace pretty clear.

hook_js_settings_alter() could indeed be hook_js_drupal_settings_alter() then and it would all feel pretty good.

yched’s picture

re @Wim #60

drupalJsSettings in PHP <> drupalSettings in JS.

Right, no, it has to be the same name on both sides of course. i think drupalJsSettings works.

perhaps all of this points to the fact that "settings" is actually a misnomer. Often, the data in drupalSettings are not so much settings as it's state data

Agreed that it's about "data" more than "settings", but yeah, I don't think that changes much on the current naming issue.

But no matter what, I think you'd always need to clarify on client side that it's coming from the server and on the server you'd need to clarify that it's for the client

Yep, it's a mirror :-)
But my reasoning with drupalJsSettings working on both sides is that :
- it is more important to disambiguate "this is about JS" on the PHP side, as hook_js_settings_alter() shows. Drupal is primarily about PHP, so unless somthing explicitly states it's about JS, then you assume it's about PHP - which is why hook_drupal_settings_alter() wouldn't work.
- On the JS side, "this comes from the server" is somewhat carried by "drupal" : in drupal, things come from php on the server, where would they come from otherwise ? (well, local storage I guess - but we don't have a specific drupal API/layer for that, right ?)
In other words, much less ambiguity to worry about on the JS side IMO.

vijaycs85’s picture

+1 to this improvement.

Reg: drupalSettings name - I don't really mind *the name* considering what we have now and surely we won't regret in future (touch wood) because of this name :)

catch’s picture

Status: Reviewed & tested by the community » Fixed

OK I thought about this a bit more and discussed briefly with Alex Pott and Wim Leers in irc.

- drupalSettings we've already changed and it's close to Drupal.settings in 7.x. Existing JavaScript that already uses settings provided by core won't need to update if we keep it the same (probably a tiny number either way though).
- #attached will only have library and drupalSettings by the time we're done here, that's only two things to figure out so it's already much more learnable than Drupal 7. The fact it's in #attached at all makes it obvious it's a front end thing (once you know what #attached itself is for).
- I like the consistency of drupalJsSettings between js and PHP, but it comes at the cost of redundancy in JavaScript. Also visually the lowercase l and upper case J make it hard to look at and have me second guessing the spelling for typos. nod_ alluded to a similar thing.
- that leaves hook_js_settings_alter() in the cold a bit, but hook_js_settings_alter() doesn't match drupalJsSettings in terms of googling/grepping anyway, and it's a rarely used hook.

So... I'm going to go ahead and commit this as is. Committed/pushed to 8.0.x, thanks!

yched’s picture

Fine with the decision, doesn't reduce the awesomeness of this patch anyway :-)
@Wim++

corbacho’s picture

Great!
That was a sensitive balance and decision.
Wim++

yoroy’s picture

This seems to have caused #2388215: Tests for Drag and drop

jibran’s picture

hass’s picture

vijaycs85’s picture

@hass yep, it is Working as designed (WAD). Check the change notice for more details.

hass’s picture

It's a design flaw and these change notice does not document what I'm doing.

Status: Fixed » Closed (fixed)

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