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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[QUEST] 馃尣Project Trim 馃尣 #6166

runspired opened this issue Jun 18, 2019 · 6 comments


None yet
4 participants
Copy link

commented Jun 18, 2019

馃尣 Project Trim馃尣

As the Ember Community approaches delivery of long awaited features enabling tree-shaking, ember-data needs to take some steps to enable this feature to shed the weight of features that consuming applications do not use.

The first step is to ensure that the packages ember-data provides are properly encapsulated. In many cases, this will both enable support for tree-shaking once available to the broader community and enable manually opting for a subset of packages.

Later steps will ensure that ember-data relies on explicit imports (whether automatically generated at build-time or declared by consuming applications) where currently we rely on resolver lookups.

馃尣 Use ember-data without @ember-data/serializer

The serializer package provides reference serializer implementations and a base serializer class that are not required for applications that choose to write a custom serializer implementing the minimal serializer interface. This includes the EmbeddedRecordsMixin and the base Transform class.

Transforms, while specified via attr available from @ember-data/model are a concept specific to these reference serializers and not used anywhere else within ember-data. Custom serializers thus may or may not choose to use them via the same mechanism (owner.lookup('transform:<name>')). Lastly the Transform base class merely shows the interface required for transforms but is not required to be used as a base class.

Action Items

  • add a public Typescript interface for the minimal required serializer interface
  • eliminate registration of default transforms (use app re-exports instead)
  • eliminate injection of -default and -json-api serializer (use app re-exports instead)
  • deprecate -default serializer fallback in Store.serializerFor
  • deprecate Adapter.serializer and Adapter.defaultSerializer fallbacks (which currently default to -json-api.
  • deprecate Model.toJSON and support the scenario for quick debug-mode inspection via debugData() method which in DEBUG would print a similar object to the current toJSON method.

馃尣 Use ember-data without @ember-data/adapter

The adapter package provides reference adapter implementations and a base adapter class that are not required for applications that choose to write a custom adapter implementing the minimal adapter interface.

Action Items

  • add a public Typescript interface for the minimal required adapter interface
  • eliminate injection of -rest and -json-api adapter (use re-export pattern for -json-api adapter)
  • deprecate Store.defaultAdapter (-json-api) and the -json-api adapter fallback behavior
  • eliminate -rest adapter which is only available for tests at this point unless consumers manually call serializerFor('-rest').
  • cleanup minimum required adapter interface (ensure coalescing findBelongsTo and findHasMany methods are appropriately documented or guarded)

馃尣 Use ember-data without @ember-data/model

While at the time of writing this quest @ember-data/model is the only model class available for use with ember-data based on public APIs, the introduction of custom Model Classes will mean that users who install @ember-data/model alternatives via addon or by writing their own should be able to consume ember-data without using a package which provides a model implementation they do not use.

Enabling use without @ember-data/model requires much more groundwork than that needed for the adapter and serializer package.

Model Action Items

  • move the implementation of Model from the store package into the Model package.
  • move the implementation of @hasMany and @belongsTo into the Model package.
  • move -private/system/relationships/ext.js in @ember-data/store into the Model package
  • move the implementation of ManyArray and PromiseManyArray into the Model package. See RFC notes
  • move the implementation of PromiseBelongsTo into the Model package.
  • inject the Model specific _modelForMixin implementation into the store from the Model package (this provides the multi-inheritance polymorphism feature which some aspects of ember-data currently support).
  • deprecate BelongsToReference.push receiving a Model instance
  • polish off the implementation of the Identifiers RFC.
    • refactor conversion of Record to RecordIdentifier to occur within @belongsTo and @hasMany

InternalModel Action Items

  • Deprecate/shim intimate Reference.internalModel property
  • Refactor Store.getReference to not lookup the associated InternalModel to generate the reference.
  • Move the state-machine into the Model package.
  • Refactor store APIs to use identifiers instead of InternalModel
  • Implement RecordData Errors RFC
  • Implement Request State RFC.
  • Move InternalModel into the Model package.

InternalModel Cleanup Action Items

Once the items in InternalModel Action Items are complete, we can move the instantiation and lookup logic in the Store into the Model package.

  • create InternalModel only for @ember-data/model when using the instantiateRecord hook.
  • Eliminate any remaining Store._internalModelForId usage in favor of Identifier based logic.

馃尣 Use ember-data without @ember-data/relationship-layer

The relationship-layer package is currently deeply entangled with @ember-data/model's Model implementation. Even though we can encapsulate the imports to/from these packages, users would not be able to use @ember-data/model without also using @ember-data/relationship-layer. Additionally, in its current form the relationship-layer is not abstracted away from the specifics of the implementation of Model making is largely unusable with other Model implementations. Changes to address this are needed but are outside the scope of this quest, and until such time as they occur users wishing to drop this package would need to drop both this and the Model package together.

  • move everything within -private/system/relationships/state in @ember-data/store into a new relationship-layer package. See RFC notes
  • Move belongsToReference and HasManyReference into relationship-layer from store.
  • refactor usage of internalModel to pull information from the RecordIdentifier or the Store for type id hasRecord and getRecord()
  • introduce a private -request-manager service for the store to use to refactor our current network request flows onto
  • isolate relationship fetching logic (currently spread across dozens of private store methods) into a private middleware to be used by the private -request-manager service
  • isolate coalescing logic into a private middleware to be used by the private -request-manager service (related to relationships due to how some relationship codepaths flow through it, but should not be part of the relationship-layer package)

馃尣 Use ember-data without @ember-data/debug

Provides the DataAdapter for the ember-inspector

  • refactor to use service injection, kill initializer injection
  • refactor to manage own registration if still necessary
  • detect should not require Model
    • Custom RecordClass RFC should recommend something here

馃尣 Use ember-data without @ember-data/record-data

Provides the default RecordData implementation

  • move RecordData into this package
  • hook into store package to implement createRecordDataFor


  • kill createStore and setupStore
  • deprecate injection of -default serializer if moduleFor style tests are still supported
    • lazily register and the -default serializer when this condition is detected

馃尣 Tree Shaking Strategy

embroider is pursuing a strategy in which consuming applications opt in to enabling tree-shaking of specific kinds of features once they have determined for their own application that this is allowable.

To this end, users of ember-data would also opt in to tree shaking, possibly on a per-primitive basis.

Models - build time generated imports, nothing would be shaken except when possible for users opting into the "megamorphic model" case once that becomes available.

  • generation of static import file to keep embroider happy

Adapters/Serializers - in the near-term, deprecating various fallbacks will allow us to shake out the implementations provided by default once tree-shaking is enabled more generally. Here, as with models, we would generate at build time a list of the user's adapters as a list of static imports. Any default implementations not imported by user adapters would then be dropped.

In the long-term, adapters would be deprecated in favor of user-supplied network middlewares. Such middlewares, including those provided by addons, would be imported and registered with the request-manager service directly. Since these are static imports being registered to a service, in the long term no custom infrastructure would be needed to support tree-shaking.

Also in the long-term, serializers would be deprecated in favor of either their corresponding "adapter" replacement handling these concerns or in favor of middlewares specific to normalization and serialization concerns. Similarly, in the long term no custom infra for ensuring static imports for tree-shaking needs would be required.

  • generation of static import file to keep embroider happy
  • generation of static import file to keep embroider happy

Transforms - There are three ways for a user to utilize a transform today: attr(<transformName>), owner.lookup('transform:<transformName>') and direct import of a transform followed by Transform.create(). Of these, the third already plays nicely with tree-shaking. For attr and lookup usage we will need to enforce "static string usage" for lookup and and attr(), at which point we can use this to generate an import file of only those transforms that are actually in-use.

Also note, if none of the default serializers is in use and there is no project usage of lookup('transform:<transformName>') then it is likely we can drop all transforms even when referenced by attr.

  • deprecate non-static strings for lookup and attr
  • generation of static import file of lookup and attr transform usages

DefaultRecordData/DefaultModel - we would export our default setup within the app/ directory. An end user or addon configuring their own Model or RecordData would result in overriding this.

DebugAdapter - use DEBUG to drop in production unless otherwise specified

  • deprecate automatically shipping to production
  • enable optional shipping to production

馃尣 Tree Shake all of ember-data

  • deprecate defaultStore behavior in Ember
  • deprecate injected store on controller/route

@runspired runspired self-assigned this Jun 18, 2019

efx added a commit to efx/data that referenced this issue Jun 28, 2019

notify of deprecated methods
Noticed these still annotated with TODO and were not completed as part
of emberjs#4695. Fixing this to understand how to deprecate functionality
rellated to emberjs#6166.

This comment has been minimized.


This comment has been minimized.

Copy link
Contributor Author

commented Jul 10, 2019

@lifeart hate to tell you this but we've got the codemod and lint rules mostly ready to go already.


I think we still need to update the lint plugin to pull from this rfc-data


This comment has been minimized.

Copy link

commented Jul 11, 2019

@runspired good news! @dcyriller should we move codemod into ?
//cc @rwjblue
// // #topic-codemods

This comment has been minimized.

Copy link

commented Jul 11, 2019 — with Octobox

I created an issue to discuss that over in the codemod repo...


This comment has been minimized.

Copy link

commented Jul 11, 2019

@lifeart good idea, sure I'll do that. Let me fix a bug and initiate the migration.


This comment has been minimized.

Copy link
Contributor Author

commented Jul 11, 2019

There is node a lint rule PR here: ember-cli/eslint-plugin-ember#450

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can鈥檛 perform that action at this time.