DEV: Migrate discourse core to Ember initializers#22095
Conversation
There was a problem hiding this comment.
This is very fishy – not just because it's accessing the private __container__ property, but in general, accessing the container and instantiating objects in an application initializer before the app instance has been created is highly suspicious/likely incorrect. That being said, it's exactly what the current code is already doing, so this is just exposing an existing problem.
There was a problem hiding this comment.
This is again highly suspicious – the service will likely have an incorrect owner, and may get leaked/cached inappropriately beyond the application instance's lifetime.
There was a problem hiding this comment.
This file is moved to app/assets/javascripts/discourse/app/instance-initializers/register-service-worker.js but git lost track of it
There was a problem hiding this comment.
owner.__container__.registry is suspicious but it's again what the code already does now
There was a problem hiding this comment.
This is fishy per above, but this is what the existing code does and changing it causes issues
There was a problem hiding this comment.
This file is moved. The function used to take the owner as the first argument, but it's unused so I removed it.
There was a problem hiding this comment.
This assumes this "class" isn't "subclassed" and/or this.container isn't meant to be public
There was a problem hiding this comment.
Not necessary since setOwner uses a WeakMap internally
There was a problem hiding this comment.
this.keyTrapper is always nulled out together with this.container in teardown so this check is redundant
There was a problem hiding this comment.
The container argument is unused for a while and this assumes this function is internal and ok to change
There was a problem hiding this comment.
This assumes this class isn't subclassed and/or this.container isn't meant to be public
There was a problem hiding this comment.
No longer necessary with the WeakMap implementation
There was a problem hiding this comment.
This assumes:
- This is the canonical source for the
chatplugin (i.e. it's not a vendored copy from somewhere else) - The initializer modules aren't meant to be public APIs and this is the only place that does it
Otherwise we'll have to make a no-op initializer in discourse/initializers/onebox-decorators to re-export the function to preserve compatibility
There was a problem hiding this comment.
I've checked all the theme/plugin codebases we're aware of, and I don't see any occurrences of the string 'onebox-decorators', so I think we're good to proceed here 👍
https://meta.discourse.org/t/updating-our-initializer-naming-patterns/241919 For historical reasons, Discourse has different initializers conventions than standard Ember: | Ember | Discourse | | | initializers | pre-initializers | runs once per app load | | instance-initializers | (api-)initializers | runs once per app boot | In addition, the arguments to the initialize function is different – Ember initializers get either the `Application` or `ApplicationInstance` as the only argument, but the "Discourse style" gets an extra container argument preceding that. This is confusing, but it also causes problems with Ember addons, which expects the standard naming and argument conventions: 1. Typically, V1 addons will define their (app, instance) initializers in the `addon/(instance-)initializers/*`, which appears as `ember-some-addon-package-name/(instance-)initializers/*` in the require registry. 2. Just having those modules defined isn't supposed to do anything, so typically they also re-export them in `app/(instance-)initializers/*`, which gets merged into `discourse/(instance-)initializers/*` in the require registry. 3. The `ember-cli-load-initializers` package supplies a function called `loadInitializers`, which typically gets called in `app.js` to load the initializers according to the conventions above. Since we don't follow the same conventions, we can't use this function and instead have custom code in `app.js`, loosely based on official version but attempts to account for the different conventions. The custom code that loads initializers is written with Discourse core and plug-ins/themes in mind, but does not take into account the fact that addons can also bring initializers, which causes the following problems: * It does not check for the `discourse/` module prefix, so initializers in the `addon/` folders (point 1 above) get picked up as well. This means the initializer code is probably registered twice (once from the `addon/` folder, once from the `app/` re-export). This either causes a dev mode assertion (if they have the same name) or causes the code to run twice (if they have different names somehow). * In modern Ember blueprints, it is customary to omit the `"name"` of the initializer since `ember-cli-load-initializers` can infer it from the module name. Our custom code does not do this and causes a dev mode assertion instead. * It runs what then addon intends to be application initializers as instance initializers due to the naming difference. There is at least one known case of this where the `ember-export-application-global` application initialize is currently incorrectly registered as an instance initializer. (It happens to not use the `/addon` folder convention and explicitly names the initializer, so it does not trigger the previous error scenarios.) * It runs the initializers with the wrong arguments. If all the addon initializer does is lookup stuff from the container, it happens to work, otherwise... ??? * It does not check for the `/instance-initializers/` module path so any instance initializers introduced by addons are silently ignored. These issues were discovered when trying to install an addon that brings an application initializer in discourse#22023. To resolve these issues, this commit: * Migrates Discourse core to use the standard Ember conventions – both in the naming and the arguments of the initialize function * Updates the custom code for loading initializers: * For Discourse core, it essentially does the same thing as `ember-cli-load-initializers` * For plugins and themes, it preserves the existing Discourse conventions and semantics (to be revisited at a later time) This ensures that going forward, Ember addons will function correctly.
3f03a27 to
e30a31e
Compare
|
@davidtaylorhq @cvx I think this is ready for review. There is one failing test – is that known to be flaky? I vaguely recall the same test was passing in a previous run (had to push some changes). I did not bundle the deprecations for the plugins in this pull request. In additional to the naming differences the arguments are also different, if we are going to go through the trouble of deprecating the legacy version, we should probably take care of that too, either by removing the argument or wrapping it in some kind of discourse-specific API (e.g. |
davidtaylorhq
left a comment
There was a problem hiding this comment.
This looks great to me, thanks for the detailed description and comments @chancancode!
Gonna let @cvx take a look as well, then we should be good to merge.
| @@ -1,9 +1,6 @@ | |||
| export default { | |||
| name: "sniff-capabilities", | |||
| after: "export-application-global", | |||
There was a problem hiding this comment.
Forgot to mention about this (and a few other instances of the same thing):
"export-application-global" (from ember-export-application-global) is actually an application initializer that was incorrectly run as instance initializer with the previous setup.
With that fixed now (fixing that itself could have caused issue and worth calling out), this now errors because there is no instance initializer with that name. Since application initializers are guaranteed to have already run, and "export-application-global" itself has no other ordering dependencies, I figured I could just remove all of these, and as far as I can tell it didn't cause any problems.
| @@ -1,11 +1,8 @@ | |||
| import { loadSprites } from "discourse/lib/svg-sprite-loader"; | |||
|
|
|||
| export default { | |||
| name: "svg-sprite-fontawesome", | |||
| after: "export-application-global", | |||
| @@ -13,15 +13,12 @@ import Ember from "ember"; | |||
| const showingErrors = new Set(); | |||
|
|
|||
| export default { | |||
| name: "theme-errors-handler", | |||
| after: "export-application-global", | |||
| @@ -31,8 +31,6 @@ function animatedImgs() { | |||
| } | |||
|
|
|||
| export default { | |||
| name: "animated-images-pause-on-click", | |||
There was a problem hiding this comment.
The file is renamed to match this name during the move
| @@ -1,5 +1,6 @@ | |||
| import "./global-compat"; | |||
|
|
|||
| import require from "require"; | |||
https://meta.discourse.org/t/updating-our-initializer-naming-patterns/241919
For historical reasons, Discourse has different initializers conventions than standard Ember:
In addition, the arguments to the initialize function is different – Ember initializers get either the
ApplicationorApplicationInstanceas the only argument, but the "Discourse style" gets an extra container argument preceding that.This is confusing, but it also causes problems with Ember addons, which expects the standard naming and argument conventions:
Typically, V1 addons will define their (app, instance) initializers in the
addon/(instance-)initializers/*, which appears asember-some-addon-package-name/(instance-)initializers/*in the require registry.Just having those modules defined isn't supposed to do anything, so typically they also re-export them in
app/(instance-)initializers/*, which gets merged intodiscourse/(instance-)initializers/*in the require registry.The
ember-cli-load-initializerspackage supplies a function calledloadInitializers, which typically gets called inapp.jsto load the initializers according to the conventions above. Since we don't follow the same conventions, we can't use this function and instead have custom code inapp.js, loosely based on official version but attempts to account for the different conventions.The custom code that loads initializers is written with Discourse core and plug-ins/themes in mind, but does not take into account the fact that addons can also bring initializers, which causes the following problems:
It does not check for the
discourse/module prefix, so initializers in theaddon/folders (point 1 above) get picked up as well. This means the initializer code is probably registered twice (once from theaddon/folder, once from theapp/re-export). This either causes a dev mode assertion (if they have the same name) or causes the code to run twice (if they have different names somehow).In modern Ember blueprints, it is customary to omit the
"name"of the initializer sinceember-cli-load-initializerscan infer it from the module name. Our custom code does not do this and causes a dev mode assertion instead.It runs what then addon intends to be application initializers as instance initializers due to the naming difference. There is at least one known case of this where the
ember-export-application-globalapplication initialize is currently incorrectly registered as an instance initializer. (It happens to not use the/addonfolder convention and explicitly names the initializer, so it does not trigger the previous error scenarios.)It runs the initializers with the wrong arguments. If all the addon initializer does is lookup stuff from the container, it happens to work, otherwise... ???
It does not check for the
/instance-initializers/module path so any instance initializers introduced by addons are silently ignored.These issues were discovered when trying to install an addon that brings an application initializer in #22023.
To resolve these issues, this commit:
Migrates Discourse core to use the standard Ember conventions – both in the naming and the arguments of the initialize function
Updates the custom code for loading initializers:
ember-cli-load-initializersThis ensures that going forward, Ember addons will function correctly.