diff --git a/text/0000-ember-data-packages.md b/text/0000-ember-data-packages.md new file mode 100644 index 0000000000..ac55fc0ca4 --- /dev/null +++ b/text/0000-ember-data-packages.md @@ -0,0 +1,473 @@ +- Start Date: 2018-10-31 +- RFC PR: (leave this empty) +- Ember Issue: (leave this empty) + +# Ember Data Packages + +## Summary + +This documents presents the proposed **public** import path changes for `ember-data`, and moving `ember-data` + into the `@ember-data` namespace. + +## Motivation + +**Reduce Confusion & Bike Shedding** + +Users of `ember-data` have often noted their confusion by the existence of both direct and "god object" (`DS.`) style + imports for modules from `ember-data`. The documentation currently uses primarily the `DS.` style, and users have + expressed interest and confusion over why the documentation has not been updated to reflect direct imports. + +**Improve The TypeScript Experience** + +Presence of multiple import locations confuses `Typescript`'s autocomplete, symbol resolution, and type hinting. + +**Simplify The Mental Model** + +Users of `ember-data` complain about the large API surface area; however, a large portion of this surface area is + non-essential user-land APIs that the provided adapter and serializer implementations expose. This move to packages + helps us simplify the mental model in three ways. + + First: it gives us a natural way of dividing the documentation and learning story such that key concepts + and APIs are more discoverable. + + Second: it allows us specifically to isolate the API surface area explosion of the provided adapter and serializer + implementations and make it clear that these are non-essential, replaceable APIs. E.G. it will help us to communicate + that these adapters and serializers are _an implementation_, **not** _the required implementation_. + + Third: it clarifies the roles of several concepts within `ember-data` that are often misused today. Specifically: + the `embedded-records-mixin` should *_only_* be used with the `RESTAdapter`, and `transforms` are *_only_* a + serialization/deserialization concern and not a way of defining custom `attrs` or `types`. Furthermore, `transforms` + are only applicable to the serializer implementations that `ember-data` provides, and not to `custom` (and sometimes + not to `subclassed`) serializers. + +**Improve the Contributor Experience** + +Contributors to `ember-data` are faced with a large, complex project with poor code and test organization. This makes it + unduly difficult to discover what tests exist, where to add tests, where associated code lives, and even what parts of + the code base relate to the feature or bug that they are looking to address. + + This move to packages will help us restructure the project and associated tests in a manner that is more discoverable. + +**Provide a Clear Subdivision of Packages** + +Today, `ember-data` is a large single package (`~35KB gzipped` in production). `ember-data` is often one of the largest + dependencies `emberjs` users have in their applications. However, not all users utilize all parts of `ember-data`, and + some users use very little. Providing these packages helps to clearly show the cost of various features, and better + allows us to enable end users to eliminate unneeded packages. + +Users that implement their own adapter or serializers today must still carry the significant weight of the adapter and + serializer implementations that `ember-data` ships regardless. This is a weight we should enable these users to eliminate. + +With the landing of `RecordData` and the merging of the `modelFactoryFor` RFC, it is likely that many applications + will soon require far less of `ember-data` than they do today. `ember-m3` is an example of a project that utilizes these + APIs in a way that requires significantly less of the `ember-data` experience. + +**Provide Infrastructure for Additional Changes** + +`ember-data` is entering a period of extended evolution, of which `RecordData` and `modelFactoryFor` are only the early + pieces. For example, current thinking includes the possibility of `ember-data` evolving to provide an `ember-m3`-like + experience for `json-api` as the default out-of-the-box experience, and a rethinking of how we manage the request/response + lifecycle when fulfilling a request for data. + + These experiences would live alongside the existing experience for a time prior to any deprecations of the current layer, + and it is possible that sometimes the current experience would never be deprecated. Subdividing `ember-data` into these + packages will enable us to provide a more seamless transition between these experiences without hoisting any package + size costs onto users that do not use either the current or the new experience. + +## Detailed design + +This RFC proposes import paths following the guidelines established in [Ember Modules RFC #176](https://github.com/emberjs/rfcs/pull/176), + with two addendums to account for scenarios that weren't faced by `ember`: +* `Error` sub-classes are named exports +* `Mixins` are named exports + +This is done to allow for continued grouping by common usage and mental model, where otherwise users would be faced with multiple imports from length file paths. + +The following modules would continue to live in a monorepo that (until further RFC) would continue to live at `github.com/ember/data`. + +
| Before | +After | +|
|---|---|---|
| import DS from 'ember-data'; | +Direct Import | +New Location | +
@ember-data/model |
+ ||
| DS.Model | +import Model from 'ember-data/model'; | +import Model from '@ember-data/model'; | +
| DS.attr | +import attr from 'ember-data/attr'; | +import { attr } from '@ember-data/model'; | +
| DS.belongsTo | +import { belongsTo } from 'ember-data/relationships'; | +import { belongsTo } from '@ember-data/model'; | +
| DS.hasMany | +import { hasMany } from 'ember-data/relationships'; | +import { hasMany } from '@ember-data/model'; | +
@ember-data/adapter |
+ ||
| DS.Adapter | +import Adapter from 'ember-data/adapter'; | +import Adapter from '@ember-data/adapter'; | +
| DS.RESTAdapter | +import RESTAdapter from 'ember-data/adapters/rest'; | +import RESTAdapter from '@ember-data/adapter/rest'; | +
| DS.JSONAPIAdapter | +import JSONAPIAdapter from 'ember-data/adapters/json-api'; | +import JSONAPIAdapter from '@ember-data/adapter/json-api'; | +
| DS.BuildURLMixin | +none | +import { BuildURLMixin } from '@ember-data/adapter'; | +
| DS.AdapterError | +import { AdapterError } from 'ember-data/adapters/errors'; | +import AdapterError from '@ember-data/adapter/error'; | +
| DS.InvalidError | +import { InvalidError } from 'ember-data/adapters/errors'; | +import { InvalidError } from '@ember-data/adapter/error'; | +
| DS.TimeoutError | +import { TimeoutError } from 'ember-data/adapters/errors'; | +import { TimeoutError } from '@ember-data/adapter/error'; | +
| DS.AbortError | +import { AbortError } from 'ember-data/adapters/errors'; | +import { AbortError } from '@ember-data/adapter/error'; | +
| DS.UnauthorizedError | +import { UnauthorizedError } from 'ember-data/adapters/errors'; | +import { UnauthorizedError } from '@ember-data/adapter/error'; | +
| DS.ForbiddenError | +import { ForbiddenError } from 'ember-data/adapters/errors'; | +import { ForbiddenError } from '@ember-data/adapter/error'; | +
| DS.NotFoundError | +import { NotFoundError } from 'ember-data/adapters/errors'; | +import { NotFoundError } from '@ember-data/adapter/error'; | +
| DS.ConflictError | +import { ConflictError } from 'ember-data/adapters/errors'; | +import { ConflictError } from '@ember-data/adapter/error'; | +
| DS.ServerError | +import { ServerError } from 'ember-data/adapters/errors'; | +import { ServerError } from '@ember-data/adapter/error'; | +
| DS.errorsHashToArray | +none | +import { errorsHashToArray } from '@ember-data/adapter/error'; + this public method should also be a candidate for deprecation + |
+
| DS.errorsArrayToHash | +none | +import { errorsArrayToHash } from '@ember-data/adapter/error'; + this public method should also be a candidate for deprecation + |
+
@ember-data/serializer |
+ ||
| DS.Serializer | +import Serializer from 'ember-data/serializer'; | +import Serializer from '@ember-data/serializer'; | +
| DS.JSONSerializer | +import JSONSerializer from 'ember-data/serializers/json'; | +import JSONSerializer from '@ember-data/serializer/json'; | +
| DS.RESTSerializer | +import RESTSerializer from 'ember-data/serializers/rest'; | +import RESTSerializer from '@ember-data/serializer/rest'; | +
| DS.JSONAPISerializer | +import JSONAPISerializer from 'ember-data/serializers/json-api'; | +import JSONAPISerializer from '@ember-data/serializer/json-api'; | +
| DS.EmbeddedRecordsMixin | +import EmbeddedRecordsMixin from 'ember-data/serializers/embedded-records-mixin'; | +import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest'; | +
| DS.Transform | +import Transform from 'ember-data/transform'; | +import Transform from '@ember-data/serializer/transform'; | +
@ember-data/store |
+ ||
| DS.Store | +import Store from 'ember-data/store'; | +import Store from '@ember-data/store'; | +
| DS.Snapshot | +none | +none | +
| DS.PromiseArray | +none | +none | +
| DS.PromiseObject | +none | +none | +
| DS.RecordArray | +none | +none | +
| DS.AdapterPopulatedRecordArray | +none | +none | +
| DS.RecordarrayManager | +none | +none | +
| DS.normalizeModelName | +none | +import { normalizeModelName } from 'ember-data/store'; + this public method should be a candidate for deprecation + |
+
@ember-data/record-data |
+ ||
| none | +import { RecordData } from 'ember-data/-private'; | +import RecordData from '@ember-data/record-data'; | +
@ember-data/relationship-layer |
+ ||
| DS.Relationship | +none | +none | +
@ember-data/debug |
+ ||
| DS.DebugAdapter | +none | +none | +