├── 0000-template.md
├── CODE_OF_CONDUCT.md
├── README.md
├── deprecation-template.md
└── text
├── 0001-transform-attribute-meta-parameter.md
├── 0003-block-params.md
├── 0010-engines.md
├── 0011-improved-cp-syntax.md
├── 0015-the-road-to-ember-2-0.md
├── 0024-bound-attributes.md
├── 0045-internet-explorer.md
├── 0046-registry-reform.md
├── 0050-improved-actions.md
├── 0053-helpers.md
├── 0056-improved-release-cycle.md
├── 0057-ember-data-reference-unification.md
├── 0058-helper-listing.md
├── 0061-ember-data-background-fetch.md
├── 0064-contextual-component-lookup.md
├── 0065-deprecation-warning-handlers.md
├── 0091-weakmap.md
├── 0095-router-service.md
├── 0101-ember-data-friendly-errors.md
├── 0120-route-serializers.md
├── 0136-contains-to-includes.md
├── 0139-isHtmlSafe.md
├── 0143-module-unification.md
├── 0150-factory-for.md
├── 0176-javascript-module-api.md
├── 0178-deprecate-ember-k.md
├── 0186-track-unique-history-location-state.md
└── 0191-deprecate-component-lifecycle-hook-args.md
/0000-template.md:
--------------------------------------------------------------------------------
1 | - Start Date: (fill me in with today's date, YYYY-MM-DD)
2 | - RFC PR: (leave this empty)
3 | - Ember Issue: (leave this empty)
4 |
5 | # Summary
6 |
7 | One paragraph explanation of the feature.
8 |
9 | # Motivation
10 |
11 | Why are we doing this? What use cases does it support? What is the expected
12 | outcome?
13 |
14 | # Detailed design
15 |
16 | This is the bulk of the RFC. Explain the design in enough detail for somebody
17 | familiar with the framework to understand, and for somebody familiar with the
18 | implementation to implement. This should get into specifics and corner-cases,
19 | and include examples of how the feature is used. Any new terminology should be
20 | defined here.
21 |
22 | # How We Teach This
23 |
24 | What names and terminology work best for these concepts and why? How is this
25 | idea best presented? As a continuation of existing Ember patterns, or as a
26 | wholly new one?
27 |
28 | Would the acceptance of this proposal mean the Ember guides must be
29 | re-organized or altered? Does it change how Ember is taught to new users
30 | at any level?
31 |
32 | How should this feature be introduced and taught to existing Ember
33 | users?
34 |
35 | # Drawbacks
36 |
37 | Why should we *not* do this? Please consider the impact on teaching Ember,
38 | on the integration of this feature with other existing and planned features,
39 | on the impact of the API churn on existing apps, etc.
40 |
41 | There are tradeoffs to choosing any path, please attempt to identify them here.
42 |
43 | # Alternatives
44 |
45 | What other designs have been considered? What is the impact of not doing this?
46 |
47 | # Unresolved questions
48 |
49 | Optional, but suggested for first drafts. What parts of the design are still
50 | TBD?
51 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | The Ember team and community are committed to everyone having a safe and inclusive experience.
2 |
3 | **Our Community Guidelines / Code of Conduct can be found here**:
4 |
5 | http://emberjs.com/guidelines/
6 |
7 | For a history of updates, see the page history here:
8 |
9 | https://github.com/emberjs/website/commits/master/source/guidelines.html.erb
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ember RFCs
2 |
3 | Many changes, including bug fixes and documentation improvements can be
4 | implemented and reviewed via the normal GitHub pull request workflow.
5 |
6 | Some changes though are "substantial", and we ask that these be put
7 | through a bit of a design process and produce a consensus among the Ember
8 | core team.
9 |
10 | The "RFC" (request for comments) process is intended to provide a
11 | consistent and controlled path for new features to enter the framework.
12 |
13 | [Active RFC List](https://github.com/emberjs/rfcs/pulls)
14 |
15 | ## When you need to follow this process
16 |
17 | You need to follow this process if you intend to make "substantial"
18 | changes to Ember, Ember Data or its documentation. What constitutes a
19 | "substantial" change is evolving based on community norms, but may
20 | include the following.
21 |
22 | - A new feature that creates new API surface area, and would
23 | require a [feature flag] if introduced.
24 | - The removal of features that already shipped as part of the release
25 | channel.
26 | - The introduction of new idiomatic usage or conventions, even if they
27 | do not include code changes to Ember itself.
28 |
29 | Some changes do not require an RFC:
30 |
31 | - Rephrasing, reorganizing or refactoring
32 | - Addition or removal of warnings
33 | - Additions that strictly improve objective, numerical quality
34 | criteria (speedup, better browser support)
35 | - Additions only likely to be _noticed by_ other implementors-of-Ember,
36 | invisible to users-of-Ember.
37 |
38 | If you submit a pull request to implement a new feature without going
39 | through the RFC process, it may be closed with a polite request to
40 | submit an RFC first.
41 |
42 | ## Gathering feedback before submitting
43 |
44 | It's often helpful to get feedback on your concept before diving into the
45 | level of API design detail required for an RFC. **You may open an
46 | issue on this repo to start a high-level discussion**, with the goal of
47 | eventually formulating an RFC pull request with the specific implementation
48 | design.
49 |
50 | ## What the process is
51 |
52 | In short, to get a major feature added to Ember, one must first get the
53 | RFC merged into the RFC repo as a markdown file. At that point the RFC
54 | is 'active' and may be implemented with the goal of eventual inclusion
55 | into Ember.
56 |
57 | * Fork the RFC repo http://github.com/emberjs/rfcs
58 | * Copy `0000-template.md` to `text/0000-my-feature.md` (where
59 | 'my-feature' is descriptive. don't assign an RFC number yet).
60 | * Fill in the RFC. Put care into the details: **RFCs that do not
61 | present convincing motivation, demonstrate understanding of the
62 | impact of the design, or are disingenuous about the drawbacks or
63 | alternatives tend to be poorly-received**.
64 | * Submit a pull request. As a pull request the RFC will receive design
65 | feedback from the larger community, and the author should be prepared
66 | to revise it in response.
67 | * Build consensus and integrate feedback. RFCs that have broad support
68 | are much more likely to make progress than those that don't receive any
69 | comments.
70 | * Eventually, the [core team] will decide whether the RFC is a candidate
71 | for inclusion in Ember.
72 | * RFCs that are candidates for inclusion in Ember will enter a "final comment
73 | period" lasting 7 days. The beginning of this period will be signaled with a
74 | comment and tag on the RFC's pull request. Furthermore,
75 | [Ember's official Twitter account](https://twitter.com/emberjs) will post a
76 | tweet about the RFC to attract the community's attention.
77 | * An RFC can be modified based upon feedback from the [core team] and community.
78 | Significant modifications may trigger a new final comment period.
79 | * An RFC may be rejected by the [core team] after public discussion has settled
80 | and comments have been made summarizing the rationale for rejection. A member of
81 | the [core team] should then close the RFC's associated pull request.
82 | * An RFC may be accepted at the close of its final comment period. A [core team]
83 | member will merge the RFC's associated pull request, at which point the RFC will
84 | become 'active'.
85 |
86 | ## The RFC life-cycle
87 |
88 | Once an RFC becomes active then authors may implement it and submit the
89 | feature as a pull request to the Ember repo. Becoming 'active' is not a rubber
90 | stamp, and in particular still does not mean the feature will ultimately
91 | be merged; it does mean that the core team has agreed to it in principle
92 | and are amenable to merging it.
93 |
94 | Furthermore, the fact that a given RFC has been accepted and is
95 | 'active' implies nothing about what priority is assigned to its
96 | implementation, nor whether anybody is currently working on it.
97 |
98 | Modifications to active RFC's can be done in followup PR's. We strive
99 | to write each RFC in a manner that it will reflect the final design of
100 | the feature; but the nature of the process means that we cannot expect
101 | every merged RFC to actually reflect what the end result will be at
102 | the time of the next major release; therefore we try to keep each RFC
103 | document somewhat in sync with the language feature as planned,
104 | tracking such changes via followup pull requests to the document.
105 |
106 | ## Implementing an RFC
107 |
108 | The author of an RFC is not obligated to implement it. Of course, the
109 | RFC author (like any other developer) is welcome to post an
110 | implementation for review after the RFC has been accepted.
111 |
112 | If you are interested in working on the implementation for an 'active'
113 | RFC, but cannot determine if someone else is already working on it,
114 | feel free to ask (e.g. by leaving a comment on the associated issue).
115 |
116 | ## Reviewing RFC's
117 |
118 | Each week the [core team] will attempt to review some set of open RFC
119 | pull requests.
120 |
121 | We try to make sure that any RFC that we accept is accepted at the
122 | Friday team meeting, and reported in [core team notes]. Every
123 | accepted feature should have a core team champion, who will represent
124 | the feature and its progress.
125 |
126 | **Ember's RFC process owes its inspiration to the [Rust RFC process]**
127 |
128 | [Rust RFC process]: https://github.com/rust-lang/rfcs
129 | [core team]: http://emberjs.com/team/
130 | [feature flag]: http://emberjs.com/guides/contributing/adding-new-features/
131 | [core team notes]: https://github.com/emberjs/core-notes/tree/master/ember.js
132 |
--------------------------------------------------------------------------------
/deprecation-template.md:
--------------------------------------------------------------------------------
1 | - Start Date: (fill me in with today's date, YYYY-MM-DD)
2 | - RFC PR: (leave this empty)
3 | - Ember Issue: (leave this empty)
4 |
5 | # Summary
6 |
7 | One paragraph explanation of the deprecation.
8 |
9 | # Motivation
10 |
11 | Why are we doing this? What are the problems with the deprecated feature?
12 | What is the replacement functionality?
13 |
14 | # Transition Path
15 |
16 | This is the bulk of the RFC. Explain the use-cases that deprecated functionality
17 | covers, and for each use-case, describe the transition path.
18 |
19 | Describe it in enough detail for someone who uses the deprecated functionality
20 | to understand, for someone to write the deprecation guide, and for someone
21 | familiar with the implementation to implement.
22 |
23 | # How We Teach This
24 |
25 | Would the acceptance of this proposal mean the Ember guides must be
26 | re-organized or altered? Does it change how Ember is taught to new users
27 | at any level?
28 |
29 | Does it mean we need to put effort into highlighting the replacement
30 | functionality more? What should we do about documentation, in the guides
31 | related to this feature?
32 |
33 | How should this deprecation be introduced and explained to existing Ember
34 | users?
35 |
36 | # Drawbacks
37 |
38 | Why should we *not* do this? Please consider the impact on teaching Ember,
39 | on the integration of this feature with other existing and planned features,
40 | on the impact of the API churn on existing apps, etc.
41 |
42 | There are tradeoffs to choosing any path, please attempt to identify them here.
43 |
44 | # Alternatives
45 |
46 | What other designs have been considered? What is the impact of not doing this?
47 |
48 | # Unresolved questions
49 |
50 | Optional, but suggested for first drafts. What parts of the design are still
51 | TBD?
52 |
--------------------------------------------------------------------------------
/text/0001-transform-attribute-meta-parameter.md:
--------------------------------------------------------------------------------
1 | - Start Date: 2014-08-14
2 | - RFC PR: https://github.com/emberjs/rfcs/pull/1
3 | - Ember Issue: https://github.com/emberjs/data/pull/4086
4 |
5 | # Summary
6 |
7 | For Ember Data. Pass through attribute meta data, which includes `parentType`, `options`, `name`, etc.,
8 | to the transform associated with that attribute. This will allow provide the following function signiture updates to `DS.Transform`:
9 |
10 | * `transform.serialize(deserialized, attributeMeta)`
11 | * `transform.deserialize(serialized, attributeMeta)`
12 |
13 | # Motivation
14 |
15 | The main use case is to be able to configure the transform
16 | on a per-model basis making more DRY code. So the transform can be aware of type and options on `DS.attr` can
17 | be useful to configure the transform for DRY use.
18 |
19 | # Detailed design
20 |
21 | ## Implementing
22 |
23 | The change will most likely start in [`eachTransformedAttribute`][1], which gets the attributes for that instance via `get(this, 'attributes')`. In the `forEach` the `name` will be used to get the specific attribute, e.g.
24 |
25 | ```js
26 | var attributeMeta = attributes.get(name);
27 | callback.call(binding, name, type, attributeMeta);
28 | ```
29 |
30 | The next change will be in [`applyTransforms`][2], where the `attributeMeta` parameter is added and passed to `transform.deserialize` as the second argument.
31 |
32 | You also have to handle the serialization part in [`serializeAttribute`][3], where you pass through the `attribute` parameter to `transform.serialize`.
33 |
34 | ## Using
35 |
36 | A convoluted example:
37 |
38 | ```js
39 | // Example based on https://github.com/chjj/marked library
40 | App.PostModel = DS.Model.extend({
41 | title: DS.attr('string'),
42 | markdown: DS.attr('markdown', {
43 | markdown: {
44 | gfm: false,
45 | sanitize: true
46 | }
47 | })
48 | });
49 |
50 | App.TechnicalPostModel = DS.Model.extend({
51 | title: DS.attr('string'),
52 | gistUrl: DS.attr('string'),
53 | markdown: DS.attr('markdown', {
54 | markdown: {
55 | gfm: true,
56 | tables: true,
57 | sanitize: false
58 | }
59 | })
60 | });
61 |
62 | App.MarkdownTransform = DS.Transform.extend({
63 | serialize: function (deserialized, attributeMeta) {
64 | return deserialized.raw;
65 | },
66 |
67 | deserialize: function (serialized, attributeMeta) {
68 | var options = attributeMeta.options.markdown || {};
69 |
70 | return marked(serialized, options);
71 | }
72 | });
73 | ```
74 |
75 | # Drawbacks
76 |
77 | Extra API surface area, although not much. This could also potentially introduce tight coupling between models and transforms if used improperly, e.g. not returning a default value if using type checking.
78 |
79 | # Alternatives
80 |
81 | 1. Passing the information from the server, which is a poor solution.
82 | 2. Writing a new transform for each model/attribute that needs a variation. Although this might be a good solution sometimes if you extend a base transform.
83 |
84 | # Unresolved questions
85 |
86 | Does the whole meta object need to be passed, or do we selectively pass in only the useful properties? Like
87 | `options` and `parentType` and `name`..
88 |
89 |
90 |
91 | [1]: https://github.com/emberjs/data/blob/master/packages/ember-data/lib/system/model/attributes.js#L193
92 | [2]: https://github.com/emberjs/data/blob/master/packages/ember-data/lib/serializers/json_serializer.js#L117
93 | [3]: https://github.com/emberjs/data/blob/master/packages/ember-data/lib/serializers/json_serializer.js#L528
94 |
--------------------------------------------------------------------------------
/text/0003-block-params.md:
--------------------------------------------------------------------------------
1 | - Start Date: 2014-08-18
2 | - RFC PR: https://github.com/emberjs/rfcs/pull/3
3 | - Issues:
4 | - Ember Stream support: emberjs/ember.js#5522
5 | - Handlebars parser support: wycats/handlebars.js#906
6 | - HTMLBars compiler support: tildeio/htmlbars#147
7 |
8 | # Summary
9 |
10 | Introduce block parameters to the Handlebars language to standardize context-preserving helpers, for example:
11 |
12 | ```handlebars
13 | {{#each people as |person|}}
14 | {{person.name}}
15 | {{/each}}
16 | ```
17 |
18 | # Motivation
19 |
20 | ### The Problem
21 |
22 | There is no idiomatic way to write a helper that preserves context and yields values to its template. This is particularly painful for components which have strict context-preserving semantics.
23 |
24 | ### Current workarounds
25 |
26 | - Don't write components that need to yield a value.
27 | - *Problem:* This may not be an option.
28 | - Invent a non-standard per-helper syntax (like `{{#with foo as bar}}` or `{{#each item in items}}`) that hook into the undocumented `keywords` to inject variables.
29 | - *Problems:* Custom syntaxes are not in the spirit of the Handlebars language and require the consumer to know the special incantation. Component authors must an non-trivial understanding of how `keywords` work.
30 |
31 | ### New possibilities
32 |
33 | ```handlebars
34 | {{#for-each obj as |key val|}}
35 | {{key}}: {{val}}
36 | {{/for-each}}
37 | ```
38 |
39 | ```handlebars
40 | {{#form-for post as |f|}}
41 | {{f.input "title"}}
42 | {{f.textarea "body"}}
43 | {{f.submit}}
44 | {{/form-for}}
45 | ```
46 |
47 |
48 | # Detailed design
49 |
50 | - Phase 1: Add block params to the Handlebars language
51 | - Phase 2: Rewrite Ember's helpers to accept streams
52 | - Phase 3: Add block param support to `{{each}}` and `{{with}}`
53 |
54 | ### Phase 1: Add block params to the Handlebars language
55 |
56 | The proposed syntax is `{{#x-foo a b w=x y=z as |param1 param2 ... paramN|}}` and is only available for block helpers.
57 |
58 | The names of the block parameters are compiled into the inner template, but are not known to the helper (`x-foo` in the example above). To call a template and populate its block params we use the arguments option:
59 |
60 |
61 | ```javascript
62 | var template = compile('{{person.name}}', {
63 | blockParams: [ 'person' ]
64 | });
65 |
66 | template({}, ..., [ personModel ]);
67 | ```
68 |
69 | More commonly, block params will be defined inside of the template.
70 |
71 | ```
72 | {{#with currentPost.author as |a|}}
73 | {{a.name}} {{a.email}}
74 | {{/with}}
75 | ```
76 |
77 | ```javascript
78 | registerHelper('with', function(object, options) {
79 | return options.fn(this, ..., [ object ]);
80 | });
81 | ```
82 |
83 | For compatibility reasons, the *number of block params* are passed to the helper so that the pre-block-params behaviour of the helper can be preserved. Example:
84 |
85 | ```javascript
86 | function eachHelper(..., options) {
87 | if (options.blockParamsLength > 0) { /* do new behaviour */ }
88 | else { /* do old behaviour */ }
89 | }
90 | ```
91 |
92 | ### Phase 2: Rewrite Ember's helpers to accept streams
93 |
94 | In the `with` example above, if the `currentPost` changes the `a` block param should update. This means it's not sufficient to pass only the initial value of the author in the arguments. Instead, we pass a stream which emits values whenever the observed property changes.
95 |
96 | In Handlebars, a block param can appear anywhere that an identifier can, for example `{{log a.name}}`. This means that all helpers would need to be modified to understand streams.
97 |
98 | ### Phase 3: Add block param support to `{{each}}` and `{{with}}`
99 |
100 | Deprecate context-changing and ad-hoc keyword flavors of `{{each}}` and `{{with}}` in favor of block params.
101 |
102 | # Drawbacks
103 |
104 | - Handlebars already has a similar notion of with `data` which can lead to confusion.
105 |
106 | # Alternatives
107 |
108 | To my knowledge, no other designs have been considered. Not implementing this feature would mean that components would continue to be difficult to compose.
109 |
110 | # Unresolved questions
111 |
112 | The associated HTML syntax for HTMLBars needs to be finalized.
113 |
--------------------------------------------------------------------------------
/text/0010-engines.md:
--------------------------------------------------------------------------------
1 | - Start Date: 2014-10-24
2 | - RFC PR: https://github.com/emberjs/rfcs/pull/10
3 | - Ember Issue: https://github.com/emberjs/ember.js/pull/12685
4 |
5 | # Summary
6 |
7 | Engines allow multiple logical applications to be composed together into a
8 | single application from the user's perspective.
9 |
10 | # Motivation
11 |
12 | Large companies are increasingly adopting Ember.js to power their entire
13 | product lines. Often this means separate teams (sometimes distributed
14 | around the world) working on the same app. Typically, responsibility is
15 | shared by dividing the application into one or more "sections". How this
16 | division is actually implemented varies from team to team.
17 |
18 | Sometimes, each "section" will be a completely separate Ember app, with
19 | a shared navigation bar allowing users to switch between each app. This
20 | allows teams to work quickly without stepping on each others' toes, but
21 | switching apps feels slow (especially compared to the normally speedy
22 | route transitions in Ember) because the entire page must be thrown out,
23 | then an entirely new set of the same assets downloaded and parsed.
24 | Additionally, code sharing is largely accomplished via copy-and-paste.
25 |
26 | Other times, the separation is enforced socially, with each team
27 | claiming a section of the same app in the same repository.
28 | Unfortunately, this approach leads to frequent conflicts around shared
29 | resources, and feedback from tests gets slower and slower as test suites
30 | grow in size.
31 |
32 | A more modular approach is to break off elements of a single application into
33 | separate [addons](http://www.ember-cli.com/user-guide/#addons). Addons are
34 | essentially mixins for [ember-cli](http://www.ember-cli.com/) applications. In
35 | other words, the elements of an addon are merged with those of the application
36 | that includes them. While addons allow for distributed development, testing, and
37 | packaging, they do not provide the logical run-time separation required for
38 | developing completely independent "sections" of an application. Addons must
39 | function within the namespace, registry, and router of the application in which
40 | they are included.
41 |
42 | Engines provide an alternative to these approaches that allows for distributed
43 | development, testing, and packaging, _as well as_ logical run-time separation.
44 | Because engines are derived from applications, they can be just as
45 | full-featured. Each has its own namespace and registry. Even though engines are
46 | isolated from the applications that contain them, the boundaries between them
47 | allow for controlled sharing of resources.
48 |
49 | Engines can be either "routable" or "route-less":
50 |
51 | * Routable engines provide a routing map which can be integrated with the
52 | routing maps of parent applications or engines. Routing maps are alway eager
53 | loaded, which allows for deep linking into an engine's routes regardless of
54 | whether the engine itself has been instantiated.
55 |
56 | * Route-less engines can isolate complex functionality that is not related to
57 | routing (e.g. a chat engine in a sidebar). Route-less engines can be rendered
58 | into outlets ad hoc as routes are loaded.
59 |
60 | The potential scope of engines is large enough that this feature merits
61 | development and delivery in multiple phases. A minimum viable version could be
62 | released sooner, which could be augmented with more advanced features later.
63 |
64 | An initial release of engines could provide the following benefits:
65 |
66 | * Distributed development - Engines can be developed and tested in isolation
67 | within their own Ember CLI projects and included by applications or other
68 | engines. Engines can be packaged and released as addons themselves.
69 |
70 | * Integrated routing - Support for mounting routable engines in the routing maps
71 | of applications or other engines.
72 |
73 | * Ad hoc embedding - Support for embedding route-less engines in outlets as
74 | needed.
75 |
76 | * Clean boundaries - An engine can cooperate with its parents through a few
77 | explicit interfaces. Beyond these interfaces, engines and applications are
78 | isolated.
79 |
80 | Subsequent releases of engines could allow for the following:
81 |
82 | * Lazy loading - An engine could allow its parent to boot with only its routing
83 | map loaded. The rest of the engine could be loaded only as required (i.e.
84 | when a route in an engine is visited). This would allow applications to boot
85 | faster and limit their memory consumption.
86 |
87 | * Namespaced access to engine resources from applications - This could open up
88 | the potential for applications to use, and extend, an engine's resources much
89 | like resources in other addons, but without the possibility of namespace
90 | collisions.
91 |
92 | ## Detailed design
93 |
94 | Engines are very similar to regular applications: they can be developed in
95 | isolation in Ember CLI, include addons, and contain all the same elements,
96 | including routes, components, initializers, etc. The primary differences are
97 | that an engine does not boot itself and an engine does not control the router.
98 |
99 | ### Engine internals
100 |
101 | New `Engine` and `EngineInstance` classes will be introduced.
102 |
103 | Applications and engines will share ancestry. It remains TBD whether
104 | applications will subclass engines, or whether a common ancestor will be
105 | introduced.
106 |
107 | Engines and applications will share the same pattern for registry / container
108 | ownership and encapsulation. Both will also have initializers and instance
109 | initializers.
110 |
111 | Engine instances will have access to their parent instances. An engine's parent
112 | could be either an application or engine.
113 |
114 | #### Routable vs. route-less engines
115 |
116 | Routable engines will define their routes in a new `Ember.Routes` class. This
117 | class will encapsulate the functionality provided by `Router#map`, and will be
118 | used internally by `Ember.Router` as well (with no public interface changes of
119 | course).
120 |
121 | Route-less engines do not define routing maps nor can they contain routes.
122 |
123 | ### Developing engines
124 |
125 | Engines can be developed in isolation as Ember CLI addon projects or as part of
126 | a parent application.
127 |
128 | #### Engines as addons
129 |
130 | Engines can be created as separate addon projects with:
131 |
132 | ```
133 | ember engine
134 | ```
135 |
136 | This will create a special form of an ember addon. The file structure will match
137 | that of a standard addon, but will have an `engine` directory instead of an
138 | `addon` directory.
139 |
140 | Engines can be unit tested and can also be integration tested within a dummy
141 | app, just like standard addons.
142 |
143 | #### In-repo engines
144 |
145 | An engine can be created within an existing application's project using a
146 | special `in-repo-engine` generator (similar to the `in-repo-addon` generator):
147 |
148 | ```
149 | ember g in-repo-engine
150 | ```
151 |
152 | In-repo engines can be unit tested in isolation or integration testing with the
153 | main application (instead of a dummy application).
154 |
155 | > Note: In-repo addons currently are created in the `/lib` directory (e.g.
156 | `/lib/my-addon`). Unit tests and integration tests are currently co-mingled with
157 | tests for the main application. It's recommended that in-repo engines provide
158 | better test separation than is provided for regular addons, and perhaps the
159 | whole in-repo addon directory structure should be re-examined at the same time
160 | in-repo engines are introduced.
161 |
162 | #### Engine directory structure
163 |
164 | An engine's directory will contain a file structure identical to the `app`
165 | directory in a standard ember-cli application, with the following exceptions:
166 |
167 | * `engine.js` instead of `app.js` - defines the `Engine` class and
168 | loads its initializers.
169 |
170 | * `routes.js` instead of `router.js` - defines an engine's routing map in a
171 | `Routes` class. This file should be deleted entirely for route-less engines.
172 |
173 | ### Installing engines
174 |
175 | Engines developed as addons can be installed in an application just like any
176 | other addon:
177 |
178 | ```
179 | ember install
180 | ```
181 |
182 | During development, you can use `npm link` to make your engine available in
183 | another parent engine or application.
184 |
185 | ### Mounting routable engines
186 |
187 | The new `mount()` router DSL method is used to mount an engine at a particular
188 | "mount-point" in a route map.
189 |
190 | For example, the following route map mounts the `discourse` engine at the
191 | `/forum` path:
192 |
193 | ```
194 | Router.map(function() {
195 | this.mount('discourse', {path: '/forum'});
196 | });
197 | ```
198 |
199 | > Note: If unspecified, `path` will match the name of the engine.
200 |
201 | Calls to `mount` can be nested within routes. An engine can be mounted at
202 | multiple routes, and each will represent a new instance of the engine to be
203 | created.
204 |
205 | ### Mounting route-less engines
206 |
207 | A `mount()` DSL will also be added to routes, which will enable embedding of
208 | route-less engines in outlets. This can be called from `renderTemplate` (or
209 | `renderComponents` once routable components are introduced).
210 |
211 | `mount` has a similar signature to `render`, although it is obviously
212 | engine-specific instead of template-specific. `mount` can be used to specify
213 | a target template and outlet as follows:
214 |
215 | ```
216 | renderTemplate: function() {
217 | // Mount the chat engine in the sidebar
218 | this.mount('chat', {
219 | into: 'main',
220 | outlet: 'sidebar'
221 | });
222 | }
223 | ```
224 |
225 | As a result, the engine's `application` template will be rendered into the
226 | `sidebar` outlet in the application's `main` template.
227 |
228 | ### Loading phases
229 |
230 | Engines can exist in several phases:
231 |
232 | * Booted - an engine that's been installed in a parent application will have
233 | its dependencies loaded and its (non-instance) initializers invoked when the
234 | parent application boots.
235 |
236 | * Mounted - Routable and route-less engines have slightly different concepts of
237 | "mounting". A routable engine is considered mounted when it has been included
238 | by a router at one or more mount-points. A route-less engine is considered
239 | mounted as soon as a route's `mount` call resolves.
240 |
241 | * Instantiated - When an engine is instantiated, an `EngineInstance` is created
242 | and an engine's instance initializers are invoked. A routable engine is
243 | instantiated when a route is visited at or beyond its mount-point. A
244 | route-less engine is instantiated as soon as it is mounted.
245 |
246 | Special `before` and `after` hooks could be added to application instance
247 | initializers that allow them to be ordered relative to engine instance
248 | initializers.
249 |
250 | ### Engine boundaries
251 |
252 | Besides its routing map, an engine does not share any other resources with its
253 | parent by default. Engines maintain their own registries and containers, which
254 | ensure that they stay isolated. However, some explicit sharing of resources
255 | between engines and parents is allowed.
256 |
257 | #### Engine / parent dependencies
258 |
259 | Dependencies between engines and parents can be defined imperatively or
260 | declaratively.
261 |
262 | Imperative dependencies can be defined in an engine's instance initializers.
263 | When an engine is instantiated, the `parent` property on its `EngineInstance` is
264 | set to its parent instance (either an `ApplicationInstance` or
265 | `EngineInstance`). Since the engine instance is available in the instance
266 | initializer, this `parent` property can also be accessed. This allows an engine
267 | instance to interrogate its parent, specifically through its `RegistryProxy` and
268 | `ContainerProxy` interfaces.
269 |
270 | Alternatively, declarative dependencies can be defined on a limited basis. The
271 | initial API will be limited: an engine can define an array of `services` that it
272 | requires from its parent.
273 |
274 | For example, the following engine expects its parent to provide `store` and
275 | `session` services:
276 |
277 | ```
278 | import Ember from 'ember';
279 |
280 | var Engine = Ember.Engine.extend({
281 | dependencies: {
282 | services: [
283 | 'store',
284 | 'session'
285 | ]
286 | }
287 | });
288 |
289 | export default Engine;
290 | ```
291 |
292 | The parent application can provide a re-mapping of services from its namespace
293 | to that of the engine via an `engines` declaration.
294 |
295 | In the following example, the application shares its `store` service directly
296 | with the `checkout` engine. It also shares its `current-user` service as the
297 | `session` service requested by the engine.
298 |
299 | ```
300 | import Ember from 'ember';
301 |
302 | var App = Ember.Application.extend({
303 | engines: {
304 | checkout: {
305 | dependencies: {
306 | services: [
307 | 'store',
308 | {session: 'current-user'}
309 | ]
310 | }
311 | }
312 | }
313 | });
314 |
315 | export default App;
316 | ```
317 |
318 | When engines are instantiated, the listed dependencies will be looked up on
319 | the parent and made accessible within the engine.
320 |
321 | Note that the `engines` declaration provides further space to define
322 | characteristics about an engine, such as whether it should be eager or
323 | lazy-loaded, URLs for manifest files, etc.
324 |
325 | # Drawbacks
326 |
327 | This RFC introduces the new concept of engines, which increases the
328 | learning curve of the framework. However, I believe this issue is
329 | mitigated by the fact that engines are an opt-in packaging around
330 | existing concepts.
331 |
332 | In the end, I believe that "engines" are just a small API for composing
333 | existing concepts. And they can be introduced at the top of the
334 | conceptual ladder, once users are comfortable with the basics of Ember,
335 | and only for those working on large teams or distributing addons.
336 |
337 | # Alternatives
338 |
339 | Several incomplete alternatives are discussed in the Motivations section above.
340 |
341 | I know of no alternatives being discussed in the Ember community that meet the
342 | same needs as engines; namely, for development _and_ run-time isolation.
343 |
344 | # Unresolved questions
345 |
346 | ## Non-CLI Users
347 |
348 | This RFC assumes Ember CLI. I would prefer to prove this out in Ember
349 | CLI before locking down the public APIs/hooks the router exposes for
350 | locating and mounting engines. Once this is done, however, we should
351 | expose and document those hooks so users who cannot use Ember CLI for
352 | whatever reason can still take advantage of composability.
353 |
354 | ## Declarative dependencies
355 |
356 | The initial scope of declarative dependency sharing is limited in scope to
357 | services. Should other types of dependencies be declaratively shareable?
358 | Should addons be the recommended path to share all other dependencies?
359 |
360 | ## Async mounting of route-less engines
361 |
362 | `Route#renderTemplate` is called synchronously, although `Route#mount` should
363 | surely be async. How async mounting is represented in the route lifecycle is
364 | TBD. A solution isn't proposed here because the problem is shared by routable
365 | and async components, and a common solution should be reached.
366 |
367 | ## Lazy loading manifests
368 |
369 | In order to facilitate lazy loading of engines, we will need to determine a
370 | structure for manifest files that contain an engine's assets. Furthermore, an
371 | application will need to be configurable with URLs for these manifests.
372 |
373 | It's likely that an engine's routing map will always be needed at the time of
374 | application deployment. Allowing lazy loading of routing maps would prevent the
375 | formation of any links from a parent application into an engine's routes.
376 |
377 | When developed in isolation as addons, engines will have their own sets of
378 | dependencies. These dependencies will be treated like any other addons when
379 | engines are deployed together with an application. However, in order to support
380 | lazy loading, it would be ideal to dedupe dependencies in order to create a lean
381 | and conflict-free asset manifest.
382 |
383 | Reference: deduping strategy discussed by @wycats in
384 | [this Google doc](https://docs.google.com/a/tomdale.net/document/d/12CsR-zli5oP2TDWOef_-D28zjmbVD83hU4q9_VTk-9s/edit).
385 |
386 | ## Namespaced access to engine resources
387 |
388 | The concept of namespaced access to engine resources is mentioned above as a
389 | potential goal of a future release of engines. This will require further
390 | discussion to decide how it should work both technically and semantically, and
391 | how it applies to lazy-loaded engines.
392 |
393 | If these problems can be resolved, this feature would allow for more flexibility
394 | in parent / engine interactions. Instead of just allowing engines to look up
395 | resources in a parent, the inverse could also be allowed.
396 |
397 | For example, if the `authentication` engine contains
398 | `engines/authentication/models/user.js`, a parent application could look up this
399 | same model through a namespace. Perhaps as follows:
400 |
401 | ```js
402 | container.lookup('authentication@model:user');
403 | ```
404 |
405 | Other APIs in Ember would need to be extended to support namespaces to
406 | take full advantage of this feature. For example, components that ship
407 | with an engine might be accessed from the primary application like this:
408 |
409 | ```handlebars
410 | {{authentication@login-form obscure-password=true}}
411 | ```
412 |
--------------------------------------------------------------------------------
/text/0011-improved-cp-syntax.md:
--------------------------------------------------------------------------------
1 | - Start Date: 2014-09-30
2 | - RFC PR: https://github.com/emberjs/rfcs/pull/11
3 | - Ember Issue: https://github.com/emberjs/ember.js/pull/9527
4 |
5 | # Summary
6 |
7 | Improve computed property syntax
8 |
9 | # Motivation
10 |
11 | Today, the setter variant of CP's is both confusing, and looks scary as sin.
12 | (Too many concepts must be taught and it is too easy to screw it up.)
13 |
14 | # Detailed design
15 |
16 | today:
17 | ------
18 |
19 | ```js
20 | fullName: Ember.computed('firstName', 'lastName', function(key, value) {
21 | if (arguments.length > 1) {
22 | var names = value.split(' ');
23 | this.setProperties({
24 | firstName: names[0],
25 | lastName: names[1]
26 | });
27 | return value;
28 | }
29 |
30 | return this.get('firstName') + ' ' + this.get('lastName');
31 | });
32 | ```
33 |
34 | Tomorrow:
35 | ---------
36 |
37 | ```js
38 | fullName: Ember.computed('firstName', 'lastName', {
39 | get: function(keyName) {
40 | return this.get('firstName') + ' ' + this.get('lastName');
41 | },
42 |
43 | set: function(keyName, fullName, oldValue) {
44 | var names = fullName.split(' ');
45 |
46 | this.setProperties({
47 | firstName: names[0],
48 | lastName: names[1]
49 | });
50 |
51 | return fullName;
52 | }
53 | });
54 | ```
55 |
56 |
57 | Notes:
58 | ------
59 |
60 | * we should keep `Ember.computed(fn);` as shorthand for getter only
61 | * `get` xor `set` variants would also be possible.
62 | * `{ get() { } }` is es6 syntax for `{ get: function() { } )`
63 |
64 | Migration
65 | ---------
66 |
67 | * 1.x support both, detect new behaviour by testing if the last arg is not null and typeof object
68 | * 1.x+1 deprecate if last arg is a function and its arity is greater than 1
69 |
70 |
71 | # Drawbacks
72 |
73 | N/A
74 |
75 | # Alternatives
76 |
77 | N/A
78 |
79 | # Unresolved questions
80 |
81 | None
82 |
--------------------------------------------------------------------------------
/text/0024-bound-attributes.md:
--------------------------------------------------------------------------------
1 | - 2014-11-26
2 | - RFC PR: https://github.com/emberjs/rfcs/pull/24
3 | - Ember Issue:
4 |
5 | # Summary
6 |
7 | Unlike Handlebars, HTMLBars parses HTML as it parses a template.
8 | Bound attributes are one syntax now possible.
9 |
10 | For example, this variable `color` is bound to set a class:
11 |
12 | ```hbs
13 |
14 | ```
15 |
16 | Though traditional HTML attribute syntax should be preserved (using
17 | `class` and not `className` for example), the default path will be
18 | to set attributes as properties on the DOM node.
19 |
20 | However this happy path has several important exceptions, and results
21 | in a few strange edge cases. This rfc will go into detail about the
22 | expected behavior without talking about the implementation of attribute
23 | on the Ember rendering pipeline.
24 |
25 | # Motivation
26 |
27 | `{{bind-attr` is a verbose syntax and difficult for new developers to
28 | understand.
29 |
30 | # Detailed design
31 |
32 | Given a use of bound attributes:
33 |
34 | ```hbs
35 |
36 | ```
37 |
38 | There are three important inputs:
39 |
40 | * The element (`tagName`, `namespaceURI`)
41 | * The attribute name
42 | * The value (literal or stream)
43 |
44 | The following described the algorithm for updating the attribute/property
45 | value on an element.
46 |
47 | 1. If the element has an SVG namespace, use `setAttribute`. Setting SVG attributes
48 | as properties is not supported.
49 | 2. If the attribute name is `style`, use `setAttribute`.
50 | 3. Normalize the property name as described in `propertyNameFor` below. If a normalized
51 | name is returned, set that property on the element (`element[normalizedPropName]`).
52 | If it is not returned, set with `setAttribute`.
53 |
54 | `propertyNameFor` is a normalization setup for attribute names that takes the element
55 | and attribute name as input.
56 |
57 | 1. Build a list of normalized properties for the passed element `normalizedAttrs[element.tagName][elementAttrName.toLowerCase()] = elementAttrName`
58 | 2. Fetch the normalized property name from this list `normalizedAttr = normalizedAttrs[element.tagName][passedAttrName.toLowerCase()]`
59 | 3. Return this normalized attr. If an `attrName` is did not normalize to a property (for example `class`), null is returned
60 |
61 | ### Acknowledged edge cases
62 |
63 | * Boolean attrs with blank string won't work like they would in HTML: `` would be false
64 | * Some selectors may not work as expected. `` will not result in a working `[value=red]` selector
65 |
66 | # Drawbacks
67 |
68 | None.
69 |
70 | # Alternatives
71 |
72 | Two obvious alternatives considered in detail are Angular and React.
73 |
74 | In **Angular 2.0**, [a new prop/attr/event syntax](http://www.beyondjava.net/blog/angularjs-2-0-sneak-preview-data-binding/)
75 | is being introduced.
76 |
77 | Setting an attribute just like setting an HTML attribute:
78 |
79 | ```html
80 |
81 | ```
82 |
83 | Properties are flagged with the `[]` syntax:
84 |
85 | ```html
86 |
87 | ```
88 |
89 | Angular is limited by it's HTML templating here. The value must be quoted
90 | to have complex content, where as in HTMLBars it is easier to bend the
91 | rules to introduce literal values: `disabled={{controller.isInputDisabled}}`.
92 |
93 | Events are out of our immediate purview in this RFC, but for completeness
94 | note Angular's syntax:
95 |
96 | ```html
97 |
98 | ```
99 |
100 | **React's JSX** has its own [property syntax](http://facebook.github.io/react/docs/jsx-in-depth.html),
101 | one that diverges from traditional HTML by focusing entirely on properties
102 | instead of attributes. This means the templates are well prepared for
103 | use with components, but also that JSX must maintain a large whitelist of
104 | special cases such as [supported tags](http://facebook.github.io/react/docs/tags-and-attributes.html)
105 | and [some HTML attributes](http://facebook.github.io/react/docs/jsx-gotchas.html).
106 |
107 | In general we would prefer to have Ember templates be as close to HTML
108 | as possible, without requiring developers to learn a new set of property
109 | names replacing the attribute names they already know.
110 |
111 | # Unresolved questions
112 |
113 | * How do we deal with `on*` attributes?
114 | * Should we do anything special about generic element properties like ``?
115 | * Should HTMLBars unbound attributes use the same alorithm?
116 |
117 | There is a spike of significant depth [in PR #9721](https://github.com/emberjs/ember.js/pull/9721)
118 | and a followup [in PR #9977](https://github.com/emberjs/ember.js/pull/9977).
119 |
--------------------------------------------------------------------------------
/text/0045-internet-explorer.md:
--------------------------------------------------------------------------------
1 | - Start Date: 2015-06-07
2 | - RFC PR: https://github.com/emberjs/rfcs/pull/45
3 | - Ember Issue: (leave this empty)
4 |
5 | # Summary
6 |
7 | Solicit feedback about the support timeframe for Internet Explorer 8 and Internet Explorer 9.
8 |
9 | # Motivation
10 |
11 | As Ember heads towards version 2.0, it is a good time to evaluate our browser support matrix. Ember follows Semantic Versioning, and we consider browser compatibility to be under the umbrella of those guarantees. In other words, we will continue to support whatever browsers we officially support in Ember 2.0 until Ember 3.0.
12 |
13 | Ember 1.x did not have an official browser support matrix, but we would like to correct this for Ember 2.0.
14 |
15 | We want to make this decision on the basis of the browsers that our community still needs to support, while weighing that against the costs we bear as a community to support older browsers. This RFC will lay out some of those costs, so we can decide what tradeoff is most appropriate.
16 |
17 | Members of the core team maintain many different kinds of apps across many different kinds of companies. Some of us work on applications with small, agile teams, while others work inside of large corporations with many engineers. When this topic came up amongst the team, we discovered that, across all these different companies and Ember apps, no one was still supporting IE8.
18 |
19 | Because of this, the core team's impression is that the costs of IE8 support now far exceed the benefits, and we are considering dropping support
20 | for IE8 in Ember 2.0. Before we make the decision, we want to hear from the rest of the community. Supporting IE8 incurs significant cost, both in terms of features and maintenance, and we want the community to help us think through the cost-benefit analysis.
21 |
22 | Ember is more than just the framework's code. When people use Ember, they expect to be able to use Ember's tooling, read Ember's documentation, find solutions to problems on Stack Overflow, and read tutorials produced by community members. All of these are shackled to the limitations of IE8, and by dropping support for IE8, people can begin to rely on the improved baseline of ES5.
23 |
24 | Below, we outline the costs of continuing to support IE8, so that you can help us make a considered decision.
25 |
26 | # Detailed design
27 |
28 | ## IE8
29 |
30 | ### Eliminate `get()`
31 |
32 | Currently, accessing properties on an Ember object requires using the `.get()` method. By using this abstraction, we have been able to implement several powerful features, such as proxies and computed properties, even on older browsers like IE8 that lack getters and setters.
33 |
34 | However, ECMAScript 5, which shipped in **2009**, added support for getters to JavaScript itself, and we would like to use this feature in Ember to eliminate the explicit calls to `get`. Developers new to the framework tell us that having to remember to use `.get()` is a big source of confusion. More seasoned developers get used to it, but moving the Ember object model closer to the pure JavaScript object model is a major goal for Ember 2.x. While many of the features of ES6 classes can be transpiled, getters and setters require engine support, and could not be used if we needed to support IE8.
35 |
36 | ### More ES6 Features, Today
37 |
38 | While much of ES6 can be transpiled correctly to ES3 (the version of JavaScript included with IE8), transpiling ES6 modules and classes requires `defineProperty`.
39 |
40 | Continued support for IE8 limits our ability to adopt new ES6 features in the internals of Ember, and to talk about them in our documentation.
41 |
42 | One example: In ES6, classes define their methods as non-enumerable properties. Transpiling this to existing browsers is only possible with `defineProperty`, which is not included in IE8. Trying to transpile ES6 classes to work on IE8 would lead to apps exhibiting subtly different behavior that would be painful to debug. IE8 users would discover that the larger Ember ecosystem was incompatible with their apps in hard-to-predict ways, and we think the ecosystem is one of the biggest advantages Ember offers.
43 |
44 | In other words, we don't think we can make the full transition to JavaScript classes a first-class part of the Ember experience if we still support IE8. As we did with modules, we would like to move more of our core to JavaScript features in the future, which would be significantly stymied by the lack of `defineProperty` in IE8.
45 |
46 | ### Remove the jQuery Dependency
47 |
48 | For its entire lifetime, Ember has relied on jQuery to smooth the rough edges of browser compatibility when interacting with the DOM. When people think about that dependency, they often assume that we could just replace calls to things like `.attr` with their more verbose DOM counterpart and call it a day.
49 |
50 | jQuery does more than just patch over IE8 rough spots; it also serves as the central place for normalizing behavior that can differ significantly across browsers. If we tried to pick-and-choose pieces of jQuery to pull into Ember, we would also be responsible for backporting any changes made to jQuery. We'd rather just rely on jQuery directly; that's what dependencies are for.
51 |
52 | The jQuery dependency has helped us with a few cross-browser areas:
53 |
54 | * Portable `DOMContentLoaded` (via `jQuery.ready`)
55 | * Support for event delegation across a wide variety of events.
56 | * Attribute and property normalization, which has already been implemented by HTMLBars
57 | * HTML parsing, which has also been implemented by HTMLBars
58 |
59 | Of these, proper support for event delegation is the largest remaining reason to rely on jQuery. IE9's support for the capture phase of events makes it simpler to support event delegation properly across all event types without a normalization layer.
60 |
61 | ### Support More Event Types
62 |
63 | Many newly specified events in the web platform (such as the media events) do not bubble, which is a problem for frameworks like Ember that rely on event delegation. However, the capture API, which was added in IE9, is invoked properly for all events, and does not require a normalization layer. Not only would supporting the capture API allow us to drop the jQuery dependency, but it would allow us to properly handle these non-bubbling events. This would allow you to use events like `playing` in your components without having to manually set up event listeners.
64 |
65 | ### CSS Improvements in Ember 2.x
66 |
67 | Today, the main Ember framework does very little to directly help with CSS. We expect that to change in the 2.x series, as we explore ways to help tame the CSS beast.
68 |
69 | However, a number of important CSS features landed in IE9: CSS3 selectors, full support for `querySelectorAll`, `getComputedStyle`, `calc()` to name a few. Productively tackling the CSS problem without these features would be like fighting with both hands tied behind our backs, and it may be impossible for us to robustly tackle the problem until Ember 3.0 if we needed to continue to support IE8.
70 |
71 | While it may be theoretically possible to implement some form of this feature in IE8, it is likely that the cost of doing so in a backwards-compatible way would significantly add to development time; perhaps so significantly it would be better to wait until we drop support for IE8 than attempt to bolt it on to a browser released half a decade ago.
72 |
73 | ### Maintenance Costs
74 |
75 | While it's very easy to weigh the costs of features that we could not implement at all due to IE8, there is a much more pernicious cost that is harder to see.
76 |
77 | Support for IE8 adds costs, sometimes significant, to every new feature we work on. For example, broken support for text nodes in IE8 significantly impeded early work on Glimmer. Every new area of work requires budgeting a significant amount of time for IE8 support.
78 |
79 | This is not surprising. When asked many years ago what jQuery could do when IE6 was gone, John Resig replied that we would gain little from dropping IE6, and that the benefits would not come until jQuery could drop IE8, the last version of IE featuring the bugs that made IE6 so difficult to develop for.
80 |
81 | Quite often, we will assume that a feature is ready to ship, and only discover subtle issues in IE8 very close to the release once it has been tested. We estimate that support for legacy Internet Explorer slowed down the development of HTMLBars by 2x.
82 |
83 | In short, we would be able to implement more features more quickly without the burden of bugs that were first introduced 15 years ago.
84 |
85 | ## What About IE9?
86 |
87 | In the first decade of 2000, browsers were updated very slowly, and every new release took a long time to be supplanted by the next release. As the last version of Internet Explorer supported by Windows XP, IE8 is a relic of this bygone era. In contrast, IE9 usage was quickly supplanted by IE10, and that pattern continues with IE11.
88 |
89 | The public trackers have IE9 at a lower share of total usage than IE8, so it might be worth considering dropping them together. Our decision for Ember 2.0 will likely hold until late 2016, so it's worth considering more than just the current moment when making the decision.
90 |
91 | While IE9 added support for the ES5 features we need to move into the future for JavaScript, IE10 added support for the last great wave of web features. Here is a sampling:
92 |
93 | * Flexbox and Grid Layout
94 | * Offline storage (IndexedDB, File, Blob)
95 | * Web Workers
96 | * Typed Arrays
97 | * Web Sockets
98 | * App Cache
99 | * History API
100 |
101 | Several of these features are required for asm.js, and in total, they make the web platform a capable application runtime. While we don't have any immediate plans to take advantage of these web features right now, the best experiments that people are doing today rely on them. By assuming IE10 as the baseline across the entire ecosystem, we would be able to do much more aggressive experimentation on the web platform.
102 |
103 | # Drawbacks
104 |
105 | Many users have told us that they chose Ember because of the community's commitment to backwards compatibility. When we announced in early 2014 that we would continue to support IE8 for at least another year, other libraries and frameworks had already dropped support. That being said, there will always be organizations using Ember that exist on the tail-end of browser adoption patterns. We risk alienating or upsetting those users by dropping support for a browser that, while on the way out, is not yet completely gone.
106 |
107 | However, in many cases, the requirement of IE8 support is driven by non-technical management who do not have a strong sense of the experience of using apps in IE8. In practice, many applications are not rigorously tested in older browsers, and the performance of IE8 is so bad that applications written using any framework perform poorly. Techniques that framework and application developers use to make Chrome fast quite often have pathological characteristics on browsers with a DOM and JavaScript engine written in the 90s.
108 |
109 | Still, some people make it work, and dropping IE8 support may prevent those teams from staying with the community as it migrates to Ember 2.0.
110 |
111 | # Alternatives
112 |
113 | ## Drop IE8 Support During 2.x
114 |
115 | One alternative we have considered is deprecating IE8 support prior to releasing 2.0, but still maintaining it for a few point releases to give IE8 more time to lose market share.
116 |
117 | After discussing with the core team, we believe that this would be a violation of our Semantic Versioning commitment to users. Specifically, we want to avoid a large group of apps getting stuck midway through the 2.x cycle. Version numbers are an important tool for developers, maintainers and ecosystems to communicate compatibility. Tools such as package managers rely on version numbers correctly indicating breaking changes.
118 |
119 | We consider browser compatibility to be a feature of Ember, and dropping IE8 support in a minor release would be akin to stripping out any other major feature. While the ecosystem would muddle along in either case, such a move would cause exactly the kind of ecosystem fragmentation that Semantic Versioning is designed to prevent.
120 |
121 | If we want to communicate the idea that changing versions comes with a reduction in functionality, we should do that the same way we always do, by incrementing the major version.
122 |
123 | ## Early 3.0
124 |
125 | Another option is to release 3.0 in six months, rather than the nearly two years between Ember 1.0 and Ember 2.0.
126 |
127 | Correctly tuning the cadence of major releases is a delicate tradeoff. Semantic Versioning allows us to easily communicate about breaking changes, and some take this as a license to make them frequently. However, a robust ecosystem relies on a certain measure of stability.
128 |
129 | We believe that the frustration of breaking changes every six months (or even a year) would outweigh whatever benefits it would provide. Ember's biggest goal is building a shared foundation for our ecosystem to build on, and this requires a careful commitment to stability.
130 |
131 | While we could make a "small" breaking release soon after 2.0, breaking changes inherently fragment the ecosystem, and we hope that the years to come bring more stability for add-on authors and tool-makers, not less.
132 |
133 | ## Bring Your Own Compatibility
134 |
135 | Some libraries attempt to thread the needle of IE8 compatibility by asking users to bring their own compatibility libraries. They write the internals of their framework as if IE8 did not exist, and require end users to use polyfills to make the environment look equivalent to newer browsers. For example, React asks users to bring libraries such as `es5-shim`, `es5-sham`, `console-polyfill` and `html5shiv` if they want IE8 support.
136 |
137 | Facebook.com supports IE8, and uses React, so there is a path to using React with IE8. This path is partially documented on the React website. This gives us a perfect opportunity to evaluate the impact of this strategy in the real world. We admire the React team's work in this area: support for IE8 is difficult and triaging and fixing IE8 bugs requires diligent effort.
138 |
139 | After reviewing the [IE8-compatibility issues filed on React.js tracker](https://github.com/facebook/react/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+ie8), we believe there are significant user experience costs to this strategy.
140 |
141 | We have spent considerable effort on first-class IE8 support in Ember 1.x, and we feel that users who require IE8 support will have a better experience using Ember 1.14 (with the subset of the ecosystem that supports 1.x) than trying to cobble together a solution that works reliably in a version of Ember with second-class, bring-your-own-compatibility support.
142 |
143 | # Unresolved questions
144 |
145 | We are relying on the community to help us weigh the above tradeoffs. The more data you can provide about the browser makeup of your customers (especially as it affects revenue), the better we can reason whether now is the time to remove IE8 (and possibly IE9) support.
146 |
147 | If you cannot share the information publicly, please email whatever information you consider useful to browserusage@emberjs.com. We will keep it in the strictest of confidence.
--------------------------------------------------------------------------------
/text/0046-registry-reform.md:
--------------------------------------------------------------------------------
1 | - Start Date: 2015-04-09
2 | - RFC PR: https://github.com/emberjs/rfcs/pull/46
3 | - Ember Issue: https://github.com/emberjs/ember.js/pull/11440
4 |
5 | # Summary
6 |
7 | Fully encapsulate and privatize the `Container` and `Registry` classes by
8 | exposing a select subset of public methods on `Application` and
9 | `ApplicationInstance`.
10 |
11 | # Motivation
12 |
13 | The `Container` and `Registry` classes currently lead a confusing life of
14 | semi-private exclusion within Ember applications. They are undocumented
15 | publicly but not fully private either, as knowledge of their particulars is
16 | required for developing both initializers and unit tests. This situation has
17 | become untenable as the new `Registry` class has been extracted from
18 | `Container`, and the complexity of their usage has grown across
19 | `Application` and `ApplicationInstance` classes.
20 |
21 | We can bring sanity to this situation by continuing the work started at the
22 | `Application` level to expose methods such as `register` and `inject` from the
23 | internally maintained `Registry`.
24 |
25 | Furthermore, once `Container` and `Registry` are fully private, their
26 | architecture and documentation can be cleaned up. For instance, a
27 | `Container` can freely reference its associated `Registry` as `registry`
28 | rather than `_registry`, as it can be assumed that only framework developers
29 | will reference this property.
30 |
31 | # Detailed design
32 |
33 | `Application` will expose the following methods from its internally maintained
34 | registry:
35 |
36 | * `register`
37 | * `inject`
38 | * `registerOptions` - mapped to `Registry#options`
39 | * `registerOptionsForType` - mapped to `Registry#optionsForType`
40 |
41 | `ApplicationInstance` will also expose the the same methods. However, these
42 | methods will be exposed from its own internally maintained registry, which
43 | has the associated `Application`'s registry configured as a "fall back". No
44 | direct path will be provided from the `ApplicationInstance` to the
45 | `Application`'s registry.
46 |
47 | `ApplicationInstance` will also expose the following methods from its
48 | internally maintained container:
49 |
50 | * `lookup`
51 | * `lookupFactory`
52 |
53 | `ApplicationInstance` will cease exposing `container`, `registry`, and
54 | `applicationRegistry` publicly.
55 |
56 | `Application` initializers will receive a single argument to `initialize`:
57 | `application`.
58 |
59 | Likewise, `ApplicationInstance` initializers will receive a single argument
60 | to `initialize`: `applicationInstance`.
61 |
62 | `Container` and `Registry` will be made fully private and documented as
63 | such. Each `Container` will freely reference its associated `Registry` as
64 | `registry` rather than `_registry`.
65 |
66 | [ember-test-helpers](https://github.com/switchfly/ember-test-helpers)
67 | will provide an `isolatedApplicationInstance` method instead of an
68 | `isolatedContainer` for unit testing. A mechanism will be developed to specify
69 | which initializers should be engaged in the initialization of this instance.
70 | In this way, we can avoid duplication of registration logic, as is currently
71 | done in a most un-DRY manner in the [isolatedContainer](https://github.com/switchfly/ember-test-helpers/blob/master/lib/ember-test-helpers/isolated-container.js#L56-L79).
72 |
73 | # Drawbacks
74 |
75 | This refactor will require maintaining backwards compatibility and
76 | deprecation warnings until Ember 2.0. This will temporarily increase
77 | internal code complexity and file sizes.
78 |
79 | # Alternatives
80 |
81 | The obvious alternative is to make `Container` and `Registry` fully public
82 | and documented. An application's registry would be available as a `registry`
83 | property. An application instance's container would remain available as
84 | `container`.
85 |
86 | We could still pass an `Application` into application initializers
87 | and an `ApplicationInstance` into application instance initializers.
88 |
89 | If this alternative is taken, I would suggest that `Application` should
90 | deprecate `register` and `inject` in favor of calling the equivalents on its
91 | public `registry`.
92 |
93 | Regardless of which alternative is chosen, we should ensure that the public
94 | aspects of container and registry usage are well documented.
95 |
96 | # Unresolved questions
97 |
98 | * Are the public methods listed above sufficient or should any others be
99 | exposed?
100 |
101 | * What mechanism should be used to engage initializers in unit and
102 | integration tests? Should test modules simply have an `initializers` array,
103 | similar to the current `needs` array?
104 |
105 | * Given the semi-private nature of containers and registries, we may not need
106 | to worry about semver for deprecations. However, we should be good citizens
107 | and properly deprecate as much as possible. Some real world use cases in
108 | initializers will no doubt be a surprise, so we need to tread carefully.
109 |
--------------------------------------------------------------------------------
/text/0050-improved-actions.md:
--------------------------------------------------------------------------------
1 | - Start Date: 2014-05-06
2 | - RFC PR: https://github.com/emberjs/rfcs/pull/50
3 | - Ember Issue: (leave this empty)
4 |
5 | # Summary
6 |
7 | The `{{action` helper should be improved to allow for the creation of
8 | closed over functions that can be passed between components and passed
9 | the action handlers.
10 |
11 | See [this example JSBin from @rwjblue](http://emberjs.jsbin.com/rwjblue/466/edit?html,js,output)
12 | for a demonstration of some of these ideas.
13 |
14 | # Motivation
15 |
16 | Block params allow data to be passed from one component to a downstream
17 | component, however there is currently no way to pass a callback to a downstream
18 | component.
19 |
20 | # Detailed design
21 |
22 | First, the existing uses of `{{action` will be maintained. An action can be attached to an
23 | element by using the helper in element space:
24 |
25 | ```hbs
26 | {{! app/index/template.hbs }}
27 | {{! submit action will hit immediate parent }}
28 |
29 | ```
30 |
31 | An action can be passed to a component as a string:
32 |
33 | ```hbs
34 | {{! app/index/template.hbs }}
35 | {{my-button on-click="submit"}}
36 | ```
37 |
38 | ```js
39 | // app/components/my-button/component.js
40 | export default Ember.Component.extend({
41 | click: function(){
42 | this.sendAction('on-click');
43 | }
44 | });
45 | ```
46 |
47 | Or a default action can be passed:
48 |
49 | ```hbs
50 | {{! app/index/template.hbs }}
51 | {{my-button action="submit"}}
52 | ```
53 |
54 | ```js
55 | // app/components/my-button/component.js
56 | export default Ember.Component.extend({
57 | click: function(){
58 | this.sendAction();
59 | }
60 | });
61 | ```
62 |
63 | In all these cases, `submit` is called on the parent context relative to the scope `action` is
64 | attached in. The value `"submit"` is attached to the component in the last two as
65 | `this.attrs.on-click` or `this.attrs.action`, although it is not directly used.
66 |
67 | ### Creating closure actions
68 |
69 | Closure actions are created in a template and may be used in all places a string
70 | action name can be used. For example, this current functionality:
71 |
72 | ```hbs
73 |
74 | ```
75 |
76 | Would be written using a closure action as:
77 |
78 | ```hbs
79 |
80 | ```
81 |
82 | The functionality is exactly the same as the string-based action example.
83 | How does that happen?
84 |
85 | * `(action "submit")` reads the `submit` function off the current scope's
86 | `actions.submit` property.
87 | * It then creates a closure to call that function.
88 | * `{{action` receives that function as a param. It registers a listener (in
89 | this case on click) and when fired calls the closure function.
90 |
91 | Consider usage on the calling side. With the current string-based actions:
92 |
93 | ```hbs
94 | {{my-component action="submit"}}
95 | ```
96 |
97 | ```js
98 | export default Ember.Component.extend({
99 | click: function(){
100 | this.sendAction(); // submit action, legacy
101 | // this.attrs.action is a string
102 | this.attrs.action; // => "submit"
103 | }
104 | });
105 | ```
106 |
107 | With closure actions, the action is available to call directly. The `(action` helper
108 | wraps the action in the current context and returns a function:
109 |
110 | ```hbs
111 | {{my-component action=(action "submit")}}
112 | ```
113 |
114 | ```js
115 | export default Ember.Component.extend({
116 | click: function(){
117 | this.sendAction(); // submit action, legacy
118 | // this.attrs.action is a function
119 | this.attrs.action(); // submit action, new style
120 | }
121 | });
122 | ```
123 |
124 | A more complete example follows, with a controller for context:
125 |
126 | ```js
127 | // app/index/controller.js
128 | export default Ember.Controller.extend({
129 | actions: {
130 | submit: function(){
131 | // some submission task
132 | }
133 | }
134 | });
135 | ```
136 |
137 | ```hbs
138 | {{! app/index/template.hbs }}
139 | {{my-button save=(action 'submit')}}
140 | ```
141 |
142 | ```js
143 | // app/components/my-button/component.js
144 | export default Ember.Component.extend({
145 | click: function(){
146 | this.attrs.save();
147 | // for backwards compat, you may also this.sendAction('save');
148 | }
149 | });
150 | ```
151 |
152 | ### Hole punching with a closure-based action
153 |
154 | The current system of action bubbling falls down quickly when you want to pass a message through multiple
155 | levels of components. A closure based action system helps address this.
156 |
157 | Instead of relying on bubbling, a closure action wraps an action from the current context's
158 | `actions` hash in a function that will call it on that context. For example:
159 |
160 | ```hbs
161 | {{! app/index/template.hbs }}
162 | {{my-form submit=(action 'submit')}}
163 | ```
164 |
165 | ```hbs
166 | {{! app/components/my-form/template.hbs }}
167 | {{my-button on-click=attrs.submit}}
168 | ```
169 |
170 | ```hbs
171 | {{! app/components/my-button/template.hbs }}
172 |
173 | ```
174 |
175 | ```js
176 | // app/components/my-button/component.js
177 | export default Ember.Component.extend({
178 | click: function(){
179 | this.attrs['on-click']();
180 | // for backwards compat, you may also this.sendAction();
181 | }
182 | });
183 | ```
184 |
185 | A closure action can also be called by an action handler:
186 |
187 | ```hbs
188 | {{! app/index/template.hbs }}
189 | {{my-form submit=(action 'submit')}}
190 | ```
191 |
192 | ```hbs
193 | {{! app/components/my-form/template.hbs }}
194 | {{my-button on-click=submit}}
195 | ```
196 |
197 | ```hbs
198 | {{! app/components/my-button/template.hbs }}
199 |
200 | ```
201 |
202 | Lastly, closure actions allow for yielding an action to a block. For example:
203 |
204 | ```hbs
205 | {{! app/index/template.hbs }}
206 | {{my-form save=(action 'submit') as |submit reset|}}
207 |
208 | {{! ^ goes to my-form's save attr property, which
209 | is the submit action on the outer scope }}
210 |
211 | {{! ^ goes to my-form }}
212 |
213 | {{! ^ goes to outer scope }}
214 | {{/my-form}}
215 | ```
216 |
217 | ```hbs
218 | {{! app/components/my-form/template.hbs }}
219 | {{yield attrs.save (action 'reset')}}
220 | ```
221 |
222 | ```js
223 | // app/components/my-form/component.js
224 | export default Ember.Component.extend({
225 | actions: {
226 | reset: function(){
227 | // rollback
228 | }
229 | }
230 | });
231 | ```
232 |
233 | ### Currying arguments with a closure-based action
234 |
235 | With string-based actions, an argument can be passed to the called function. For
236 | example:
237 |
238 | ```hbs
239 |
240 | ```
241 |
242 | ```js
243 | export default Ember.Component.extend({
244 | actions: {
245 | save: function(model) {
246 | model.save();
247 | }
248 | }
249 | });
250 | ```
251 |
252 | Closure actions allow for another opportunity to curry arguments. Arguments
253 | set by an element action helper simply add to the end of the arguments list:
254 |
255 | ```hbs
256 | {{! app/index/template.hbs }}
257 | {{my-component save=(action "save" model)}}
258 | ```
259 |
260 | ```hbs
261 | {{! app/components/my-component/template.hbs }}
262 |
263 | ```
264 |
265 | ```js
266 | // app/index/controller.js
267 | export default Ember.Controller.extend({
268 | actions: {
269 | save: function(model, prefs) {
270 | model.set('prefs', prefs);
271 | model.save();
272 | }
273 | }
274 | });
275 | ```
276 |
277 | Multiple arguments can be curried or set at any level. If an action is called ala
278 | `this.attrs.save(additionalPrefs)`, that final argument is added
279 | to the end of the arguments list.
280 |
281 | ### Re-targeting the scope of a closure action
282 |
283 | The `target` option may be provided to specify what scope the closure is called
284 | with. For example:
285 |
286 | ```hbs
287 | {{! app/index/template.hbs }}
288 |
289 | ```
290 |
291 | Much like with the `{{action` helper, passing both a
292 | target and a bound argument will throw.
293 |
294 | The default target for a closure is always the current scope.
295 |
296 | * When routable components land, the current component will be the default target.
297 | * If a controller is the current scope, that controller will also be a default target.
298 | * A route will *never* be a closure action target. String actions will continue
299 | to have their current behavior of bubbling to the route.
300 |
301 | A later proposal will determine how actions on a route are passed to a routable
302 | component.
303 |
304 | ### Return values of a closure action
305 |
306 | Closure actions return the returned value of their called function. For example:
307 |
308 | ```js
309 | // app/index/controller.js
310 | export default Ember.Controller.extend({
311 | actions: {
312 | submit: function(){
313 | return 'great success';
314 | }
315 | }
316 | });
317 | ```
318 |
319 | ```hbs
320 | {{! app/index/template.hbs }}
321 | {{my-button save=(action 'submit')}}
322 | ```
323 |
324 | ```js
325 | // app/components/my-button/component.js
326 | export default Ember.Component.extend({
327 | click: function(){
328 | var result = this.attrs.save();
329 | // for backwards compat, you may also this.sendAction('save') but
330 | // in that case you do not have access to the return value.
331 | result; // => 'great success'
332 | }
333 | });
334 | ```
335 |
336 | ### Actionable object with INVOKE
337 |
338 | `{{mut` is a new helper in Ember.js. It is not yet widely used in Ember apps, but its
339 | interaction with the action helper is important to align early on.
340 |
341 | Mut objects represent a modifiable value. For example with tag-based components:
342 |
343 | ```hbs
344 | {{! app/index/template.hbs }}
345 |
346 | ```
347 |
348 | This will cause a mutable property to be added to `attrs`. To update the name,
349 | `this.attrs.name.update(newName)` can be called. The value can be read (in
350 | JavaScript) as `this.attrs.name.value`.
351 |
352 | Often, a mutable value will be set as the result of an action. Mutable values
353 | can be called actionable. For example:
354 |
355 | ```hbs
356 | {{! app/index/template.hbs }}
357 |
358 | ```
359 |
360 | ```js
361 | // app/components/my-form/component.js
362 | export default Ember.Component.extend({
363 | click() {
364 | const value = this.get('newValue');
365 | this.attrs.submit(value);
366 | }
367 | });
368 | ```
369 |
370 | What is happening here?
371 |
372 | * `(mut model.name)` creates a mutable object for the `model.name` value.
373 | * `{{action (mut model.name)}}` tests the passed object for a property with the
374 | key `INVOKE` (an internal symbol). This value is a function that updates the mutable value.
375 | * Action wraps the calling of the `INVOKE` property in a function like any
376 | other action, and passes it to the `attrs`.
377 |
378 | Thus, when the action is called the argument is passed to `INVOKE` which uses
379 | it to update the mutable value. This is a simple way to enable the "actions up"
380 | part of component-driven app architecture without ceremony around changing state.
381 |
382 | ### Plucking a property from the first argument with value
383 |
384 | A component (or when Ember supports this better, an element) may emit an event
385 | object and pass it to an action. In this case the value will need to be read off
386 | the event before it can be passed to the action function. For example:
387 |
388 | ```hbs
389 | {{input input=(action 'setName')}}
390 | ```
391 |
392 | ```js
393 | export default Ember.Component.extend({
394 | actions: {
395 | setName(event) {
396 | this.get('model').set('name', event.target.value);
397 | }
398 | }
399 | });
400 | ```
401 |
402 | The action serves only to read the value off of the event. Here the `value`
403 | option can be used as sugar to accomplish the same task:
404 |
405 | ```hbs
406 | {{input input=(action (mut model.name) value="target.value")}}
407 | ```
408 |
409 | The `value` path is read off of whatever the first argument to the actions is.
410 |
411 | * `(mut model.name)` becomes a function, our action
412 | * When the `input` event fires, the function is called with the event as the
413 | first argument.
414 | * The first argument is re-written to the value of `event.target.value`
415 | * The function wrapping the `mut` is set
416 | * The `mut` is updated.
417 |
418 | This option is designed to align with future plans for `on-some-event` handlers
419 | for html elements.
420 |
421 | # Drawbacks
422 |
423 | Currently `{{action` is only used in an element space:
424 |
425 | ```hbs
426 |
427 | ```
428 |
429 | The closure usage is a new, perhaps `action` is not the right word. However the two
430 | behaviors are pretty similar in their conceptual behavior.
431 |
432 | * `{{action` in element space attaches an event listener that fires a bubbling
433 | action.
434 | * `(action` closes over an action from the current scope so it can be attached
435 | via `{{action` or passed around and called later.
436 |
437 | This confusion should go away as we move to an `on-click` event listener pattern,
438 | ala `
98 | {{/with}}
99 | ```
100 |
101 | The returned value of the `(action` nested helper (a function) closes over the
102 | action being called (`actions.save` on the context and the `model` property).
103 | The `{{action` helper can accept this resulting value and invoke the action
104 | when the user clicks.
105 |
106 | The `(component` helper will close over a component name. The
107 | `{{component` helper will be modified to accept this resulting value and invoke
108 | the component:
109 |
110 | ```hbs
111 | {{#with (component "user-profile") as |uiPane|}}
112 | {{component uiPane}}
113 | {{/with}}
114 | ```
115 |
116 | Additionally, a bound value may be passed to the `(component` helper. For
117 | example `(component someComponentName)`.
118 |
119 | Attrs for the final component can also be closed over. Used with yield, this
120 | allows for the creation of components that have attrs from other scopes. For
121 | example:
122 |
123 | ```hbs
124 | {{! app/components/user-profile.hbs }}
125 | {{yield (component "user-profile" user=user.name age=user.age)}}
126 | ```
127 |
128 | ```hbs
129 | {{#user-profile user=model as |profile|}}
130 | {{component profile}}
131 | {{/user-profile}}
132 | ```
133 |
134 | Of course attrs can also be passed at invocation. They smash any conflicting
135 | attrs that were closed over. For example `{{component profile age=lyingUser.age}}`
136 |
137 | Passing the resulting value from `(component` into JavaScript is permitted,
138 | however that object has no public properties or methods. Its only use would
139 | be to set it on state and reference it in template somewhere.
140 |
141 | ### Hash helper
142 |
143 | Unlike values, components are likely to have specific names that are semantically
144 | relevent. When yielded to a new scope, allowing the user to change the name
145 | of the component's variable would quickly lead to confusing addon documentation.
146 | For example:
147 |
148 | ```hbs
149 | {{#with (component "user-profile") as |dropDatabaseUI|}}
150 | {{component dropDatabaseUI}}
151 | {{/with}}
152 | ```
153 |
154 | The simplest way to enforce specific names is to make building hashes
155 | of components (or anything) easy. For example:
156 |
157 | ```hbs
158 | {{#with (hash profile=(component "user-profile")) as |userComponents|}}
159 | {{component userComponents.profile}}
160 | {{/with}}
161 | ```
162 |
163 | The `(hash` helper is a generic builder of objects, given hash arguments. It
164 | would also be useful in the same manner for actions:
165 |
166 | ```hbs
167 | {{#with (hash save=(action "save" model)) as |userActions|}}
168 |
169 | {{/with}}
170 | ```
171 |
172 | ### Component helper shorthand
173 |
174 | To complete building a viable DSL, `.` invocation for `{{` components will be
175 | introduced. For example this `{{component` invocation:
176 |
177 | ```hbs
178 | {{#with (hash profile=(component "user-profile")) as |userComponents|}}
179 | {{component userComponents.profile}}
180 | {{/with}}
181 | ```
182 |
183 | Could be converted to drop the explicit `component` helper call.
184 |
185 | ```hbs
186 | {{#with (hash profile=(component "user-profile")) as |userComponents|}}
187 | {{userComponents.profile}}
188 | {{/with}}
189 | ```
190 |
191 | A component can be invoked like this only when it was created by the
192 | `(component` nested helper form. For example unlike with the `{{component`
193 | helper, a string is not acceptable.
194 |
195 | To be a valid invocation, one of two criteria must be met:
196 |
197 | * The component can be called as a path. For example `{{form.input}}` or `{{this.input}}`
198 | * The component can be called as a helper. For example `{{form.input value=baz}}` or `{{this.input value=baz}}`
199 |
200 | And of course a `.` must be present in the path.
201 |
202 | # Drawbacks
203 |
204 | This proposal encourages aggressive use of the `(` nested helper syntax.
205 | Encouraging this has been slightly controversial.
206 |
207 | No solution for angle components is presented here. The syntax for `.`
208 | notation in angle components is coupled to a decision on the syntax for
209 | bound, dynamic angle component invocation (a `{{component` helper for angle
210 | components basically).
211 |
212 | `(component 'some-component'` may be too verbose. It may make sense to simply
213 | allow `(some-component`.
214 |
215 | Other proposals have leaned more heavy on extending factories in JavaScript
216 | then passing an object created in that space. Some arguments against this:
217 |
218 | * Getting the container correct is tricky. Who sets it when?
219 | * Properties on the classes would not be naturally bound, as they are in this proposal.
220 | * As soon as you start setting properties, you likely want a `mut` helper,
221 | `action` helper, etc, in JavaScript space.
222 | * Keeping the component lookup in the template layer allows us to take advantage
223 | of changes to lookup semantics later, such as local lookup in the pods
224 | proposal.
225 |
226 | # Alternatives
227 |
228 | All pain, no gain. Addons really want this.
229 |
230 | # Unresolved questions
231 |
232 | There has been discussion of if a similar mechanism should be available for
233 | helpers.
234 |
--------------------------------------------------------------------------------
/text/0065-deprecation-warning-handlers.md:
--------------------------------------------------------------------------------
1 | - Start Date: 2015-06-30
2 | - RFC PR: https://github.com/emberjs/rfcs/pull/65
3 | - Ember Issue: (leave this empty)
4 |
5 | # Summary
6 |
7 | Deprecations and warnings in Ember.js should have configurable runtime handlers.
8 | This allows default behavior (logging, raise when `RAISE_ON_DEPRECATION` is true)
9 | to be overridden by an enviornment (Ember's tests), addon, or other tool
10 | (like the Ember Inspector).
11 |
12 | Ember-Data and the Ember Inspector have both requested a public
13 | API for changing how deprecation and warning messages are handled. The requirements
14 | for these and other requests are complex enough that deferring the message
15 | behavior into a runtime hook is the suggested path.
16 |
17 | # Motivation
18 |
19 | `Ember.deprecate` and `Ember.warn` usually log messages. With `ENV.RAISE_ON_DEPRECATION`
20 | all deprecations will throw an exception. In some scenarios, this
21 | is less than ideal:
22 |
23 | * Ember itself needs a way to silence some deprecations before their usage
24 | is completely removed from tests. For example, many view APIs in Ember 1.13.
25 | * The Ember inspector desires to raise on specific deprecations, or silence
26 | specific deprecations.
27 | * Ember-Data also desires to silence some deprecations in tests
28 |
29 | In [PR #1141](https://github.com/emberjs/ember.js/pull/11419)
30 | a private log level API has been introduced, which allows finer grained control
31 | if specific deprecations should be logged, throwing an error or be silenced
32 | completely. For example:
33 |
34 | ```js
35 | Ember.Debug._addDeprecationLevel('my-feature', Ember.Debug._deprecationLevels.LOG);
36 | // ...
37 | Ember.deprecate("x is deprecated, use Y instead", false, { id: 'my-feature' });
38 | ```
39 |
40 | Initially a public version of this API was discussed, but it quickly became
41 | clear that a runtime hook provided more flexibility without incurring the
42 | cost of a complex log-level API.
43 |
44 | Note that "runtime" refers to Ember itself. A custom handler could be injected
45 | into Ember-CLI's template compilation code. "runtime" in this context still
46 | refers to handling deprecations raised during compilation.
47 |
48 | # Detailed design
49 |
50 | A handler for deprecations can be registered. This handler will be called
51 | with relevent information about a deprecation, including guarantees about
52 | the presence of these items:
53 |
54 | * The deprecation message
55 | * The version number where this deprecation (and feature) will be removed
56 | * The "id" of this deprecation, a stable identifier independent of the message
57 |
58 | Additionally, an application instance may be passed with the options. An example
59 | handler would look like:
60 |
61 | ```js
62 | import { registerHandler } from "ember-debug/deprecations";
63 |
64 | registerHandler(function deprecationHandler(message, options) {
65 | // * message is the deprecation message
66 | // * options.until is the version this deprecation will be removed at
67 | // * options.id is the canonical id for this deprecation
68 | if (options.until === "2.4.0") {
69 | throw new Error(message);
70 | } else {
71 | console.log(message);
72 | }
73 | });
74 | ```
75 |
76 | Warnings are similar, but will not recieve an `until` value:
77 |
78 | ```js
79 | import { registerHandler } from "ember-debug/warnings";
80 |
81 | registerHandler(function warningHandler(message, options) {
82 | // * message is the warning message
83 | // * options.id is the canonical id for this warning
84 | if (options.id !== 'view.rerender-on-set') {
85 | console.log(message);
86 | }
87 | });
88 | ```
89 |
90 | ##### chained handlers
91 |
92 | Since several handlers may be registered, a method of deferring to a previously
93 | registered handler must be allowed. A third option is passed to handlers, the
94 | function `next` which represents the previously registered handler.
95 |
96 | For example:
97 |
98 | ```js
99 | import { registerHandler } from "ember-debug/deprecations";
100 |
101 | registerHandler(function firstDeprecationHandler(message, options, next) {
102 | console.warn(message);
103 | });
104 |
105 | registerHandler(function secondDeprecationHandler(message, options, next) {
106 | if (options.until === "2.4.0") {
107 | throw new Error(message);
108 | }
109 | next(...arguments);
110 | });
111 | ```
112 |
113 | The first registed handler will receive Ember's default behavior as `next`.
114 |
115 | ##### new assertions for deprecate and warn
116 |
117 | Ember's APIs for deprecation and warning do not currently require any information
118 | beyond a message. It is proposed that deprecations be **required** to pass
119 | the following information:
120 |
121 | * Message
122 | * Test
123 | * Canonical id (with a format of `package-name.some-id`)
124 | * Release when this deprecation will be stripped
125 |
126 | For example:
127 |
128 | ```
129 | import Ember from "ember";
130 |
131 | Ember.deprecate("Some message", false, {
132 | id: 'ember-routing.query-params',
133 | until: '3.0.0'
134 | });
135 | ```
136 |
137 | If this information is not present and assertion will be made.
138 |
139 | Warnings likewise will be required to pass a canonical id:
140 |
141 | ```
142 | import Ember from "ember";
143 |
144 | Ember.warn("Some warning", {id: 'ember-debug.something'});
145 | ```
146 |
147 | ##### default handlers
148 |
149 | The default handler for deprecation should be quite simple, and mirrors current
150 | behavior:
151 |
152 | ```js
153 | function defaultDeprecationHandler(message, options) {
154 | if (Ember.ENV.RAISE_ON_DEPRECATION) {
155 | throw new Error(format(message, options));
156 | } else {
157 | console.log(format(message, options));
158 | }
159 | }
160 | ```
161 |
162 | The default handler for warnings would be simple `console.log`.
163 |
164 | # Drawbacks
165 |
166 | By not providing a robust log-level API, we are punting complexity to the
167 | consumer of this API. For a low-level tooling API such as this one, it seems
168 | and appropriate tradeoff.
169 |
170 | # Alternatives
171 |
172 | Each app can stub out `deprecate` and `warn`.
173 |
174 | # Unresolved questions
175 |
176 | `RAISE_ON_DEPRECATION` could be considered deprecated with this new API.
177 |
--------------------------------------------------------------------------------
/text/0091-weakmap.md:
--------------------------------------------------------------------------------
1 | - Start Date: 2015-09-11
2 | - RFC PR: https://github.com/emberjs/rfcs/pull/91
3 | - Ember Issue: [#12224](https://github.com/emberjs/ember.js/pull/12224) / [#12990](https://github.com/emberjs/ember.js/pull/12990) / [#13688](https://github.com/emberjs/ember.js/pull/13688)
4 |
5 | # Summary
6 |
7 | Introduce `Ember.WeakMap` (`@ember/weakmap`), an ES6 enspired WeakMap. A
8 | WeakMap provides a mechanism for storing and retriving private state. The
9 | WeakMap itself does not retain a reference to the state, allowing the state to
10 | be reclaimed when the key is reclaimed.
11 |
12 | A traditional WeakMap (and the one that will be part of the language) allows
13 | for weakness from key -> map, and also from map -> key. This allows either the
14 | Map, or the key being reclaimed to also release the state.
15 |
16 | Unforunately, this bi-directional weakness is problemative to polyfil. Luckily,
17 | uni-directional weakness, in either direction, "just works". A polyfil must
18 | just choose a direction.
19 |
20 | *Note: Just like ES2015 WeakMap, only non null Objects can be used as keys*
21 | *Note: `Ember.WeakMap` can be used interchangibly with the ES2015 WeakMap. This
22 | will allow us to eventually cut over entirely to the Native WeakMap.*
23 |
24 | # Motivation
25 |
26 | It is a common pattern to want to store private state about a specific object.
27 | When one stores this private state off-object, it can be tricky to understand
28 | when to release the state. When one stores this state on-object, it will be
29 | released when the object is released. Unfortunately, storing the state
30 | on-object without poluting the object itself is non-obvious.
31 |
32 | As it turns out, Ember's Meta already solves this problem for
33 | listeners/caches/chains/descriptors etc. Unfortunately today, there is no
34 | public API for apps or addons to utilize this. `Ember.WeakMap` aims to be
35 | exactly that API.
36 |
37 | Some examples:
38 |
39 | * https://github.com/offirgolan/ember-cp-validations/blob/master/addon/utils/cycle-breaker.js
40 | * https://github.com/stefanpenner/ember-state-services/ (will soon utilize the user-land polyfil of this) to prevent common leaks.
41 |
42 | # Detailed design
43 |
44 | ## Public API
45 |
46 | ```js
47 | import WeakMap from '@ember/weak-map'
48 |
49 | var private = new WeakMap();
50 | var object = {};
51 | var otherObject = {};
52 |
53 | private.set(object, {
54 | id: 1,
55 | name: 'My File',
56 | progress: 0
57 | }) === private;
58 |
59 | private.get(object) === {
60 | id: 1,
61 | name: 'My File',
62 | progress: 0
63 | });
64 |
65 |
66 | private.has(object) === true;
67 | private.has(otherObject) === false;
68 |
69 | private.delete(object) === private;
70 | private.has(object) === false;
71 | ```
72 |
73 | ## Implementation Details
74 |
75 | The backing store for `Ember.WeakMap` will reside in a lazy `ownMap` named
76 | `weak` on the key objects `__meta__` object.
77 |
78 | Each `WeakMap` has its own internal GUID, which will be the name of its slot,
79 | in the key objects meta weak bucket. This will allow one object to belong in
80 | multiple weakMaps without chance of collision.
81 |
82 | Concrete Implementation: https://github.com/emberjs/ember.js/pull/12224
83 | Polyfill: https://www.npmjs.com/package/ember-weakmap
84 |
85 | # Drawbacks
86 |
87 | * implementing bi-direction Weakness in userland is problematic.
88 | * Using WeakMap will insert a non-enumerable `meta` onto the key Object.
89 |
90 | # Alternatives
91 |
92 | * Weakness could be implemented in the other direction, but this has questionable utility.
93 |
94 | # Unresolved questions
95 |
96 | N/A
97 |
--------------------------------------------------------------------------------
/text/0095-router-service.md:
--------------------------------------------------------------------------------
1 | - Start Date: 2015-09-24
2 | - RFC PR: https://github.com/emberjs/rfcs/pull/95
3 | - Ember Issue: https://github.com/emberjs/ember.js/pull/13868
4 |
5 | # Summary
6 |
7 | This RFC proposes:
8 |
9 | - creating a public `router` service that is a superset of today's `Ember.Router`.
10 |
11 | - codifying and expanding the supported public API for the `transition` object that is currently passed to `Route` hooks.
12 |
13 | - introducing the `get-route-info` template helper
14 | - introducing the `#with-route-info` template keyword
15 | - introducing the `readsRouteInfo` static property on `Component` and `Helper`.
16 |
17 | These topics are closely related because they share a unified `RouteInfo` type, which will be described in detail.
18 |
19 | # Motivation
20 |
21 | Given the modern Ember concepts of Components and Services, it is clear that routing capability should be exposed as a Service. I hope this is uncontroversial, given that we already implement it as a service internally, and given that usage of these nominally-private APIs is already becoming widespread.
22 |
23 | The immediate benefit of having a `RouterService` is that you can inject it into components, giving them a friendly way to initiate transitions and ask questions about the current global router state.
24 |
25 | A second benefit is that we have the opportunity to add new capabilities to the `RouterService` to replace several common patterns in the wild that dive into private internals in order to get things done. There are several places where we leak internals from router.js, and we can plug those leaks.
26 |
27 | A `RouterService` is great for asking global questions, but some questions are not global and today we incur complexity by treating them as if they are. For example:
28 |
29 | - `{{link-to}}` can use implicit models from its context, but that breaks when you're trying to animate to or from a state where those models are not present.
30 |
31 | - `{{link-to}}` has a lot of complexity and performance cost that deals with changing its active state, and the precise timing of when that should happen.
32 |
33 | - there is no way to ask the router what it would do to handle a given URL without actually visiting that URL.
34 |
35 | All of the above can be addressed by embracing what is already internally true: "the current route" is not a single global, it's a dynamically-scoped variable that can have different values in different parts of the application simultaneously.
36 |
37 | # Detailed design
38 |
39 | ## RouterService
40 |
41 | By way of a simple example, the router service behaves like this:
42 |
43 | ```js
44 | import Component from 'ember-component';
45 | import service from 'ember-service/inject';
46 |
47 | export default Component.extend({
48 | router: service(),
49 | actions: {
50 | goToMars() {
51 | this.get('router').transitionTo('planet.mars');
52 | }
53 | }
54 | });
55 | ```
56 |
57 | Like any Service, it can also be injected into Helpers, Routes, etc.
58 |
59 | ### Relationship between EmberRouter and RouterService
60 |
61 | Q: "Why are you calling this thing 'router' when we already have a router? Shouldn't the new thing be called 'routing' or something else?".
62 |
63 | A: We shouldn't have two things. From the user's perspective, there is just "the router", and it happens to be available as a service. While we're free to continue implementing it as multiple classes under the hood, the public API should present as a single, coherent concept.
64 |
65 | Terminology:
66 |
67 | - `EmberRouter` is the class that we already have today, defined in `ember-routing/system/router` and available publicly as `Ember.Router`
68 | - `RouterService` is the new class I am proposing.
69 |
70 | `EmberRouter` has the following public API today:
71 |
72 | - `map`
73 | - `location`
74 | - `rootURL`
75 | - `willTransition`
76 | - `didTransition`
77 |
78 | That API will be carried over verbatim to `RouterService`, and the publicly accessible `Ember.Router` class will *become* `RouterService`. In terms of implementation, I expect the existing `EmberRouter` class will continue to exist mostly unchanged. But public access to it will be moderated through `RouterService`.
79 |
80 | ### New Methods: Initiating Transitions
81 |
82 | ```js
83 | transitionTo(routeName, ...models, queryParams)
84 | replaceWith(routeName, ...models, queryParams)
85 | ```
86 |
87 | These two have the same semantics as the existing methods on `Ember.Route`:
88 |
89 | ### New Method: Checking For Active Route
90 |
91 | - `isActive(routeName, ...models, queryParams)`
92 |
93 | The arguments have the same semantics as `transitionTo`, the return value is a boolean. This should provide the same logic that determines whether to put an active class on a `link-to`. Here's an example of how we can implement `is-active` as a helper, using this method:
94 |
95 | ```js
96 | import Helper from 'ember-helper';
97 | import service from 'ember-service/inject';
98 | import observer from 'ember-metal/observer';
99 |
100 | export default Helper.extend({
101 | router: service(),
102 | compute([routeName, ...models], hash) {
103 | let allModels;
104 | if (hash.models) {
105 | allModels = models.concat(hash.models);
106 | } else {
107 | allModels = models;
108 | }
109 | return this.get('router').isActive(routeName, ...models, hash.queryParams);
110 | },
111 | didTransition: observer('router.currentRoute', function() {
112 | this.recompute();
113 | });
114 | });
115 | ```
116 |
117 | ```hbs
118 | {{!- Example usage -}}
119 |