From a042e5292ab4f53735f84490babd54389962c859 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Thu, 11 Jun 2015 20:07:59 -0400 Subject: [PATCH] Add "why upgrades" document. --- proposals/Why-Upgrades.md | 125 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 proposals/Why-Upgrades.md diff --git a/proposals/Why-Upgrades.md b/proposals/Why-Upgrades.md new file mode 100644 index 00000000..60528614 --- /dev/null +++ b/proposals/Why-Upgrades.md @@ -0,0 +1,125 @@ +# Why Upgrades + +This document attempts to motivate the "upgrades" feature of custom elements. + +## Introduction + +In this section, we lay some groundwork to explain how upgrades work, before getting in to the why. + +### Simple upgrades example + +The essence of upgrading is to allow element registration after parsing has already occurred for the relevant tag names. At this point any elements with appropriate name that already exist in the DOM are “upgraded” to the correct prototype, and their `createdCallback()` is run. For a simple example, consider + +```html + + + +``` + +(This assumes [the Dmitry solution](https://lists.w3.org/Archives/Public/public-webapps/2015JanMar/0230.html) is put in place to avoid the current spec's undesirable constructor generation.) + +### How does this work + +Essentially, while parsing, the UA keeps track of all elements with dashes in their name. When `document.registerElement` is called, it looks up the matching elements (which are currently instances of `HTMLElement`), then “proto-swizzles” them: it mutates their internal [[Prototype]] property to be the newly-appropriate prototype (`XFoo.prototype` in this example). At the same time, it runs the appropriate `createdCallback()`. In JavaScript, this looks approximately like + +```js +Object.setPrototypeOf(el, XFoo); +el.createdCallback(); +``` + +Note that (under the Dmitry solution) the end result is exactly the same as `new XFoo()`, due to how the constructor is defined. + +### Drawbacks + +The issue most often raised about upgrading is how it exposes an intermediate state, before the element finally settles down into its final API. That is, there are points in time where our `` is simply an HTMLElement. This can be observed by any script that runs before the `document.registerElement` call, or by script inside the element's `createdCallback`, during registration. For an example of the latter, consider + +```html + + + +… +``` + +If `XFoo.prototype.createdCallback` looks at `this.nextElementSibling`, it would find a `HTMLElement`, instead of an upgraded `XFoo`. + +## Why Upgrades Are Important + +In this section we argue that despite the drawbacks mentioned above, upgrades are still an important feature for the custom elements ecosystem. In a world without built-in upgrades, libraries and authors will be forced to re-invent them in a non-interoperable way, with all the same drawbacks in place and more. + +### Modern front-end development + +To see why upgrades are important, it's first necessary to recognize two important trends in modern front-end development: + +- ubiquitous use of _asynchronous modules_, and +- an embrace of _progressive enhancement_ and server-side rendering. + +Modern front-end development is extensively focused around asynchronous module systems and asynchronous module loading, including tools that compile ES2015 module syntax down to something that can be run and loaded in today's browsers. During development, or in production for simpler apps, every JavaScript module file is loaded asynchronously. For more complicated production apps, the modules are split up into logical bundles. An initial bundle is loaded (asynchronously, of course, so as not to block parsing) during initial render; others loaded as the user performs actions throughout the site, such as navigation, that necessitate loading relevant supporting code. + +At the same time, there's been a resurgence of interest in progressively-enhanced content. In its modern incarnation, this is accomplished by first doing "server-side rendering" of some sort, to deliver static HTML to the client, and only later "hydrating" that HTML into fully-interactive framework-supported content. The main advantages cited for this are crawlability and speed (i.e. time-to-first-content). For more information, see the ways in which major frameworks are scrambling to support their users in this regard: [Ember](http://tomdale.net/2015/02/youre-missing-the-point-of-server-side-rendered-javascript-apps/), [Angular](https://docs.google.com/document/d/1q6g9UlmEZDXgrkY88AJZ6MUrUxcnwhBGS0EXbVlYicY/edit?pli=1), and [React](https://facebook.github.io/react/docs/top-level-api.html#react.rendertostring). + +To summarize, modern web apps consist of: + +1. An initial payload of largely-static content, delivered directly from the server, which may not be fully interactive but is crawlable and immediately visible; +2. Asynchronously loaded functionality, often provided by a full-featured component framework, for making that content interactive. (Ember's component definitions; Angular's directive definitions; React's element definitions.) + +A very simple example of this in action can be seen with GitHub's [`