Problem/Motivation
#2918868: [policy, no patch] Use a deprecation process for JavaScript similar to what we use for PHP code decided on a standard for documenting deprecated JavaScript code: https://www.drupal.org/core/deprecation#javascript.
The next step is to document a consistent way to trigger deprecation notifications on JavaScript deprecations to notify developers that deprecated code is being used. The error should be clearly visible to developers, and there most likely should be a way to silence the notifications on production environment.
Proposed resolution
Provide Drupal.deprecationWarning
and Drupal.deprecateProperty
functions for marking classes, methods and properties as deprecated. Provide new Drupal setting suppressDeprecationWarnings
for suppressing JavaScript deprecation warnings.
Remaining tasks
Agree how to trigger errorsJavaScript maintainer @justafish signed off on this in #11 + #13.- Document that on the Drupal core deprecation policy
API changes
Three API additions:
drupalSettings.suppressDeprecationErrors
, which defaults totrue
. This ensures JS deprecation errors are not triggered on production sites. Can be modified usinghook_js_settings_alter()
Drupal.deprecationError
, to trigger a deprecation error when they're not suppressed. For use in JS functions.Drupal.deprecatedProperty
, to decorate properties that are deprecated, to allowDrupal.deprecationError
to be called automatically when deprecation errors are not suppressed.
The second and third are what developers writing JS should use to deprecate.
The first is what developers can use to either surface or suppress deprecation errors.
Release notes snippet
JavaScript code can now also trigger deprecation errors using newly added APIs (Drupal.deprecationError
and Drupal.deprecatedProperty
). JavaScript deprecation errors are exposed using console.warn
. By default, JavaScript deprecation errors are suppressed. See https://www.drupal.org/core/deprecation#javascript for more details.
Comment | File | Size | Author |
---|---|---|---|
#68 | 3070521-77.patch | 24.82 KB | tedbow |
#68 | interdiff-66-67.txt | 759 bytes | tedbow |
#66 | 3070521-66.patch | 24.75 KB | tedbow |
#66 | interdiff-63-66.txt | 739 bytes | tedbow |
#63 | 3070521-63.patch | 24.69 KB | tedbow |
Comments
Comment #2
lauriiiComment #3
lauriiiComment #4
Wim LeersComment #5
Wim LeersThis looks like a great start! 😃
Points 1 and 2 review the key parts of what #3 proposes, the other points look at the impact of those points and the bigger picture.
A method for triggering a deprecation warning using the console.
There is a suppression mechanism, which is turned on by default.
👍 Seems reasonable.
🤔 Primary question: why "deprecation warning" and not "deprecation error"? That's what it's called everywhere else.
This then is a helper to make it easy to declare deprecated properties, because they me be declared in places where that declaration cannot be followed by a function call (to
Drupal.deprecationWarning()
).👍 Makes sense.
🤔 I think
Drupal.deprecatedProperty()
makes slightly more sense? What is your reasoning for this naming?🤔🤓 I'm wondering if we want a proxy-based approach just like you have for the property, because that would allow us to not have to reformat (indent) existing function definitions?
🤔 IMHO this should link to https://www.drupal.org/core/deprecation#javascript
🤔 It's very important here to turn on deprecation warnings (errors?) when it makes sense.
I'm sure that's something for a future patch iteration.
Comment #7
lauriiiThanks for the review! ✌️
#5.1 Interesting observation! I feel like deprecation warning is more accurate since these are not actual errors, but warnings that deprecated code is being called. I did very non-scientific research by using Google to search for "deprecation error" which found 9000 results, as well as for "deprecation warning" which found over 200 000 results leading into believe that deprecation warning is a more commonly used term. However, since we're already using the deprecation error term more frequently in core, I changed these to deprecation error.
#5.2 The proposal makes sense. The function isn't actually deprecating anything but it's helping to mark it as deprecated so that the warning can be triggered.
#5.3 In my opinion, it's better to directly call the function to trigger a warning whenever possible since it results in simpler code. If you look at the compiled code, you can see how minimal the change actually is.
#5.4 👍
#5.5 I actually just hardcoded the value since I wasn't sure what should be the rule to turn deprecation warnings on. Should it be something that a module could override or should there be a configuration in core to turn off the suppression?
Comment #8
Wim LeersYep, that's fair. I only thought of it because there is a helper method for properties, so we might want one for functions too. Then again, for properties it's necessary (for the reasons I provided), for functions it's not.
Yeah, good question. I'm inclined to say "if PHP assertions are turned on, you want this to be turned on too". But that's not necessarily true: PHP assertions matter to back end developers, JS deprecations matter to front end developers, you only want both if you're working on both ends simultaneously.
I'm afraid this goes back to #1537198: Add a Production/Development Toggle To Core, which has been an unsolved problem for more years than I'd like to know 🙃
Comment #9
zrpnrThese methods for logging warnings in the console seem like an ideal approach. I did some research into how React displays warnings in strict mode, and how other js libraries handle deprecations. Logging to the console is standard since there isn't a native feature of the language. Typically with a React app where there is a compile step the "production" build won't display these kind of developer notices. That's not an option for Drupal though since the compiled files are the ones that get loaded and used.
I agree that php assertions and js deprecations shouldn't be connected, but what about something more user friendly like the "Logging and Errors" config? I think it's
system.logging.error_level
.This could just be TRUE only for
error_level: hide
so that the warnings would always appear unless deliberately suppressed.We want developers to notice these warnings, but to be easily suppressed by setting this option to "none" on production.
I think most developers or site builders would think to go here (admin/config/development/logging) first if they wanted to hide those console warnings.
I was curious to see how the compiler handled this, but it is still using
Proxy
. I don't think Proxy is supported by IE 11 since it is an ES6 feature of javascript.Likewise:
Reflect is also not supported in IE11.
Comment #10
justafishComment #11
justafishThis is cool 👍
Is there a reason deprecationError is a regular function() and deprecatedProperty is an arrow function?
You could also use console.trace instead of console.warn, so it's easier to find where the message was triggered and doesn't mean you need to rely so much on the error message text.
I prefer to pass objects through to functions in JavaScript, it's much more flexible if you want to expand later. I'd also set default values where possible.
Comment #12
lauriiiI disabled this when Proxy or Reflect isn't supported which seems fine to me since this is a developer-facing feature so it might be safe to assume that they're not running IE 11.
There was no reason. I was supposed to convert both of them into arrow functions but somehow got just into half way with that 🤣 I converted all functions to use arrow functions.
I would prefer using
console.warn
because it makes deprecations much more visible. Also, some browsers provide trace even for warnings 😇👍
I don't think we can set reasonable default values. Drupal has this whole document about the format of deprecation warning messages. Setting a default value could encourage people to break that pattern 🤠
Comment #13
justafishLooks good (assuming the tests pass)! 💃
Comment #14
Wim LeersYay! Thanks, @justafish! :)
I agree that the JS side of things here looks ready, but I think we should consider implementing @zrpnr's suggestion too:
Or if we don’t, at least open a follow-up for it.
Comment #15
lauriiiI'm not sure if we should use the "Error messages to display" configuration for this since it explicitly mentions displaying them. If we do decide to use it, I think we should add mention to the UI that the setting affects JavaScript deprecations warnings displayed in the console as well. We were planning to use that setting #2987444: Ajax errors are not communicated through the UI but it's slightly different since it actually displays errors in the UI.
Comment #16
Wim LeersSo we still need a follow-up to determine a smarter default for
suppressDeprecationErrors
. But since this issue is at least major (or is it critical?), we should go ahead and get this committed ASAP.Comment #17
lauriiiAdjusted one of the deprecation warning messages.
Comment #18
zrpnrThat's a good point, very unlikely developers would be working using IE11, but the additional check you added is an improvement and an additional safeguard if warnings were accidentally left enabled on production.
+1 for passing objects to the functions, and using arrow functions everywhere!
Should we remove the
@todo Add deprecation warning after it is possible
from the docblock aboveDrupal.theme.ajaxWrapperNewContent
andDrupal.theme.ajaxWrapperMultipleRootElements
as part of this patch?Created #3082404: Follow-up to #3070521 Provide option to enable javascript deprecation warnings
I agree that this feature should not block this issue.
This is still RTBC since the latest patch was a small change and tests pass, nice work @lauriii !
Comment #19
lauriiiMoved setting the
suppressDeprecationErrors
default value tocore.libraries.yml
to allow modules to use the alter function to override this. I also rengerated the compiled JS because it seems like I forgot to do that for #17.Comment #20
lauriiiI also opened change records for this.
Comment #21
Wim Leers👍 WHY DID I NOT THINK OF THIS!?
But … it's not in the patch?
Comment #22
lauriiiIgnore patch in #19, this is the right patch.
Comment #23
Wim LeersPerfect.
I think I even worked on adding the default
drupalSettings
tocore.libraries.yml
way back when … yep: #2382557: Change JS settings into a separate asset type. This looks perfect now.Comment #24
xjmI wonder if it would be best to merge the two change records for this? I think the information on how to suppress the messages could be added at the end of https://www.drupal.org/node/3082634.
Comment #25
larowlanFor #24
Comment #26
lauriiiThe reason for splitting them into separate change records was that the information on these change records is targeted to different groups of people. I'm fine with moving them into a single change record if other people prefer that approach.
Comment #27
lauriiiI discussed this with @xjm and as a result, I merged the change records. Moving back to RTBC.
Comment #28
xjmI still need my release note. :)
Comment #29
xjmComment #30
xjmProbably we should tick all the boxes here since this significantly blah blah blah. :) Lauri has already signed off so I didn't add that tag.
Comment #31
Wim LeersComment #32
larowlanI'm happy with this - I reviewed it back in #25 and only had questions about the change records. But I realise I didn't actually say 'this looks good' or anything like that.
Comment #33
tedbowI chatted with lauri and he suggested we needed a way to get deprecation messages in our FunctionJavascript phpunit tests if deprecated JS functions are called.
Here is a try at that.
This starts from some work lauri had done after #22
Comment #34
tedbowWe store the warning in localstorage because there may be calls on previous pages and we need to be able evaluate at the end of the test if any JS deprecated calls were made.
Here we test for a know deprecation message
We have to always have this test module enabled because it intercepts the calls to
console.warn()
to ensure that for all calls across across all page loads in test we will detect deprecated JS calls.@lauriii made all the changes to the nightwatch stuff so I will let him explain those.
Comment #35
lauriiiWe will still have to make the Nightwatch tests use the new test module to follow deprecation warnings in a more consistent way. This should fix some of the test failures. The patch also still contains some code from #3084698: Add console logs to all Nightwatch tests to make debugging easier.
Comment #36
lauriiiSince we haven't silenced any deprecations as part of this, I assume some of the JavaScript deprecations we add here should actually be triggered. Let's see if this helps.
Comment #37
Wim Leers✅
👎Why these changes?this was in #35, but fixed in #36 :)Comment #39
lauriiiAdded new assertion to Nighwatch to check if deprecations have been triggered. ✌️For now, this has to be manually run in every test case but we could add it to afterEach if we wanted to.
Let's move deprecating actual production code to follow-up to make sure we have at least this in prior to 8.8.0-alpha1.
Comment #40
Wim LeersI think this is the right call. 👍
✅ Sample deprecated JS function.
✅ Sample deprecated JS property.
✅ Using both deprecated pieces of code. This triggers the deprecation errors.
✅ This allows the JS deprecation errors to actually show up.
🤔 Ohhhh! I did not expect this. But I think it might make sense. 👍 We need JS deprecation errors to be surfaced in all our functional tests, just like PHP deprecation errors.
Worth nothing: this means that this won't work in other install profiles, like
standard
,demo_umami
, or Drupal distributions like Thunder or Lightning. Do we believe that's okay?Shouldn't we move this to
\Drupal\FunctionalJavascriptTests\WebDriverTestBase
instead?Why is that not possible?
🤓 Übernit: Missing doc.
✅ This proves deprecations are surfaced in tests 🥳
✅ This maps JS deprecation errors to PHP deprecation errors, so our existing testing infrastructure can surface it! 👏
✅ And this allows nightwatch JS tests to ensure there are no deprecation errors either.
I would have RTBC'd this, but I think point 5 needs more discussion still.
Comment #41
lauriiiWe need that for Nighwatch tests as well, which doesn't use
\Drupal\FunctionalJavascriptTests\WebDriverTestBase
. Maybe we should install it in both,\Drupal\FunctionalJavascriptTests\WebDriverTestBase
andtesting
installation profile.Comment #42
lauriiiHere's code for what I suggested in #41 and this should also fix the failing test.
Comment #44
lauriiiComment #45
Wim Leers+1
So we need it in
testing
to make it work for Nightwatch tests. We need it inWebDriverTestBase
so that it works in all functional JS tests.Arguably, we shouldn't add it to
testing
, and instead add anightwatch_testing
install profile instead. Because it's possible and even likely that there are more customizations necessary for Nightwatch tests. Furthermore, arguably it does not make sense to have thepage_cache
anddynamic_page_cache
modules installed for Nightwatch tests, since Nightwatch tests are solely about client side testing, not about server-side responses and their cacheability.Together, that means I'm implicitly proposing
nightwatch_testing.info.yml
to look like this:Comment #46
lauriiiAddressing #45.
Comment #47
Wim Leers🥳 This ensures that Nightwatch tests install Drupal with this new
nightwatch_testing
install profile. 👍🤓 Still the same nit as in #40.6.
This is no longer necessary AFAICT? 😊Ah no, the install profile installsjs_deprecation_log_test
(which results in the logging), this is installingjs_deprecation_test
which intentionally triggers deprecation errors so we can test it. 👍🤔 Why do we need to add this wait now? This seems like a debug leftover?Oh … this is to allow the JS deprecation errors to have been triggered prior to us asserting there are no JS deprecation errors. 👍Comment #48
Wim LeersThis needed a follow-up for #39. Done: #3085926: Deprecate Drupal.theme.ajaxWrapperNewContent + Drupal.theme.ajaxWrapperMultipleRootElements.
Comment #49
Wim LeersIssue summary updated:
Credited @zrpnr for his review in helping validate the approach. Also credited @tedbow for his crucial help in writing test coverage for this.
Comment #50
Wim LeersChange record added: https://www.drupal.org/node/3085933
EDIT: d'oh that already existed at https://www.drupal.org/node/3082634. Merged my text into @lauriii's. Keeping it around for now, to retain the history. Once Lauri's is published, mine can be deleted. 🤓
Comment #51
Wim LeersUpdated documentation at https://www.drupal.org/core/deprecation#javascript: https://www.drupal.org/node/2856615/revisions/view/11570944/11590225
Comment #52
tedbow#46 failed because the tests switch to stark from classy and there was 1 css selector that didn't exist anymore.
Fixed
Comment #53
lauriiiThis brings up a concern that this might break contrib / custom tests given that we're changing the testing theme. I grepped contrib projects to make sure that this doesn't break anything there, and I couldn't find any usages of Nighwatch there. A change record probably wouldn't hurt anyway.
Comment #54
Wim Leers✅ https://www.drupal.org/node/3085950
Comment #55
larowlanChromeDriver has a very long-lived cache (in my experience), should we be removing the items from localStorage after each test to prevent pollution of subsequent tests?
Comment #56
Wim LeersOh, that's a very interesting remark!
Can't we just use
sessionStorage
instead? That is cleared for every new tab and window by definition :)Comment #57
tedbowthis should be
const
This line is update when I run
yarn prettier
. Maybe I didn't run it on last patch?Ran prettier.
This be a arrow function
This should be an arrow function
Comment #58
tedbowmy #57.3 & 4 changes broke the tests. I will defer @lauriii on this and assume his version was actually correct.
Comment #59
Wim LeersHurray! :)
Comment #60
larowlan+1 RTBC
Comment #61
catchCan't really do a meaningful review of the js here as such, but the change record looks good to me, and fine with the nightwatch switching to stark change.
Explicitly tagging with 'needs documentation updates' which should happen asap once this is committed (or could probably happen just before too).
Comment #62
larowlanThe pre-commit hooks complain about this patch
Comment #63
tedbow@larowlan sorry about that.
I did
prettier didn't make any changes
Hope this passes
Comment #64
Wim Leers14 times
caused this test to be marked as
despite all tests passing. This is a pre-existing and known issue with DrupalCI + eslint tooling.If I try to commit #63 locally with
d8githooks
, it does pass all tests:Comment #65
alexpottSo nightwatch tests are broken. Not the nicest reporting from DrupalCI :(
Comment #66
tedbowSorry all. Was having some issue with linting breaking the tests.
We can't use an arrow function here. So I excluded this line from linting
Comment #67
Wim LeersLots of errors like this reported by DrupalCI:
Ran nightwatch tests locally. They do not pass. 😭 I'm getting a mysterious error. It passes for @lauriii and @tedbow. So we got on a call together, and discovered this:
2 assertions, should be 4! This is also happening for Lauri & Ted.
Ted is momentarily going to upload a new patch that fixes the problem!
Comment #68
tedbowThis exact change needed to happen in
core/tests/Drupal/Nightwatch/Assertions/deprecationErrorExists.js also
Comment #69
lauriiiNightwatch--
#68 should address this problem. 🙏 This is something I run into when I was working on building these assertions in the first place. Moving this back to the RTBC queue. 🚢
Comment #70
Wim LeersRTBC confirmed, #68 passes locally for me 🥳
Comment #71
larowlanComment #72
larowlanCommitted 1b0c006 and pushed to 9.0.x. Thanks!
c/p to 8.8 and 8.9
Comment #76
larowlanOh: reminder - can we get those documentation updates please kind folks?
Comment #77
xjmpiles on as the third committer asking for docs updates
Yes please!
Also, this and the original new coding standard for JS deprecations should go in the release notes (together).
Comment #78
Wim Leers@larowlan & @xjm: I already did that more than a week ago, see #51 :)
EDIT: ah, @catch tagged this #61, 4 days after I already did it. That's why the tag was still here.
inComment #79
xjmhttps://www.drupal.org/core/deprecation#javascript actually still is incomplete, so setting NW so that we don't lose track of it.
Comment #80
lauriiiAdded some more documentation: https://www.drupal.org/node/2856615/revisions/view/11590225/11610589. 😇