Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Support for ES accessor Decorators #876

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

chriskrycho
Copy link
Contributor

@chriskrycho chriskrycho commented Nov 29, 2022

Rendered


Summary:

Introduce support for the ECMAScript Decorators Proposal for the key decorators which are part of Ember’s modern programming model, @service and @tracked:

import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking/accessor';
import { service } from '@ember/service/accessor';

export default class Example extends Component {
  @service accessor someService;
  @service('named') accessor anotherService;
  @tracked accessor someLocalState = 123;
}

We will provide new imports to support these, a codemod to migrate to the new form, and guidance for both app and addon users about how to manage the transition.

@github-actions github-actions bot added the S-Proposed In the Proposed Stage label Nov 29, 2022
@chriskrycho chriskrycho changed the title RFC: Support for ES 'accessor' Decorators RFC: Support for ES accessor Decorators Nov 29, 2022
@chriskrycho chriskrycho self-assigned this Nov 29, 2022
```js
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking/accessor';
import { service } from '@ember/service/accessor';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will there be a future RFC to simplify imports?
we have a lot of different import paths now, and it seems this is rapidly growing over time

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm planning on an RFC (or set of RFCs, we'll see how it breaks down) that eliminates over 50% of the import paths. The mechanic for that won't surprise anyone: get rid of stuff we don't need anymore!


Decorators can then layer on top of this. This is more or less what `@tracked`, `@service`, etc. already do—but a spec decorator gets a very different argument, and behaves fairly differently than the legacy decorators implementation.

We *could* try to absorb that with a single overload, but that has a much higher risk of bugs *and* doesn’t give us any hooks for linting etc. Linting matters because we want to be able to tell people statically (not just with annoying Babel compile errors) that they *must* use `accessor` with this version instead.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a lint can read the package.json and see what version of package we'd have that supports this, and then autofix-insert accessor -- making the overload more reasonable, imo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is not just the consumer side, it's also the authoring side. Those overloads are already quite heavy, and adding more complexity there substantially ups the challenge of shipping non-buggy code. It's not impossible, but it's far easier to just codemod to the new thing and have much simpler lint rule maintenance as well.

It's also not possible to see purely from the package.json: we have to support both legacy and spec decorators, so "what version are we on?" doesn't answer the question. That lint rule would have to go parse babel.config.js and ember-cli-build.js, and/or boot Ember CLI to get the resolved result of the config.

}
```

We want to make sure not to couple *this* change—which just unlocks using the spec decorators—to *that* possibility, which isn’t finalized. We also want this to be trivially codemoddable, and we also plan to deprecate the existing decorators in a future deprecation RFC, so what we ship here is certainly only a transitional path: eventually, regardless of any `@glimmer/reactivity` package, the *primary* imports for these packages should be ES decorators, *not* the legacy decorators.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, I think I like where this is going

@chriskrycho chriskrycho added S-Exploring In the Exploring RFC Stage and removed S-Proposed In the Proposed Stage labels Dec 1, 2022
Co-authored-by: Katie Gengler <katie@kmg.io>
@wagenet wagenet added the E-Polaris Work for the Polaris Edition label Mar 23, 2023
@runspired
Copy link
Contributor

I think there is an alternative path here that may be more ideal in that it ought to enable the ecosystem to more rapidly convert.

  • a codemod is written to transform all legacy framework and ember-data decorator usage into accessors

    • the codemod should be able to dry-run
    • it should report any legacy decorator usage it finds that is not from framework or data decorators. Note per-ember policy non-framework decorators were never guaranteed support but we can still try to be helpful
    • it should allow transforming non-framework/data decorators as well, potentially based on a mapping
    • a matching eslint rule with an autofix should be prepared (not recommended ... yet)
  • a babel-transform is written to auto-convert all legacy decorators belonging to the framework and to ember-data into the new accessor pattern. Similar to the codemod, and eslint rule this should report legacy decorators that don't belong to the framework or data. Unlike the codemod / eslint rule we will error when we encounter one.

  • ember-cli-babel is updated to auto-include this transform, initially behind a feature flag. Since most apps run latest or close to latest ember-cli-babel and can pick up minors like this, we're able to get most apps in the ecosystem building with the ability to switch on compat fairly quickly.

  • we start flipping the switch.

Generally this will work for all v1 addons and apps. Get to a version of ember-cli-babel that supports the new decorators, turn on support, prepare non-framework/data decorators, ship it.

Where this gets a little dicey is v2-addons since while they still partially compile during app compile based on app babel config, we would want them to ship accessor versions as soon as feasible, even before apps have updated their ember-cli-babel.

For this I think we leverage ember-auto-import, which is currently responsible for their final transpilation: converting back from the stage 3 decorators when present if necessary, and doing nothing/leaving be if ember-cli-babel has been configured to use them. Generally most apps are close to latest on ember-auto-import in my experience, and have an easy time upgrading to new minors of it.

@chriskrycho
Copy link
Contributor Author

FWIW, I am totally fine with @runspired's alternative proposal here; I definitely do not have time to rewrite or drive it at the moment, but would be happy to see this RFC rewritten with that approach instead, or to close this in favor of a newly-opened RFC with that design.

@achambers
Copy link
Contributor

@ef4 Does it make sense for you to take this on as champion?

@ef4
Copy link
Contributor

ef4 commented Aug 18, 2023

Yes, I can champion, I expect that will involve doing a pass through the text and changing the place to one more similar to what @runspired is describing.

@ef4 ef4 assigned ef4 and unassigned chriskrycho Aug 18, 2023
@ef4
Copy link
Contributor

ef4 commented Mar 10, 2025

Status update on decorators: I expect to supersede this RFC with a rather different one that would offer a more graceful upgrade, because:

  1. We can actually keep field decorators working. They might become slower, and therefore it's still good to migrate to accessor decorators. But the migration could be gradual and you won't be blocked waiting for the very last field decorator in your app and addons to be converted. You might discover that old dark corners of your app don't need to be touched at all.

  2. We need to include all existing decorators in the plan, not just the modern happy-path ones. If @computed doesn't work on modern decorators, then we also have to deprecate and remove it before we can move ahead with this RFC, and that's a big lift. IMO, I think the future path for @computed is to make sure it's pay-as-you-go: it should be possible to make a new app that never pulls in the computed system, but we should keep it around for possibly forever, as an optional thing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
E-Polaris Work for the Polaris Edition S-Exploring In the Exploring RFC Stage
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants