Custom Elements in Servo
2017-08-24 Summary of the Custom Element GSoC Project.
This summer I had the pleasure of implementing Custom Elements in Servo under the mentorship of jdm.
Introduction
Custom Elements are an exciting development for the Web Platform. They are apart of the Web Components APIs. The goal is to allow web developers to create reusable web components with first-class support from the browser. The Custom Element portion of Web Components allows for elements with custom names and behaviors to be defined and used via HTML tags.
For example, a developer could create a custom element called fancy-button
which has special
behavior (for example, ripples from material design). This element is reusable and can be used
directly in HTML:
<fancy-button>My Cool Button</fancy-button>
For examples of cool web components check out webcomponents.org.
While using these APIs directly is very powerful, new web frameworks are emerging that harness the power of Web Component APIs and give developers even more power. One major contender with frontend web frameworks is Polymer. The Polymer framework builds on top of Web Components and removes boilerplate and makes using web components easier.
Another exciting framework using Custom Elements is A-Frame (supported by Mozilla). A-Frame is a WebVR framework that allows developers to create entire Virtual Reality experiences using HTML elements and javascript. There has been some recent work in getting WebVR and A-Frame functional in Servo. Implementing Custom Elements removes the need for Servo to rely on a polyfill.
For more information on what Custom Elements are and how to use them, I would suggest reading Custom Elements v1: Reusable Web Components.
Implementation
Before I began the implementation of Custom Elements, I broke down the spec into a few major pieces.
- The
CustomElementRegistry
- Custom element creation
- Custom element reactions
The CustomElementRegistry
keeps track of all the defined custom elements for a single window
.
The registry is where you go to define new custom elements and later Servo will use the registry
to lookup definitions give a possible custom element name. The bulk of the work in this section of
the implementation was validating custom element definitions.
Custom element creation is the process of taking a custom element definition and running the
defined constructor on a HTMLElement
or the element extends. This can happen either when a new
element is created, or after an element has been created via an upgrade reaction.
The final portion is triggering custom element reactions. There are two types of reactions:
- Callback reactions
- Upgrade reactions
Callback reactions fire when custom elements:
- are connected from the DOM tree
- are disconnected from the DOM tree
- are adopted into a new document
- have an attribute that is modified
When the reactions are triggered, the corresponding lifecycle method of the Custom Element is called. This allows the developer to implement custom behavior when any of these lifecycle events occur.
Upgrade reactions are used to take a non-customized element and make it customized by running the defined constructor. There is quite a bit of trickery going on behind the scenes to make all of this work. I wrote a post about custom element upgrades explaining how they work and why they are needed.
I used Gecko’s partial implementation of Custom Elements as a reference for a few parts of my implementation. This became extrememly useful whenever I had to use the SpiderMonkey API.
Roadblocks
As with any project, it is difficult to foresee big issues until you actually start writing the implementation. Most parts of the spec were straightforward and did not yield any trouble while I was writing the implementation; however, there were a few difficulties and unexpected problems that presented themselves.
One major pain-point was working with the SpiderMonkey API. This was more due to my lack of experience with the SpiderMonkey API. I had to learn how compartments work and how to debug panics coming from SpiderMonkey. bzbarsky was extremely helpful during this process; they helped me step through each issue and understand what I was doing wrong.
While I was in the midst of writing the implementation, I found out about the HTMLConstructor
attribute. I had missed this part of the spec during the planning phase. The HTMLConstructor
WebIDL attribute marks certain HTML elements that can be extended and generates a custom constructor
for each that allows custom element constructors to work (read more about this in custom element
upgrades).
Notable Pull Requests
- Implement custom element registry
- Custom element creation
- Implement custom element reactions
- Custom element upgrades
Conclusions
I enjoyed working on this project this summer and hope to continue my involvement with the Servo project. I have a gsoc repository that contains a list of all my GSoC issues, PRs, and blog posts. I want to extend a huge thanks to my mentor jdm and to bzbarsky for helping me work through issues when using SpiderMonkey.