
Formed in 2009, the Archive Team (not to be confused with the archive.org Archive-It Team) is a rogue archivist collective dedicated to saving copies of rapidly dying or deleted websites for the sake of history and digital heritage. The group is 100% composed of volunteers and interested parties, and has expanded into a large amount of related projects for saving online and digital history.
History is littered with hundreds of conflicts over the future of a community, group, location or business that were "resolved" when one of the parties stepped ahead and destroyed what was there. With the original point of contention destroyed, the debates would fall to the wayside. Archive Team believes that by duplicated condemned data, the conversation and debate can continue, as well as the richness and insight gained by keeping the materials. Our projects have ranged in size from a single volunteer downloading the data to a small-but-critical site, to over 100 volunteers stepping forward to acquire terabytes of user-created data to save for future generations.
The main site for Archive Team is at archiveteam.org and contains up to the date information on various projects, manifestos, plans and walkthroughs.
This collection contains the output of many Archive Team projects, both ongoing and completed. Thanks to the generous providing of disk space by the Internet Archive, multi-terabyte datasets can be made available, as well as in use by the Wayback Machine, providing a path back to lost websites and work.
Our collection has grown to the point of having sub-collections for the type of data we acquire. If you are seeking to browse the contents of these collections, the Wayback Machine is the best first stop. Otherwise, you are free to dig into the stacks to see what you may find.
The Archive Team Panic Downloads are full pulldowns of currently extant websites, meant to serve as emergency backups for needed sites that are in danger of closing, or which will be missed dearly if suddenly lost due to hard drive crashes or server failures.
EisenbergEffect commentedSep 13, 2021
•
edited by nicholasrice
Overview
Server-side rendering (SSR) is the process of generating HTML markup for an arbitrary experience on the server and sending the result to the client. The primary benefit of SSR is that it can increase real and perceived first-load performance. It does this by reducing the amount of JavaScript that needs to be parsed and executed to render a view, instead delegating that rendering code to the server. This means the first bits a client receives can be the HTML representing the view, not the JavaScript required to create the markup.
This document outlines the core features required to enable SSR for the FAST library. It describes the features in mid-level detail to aid feature and task planning.
The key browser feature added to enable SSR for Web Components is called declarative shadow DOM. Simply put, this feature enables writing HTML in such a way that the browser itself will attach the shadow DOM of a custom element automatically without JavaScript. This allows pre-generating web-component shadow DOMs on the server and automatic upgrades on the client, meaning full web-component experience generation outside the browser is possible.
FAST’s approach to SSR will be to conform to the interfaces proposed by Lit (details below) that will allow SSR interoperability with other Web Component libraries.
Challenges / Risks
Hydrating Components
In most cases, components will need to be hydrated on the client, with hydration meaning that control of the component is give back to the JavaScript constructor for that element and it generally functions as if it had not been initially created using declarative shadow DOM. This JavaScript execution has a cost, and that cost eats into any potential performance improvements gained by SSR, though it is likely not substantially different than client-side rendering in the first place.
State Changes
There are times when the state on the client may be different than the state used during HTML generation on the server. This can mean the DOM must update immediately upon hydration, causing jarring visual changes, such as UI components moving, text content changing, themes changing, etc.
Additional Data Transfer
In most (but not all) cases the Web Component and application logic JavaScript will still need to be sent to the client. This can mean that more data must be sent to the client in total to support SSR. This is due to the need to send a larger HTML file and any additional JavaScript to facilitate client-side pre-hydration (such as event capturing) and styling.
Code Compression
The template renderer implements a streaming model where template results can begin to be sent to the client prior to the entire template being processed. Leveraging this feature likely means that code compression techniques like gzipping cannot be leveraged.
Considerations / Features
Community Interface Conformance
Lit has unofficially proposed a interface to facilitate SSR interop of Custom Elements from different Custom Element templating libraries. The general problem this solves is that because each Custom Element library (FAST, Lit, etc) will contain distinct implementation details for component creation, lifecycles, and templating features and syntaxes, the processes for creating a SSR string representation of that component will also be specific to the library. The common interface serves as an interop mechanism for delegating rendering to renderers written by library authors for their library’s components. This manifests as two distinct categories of code:
Template Renderer
The template renderer is the piece of code that converts a string representing a custom element with attributes () into the SSR result of that element. It does this by simulating DOM connection for the element instantiation, updating any necessary properties from attributes, and yielding out any shadow-DOM the element has as declarative shadow DOM. This will be the bulk of the SSR implementation.
The template renderer is responsible for expanding arbitrary HTML templates into a stream of HTML string data expanded with declarative shadow DOM and any HTML attributes dynamically added by custom element construction and connection lifecycles.
The template renderer will look something like:
Whole Page Rendering
The renderer will function as the mechanism to render both custom element shadow DOMs and arbitrary HTML fragments, including entry point experiences that include HTML document information such as doctype, html, head, and body elements, meta tags, scripts, styles, etc. This will facilitate simple usage with fast-element’s html tagged-template literal.
SSR Directive Implementations
FAST’s directive architecture is closely tied to a DOM implementation, so the renderer will need to patch implementations of directives so that they execute in a NodeJS environment with a minimal DOM shim. This is an opportunity for FAST to implement a directive plugin model for all first-party directives, including:
Architecting this feature using a plugin model will allow any author to create their own directives and SSR implementations (if necessary) and additionally override any first-party directive SSR implementations.
Light DOM Emission
Part of the community interfaces establish a mechanism for a custom element to emit to light DOM instead of shadow DOM. This is to support browsers that do not natively support shadow DOM. Emission to light DOM will need to change the behavior of the renderer to skip the declarative shadow DOM template element, instead simply emitting the shadow DOM as children of the custom element.
Preventing Rendering
There may be cases where an author may wish to prevent emission of all custom element constructors or custom element instances. We can add a mechanism to opt constructors out by configuring the ElementRenderer, and there is potential to upstream that mechanism into the community protocol.
Opting individual component instances is trickier because that information will need to be embedded into the component implementation itself. I think we’ll need some method that can be implemented into a component constructor that can be executed by the ElementRenderer or the renderer.
ElementRenderer
The ElementRenderer facilitates interop between other renderers and orchestrates custom element creation and rendering. It is responsible for recognizing custom element constructors it should be responsible for, creating custom element instances, dispatching attributes, and invoking the renderer for a custom element. This is a small and somewhat trivial piece of code.
Stylesheet Emission
Custom Element stylesheets are a potential source for significant redundant shadow DOM content that must be sent as part of the SSR string. If the SSR result is streamed and not pre-compiled, these redundancies will not be able to benefit from compression processes that otherwise would help negate the negative impacts of redundant string data. It is therefore important to devise a technique to memoize stylesheets on the server and re-hydrate them on the client to avoid a significant increase in redundant data transfer.
This is not a problem that is specific to FAST, so there is a potential opportunity here to either expand the community protocol proposed by Lit to help address this problem, or to propose a new community protocol.
FASTStyle Custom Element
We will address the above by injecting a small bit of JavaScript into the yielded SSR string. This JavaScript will define a custom element that manages a cache of stylesheets. The cache is populated by assigning the
cssattribute of an element instance with the raw CSS string and assigning the ‘key’ attribute to be a hash of the sheet.During rendering, the renderer will emit the above element for all stylesheets in the component. If the stylesheet is being reflected to this element for the first time, the
cssattribute will be populated with the stylesheet content. The id of the stylesheet, a hash of the sheet content, will always be assigned.When the FASTStyle element constructs on the client, the first construction will always be the instance of the element with stylesheet content (because content is only emitted to the first instance). It will populate its cache with a CSSStyleSheet instance with the stylesheet content from the server. It will then append the sheet to its root element (the custom element’s shadow root). Any subsequent constructions of the FASTStyle element for that stylesheet will skip CSSStyleSheet construction and append the sheet immediately to the root element.
In cases where CSSStyleSheet isn’t constructable, the FASTStyle will create style elements instead, and append those to the root element.
Custom Element Client-Side Hydration
Phase 1 - Naïve implementation
This initial implementation does not “hydrate” the server side rendered HTML but allows the component to re-create HTML during its usual initialization phase.
Phase 2 – Comprehensive DOM hydration
Hydration involves a different process from custom-element upgrading and connection because the shadow DOM for the element will have already been created. In hydration cases, the DOM should be re-used to preserve the performance benefits of rendering on the server.
To do this, several aspects of fast-element will need to change:
Command Buffering
Command buffering involves catching any user interaction that happens between page load and hydration of custom elements.
Typically command buffering can be complicated since in general (non-web component) scenarios it is not always known in advance what user events may occur or need to be captured. This results in large, complicated logic intended to handle any generic web page code. However, in the case of web components and FAST specifically the user events that any component needs to respond to are declared in the template and therefore the SSR Renderer can know exactly which events on each component it needs to care about.
FAST SSR Command Buffering can therefore be accomplished by emitting a small amount of code into the tag which will define a global scope method for recording user events. This could be an invisible web component or simply a vanilla javascript object. This method needs only to take in some form of identifier (hash or otherwise) for the exact element within a specific component instance that is handling the event along with the event object and place them into a queue. Then as the Element Renderer parses the template on the server, whenever it encounters an event directive (@click, @input, etc.) it can emit an appropriate event attribute into the tag (click, input, etc.) with code that will call the global event recording method if that event occurs.
On the client side as FAST Element hydrates the components whenever it needs to bind an event it can check with the Command Buffer to see if it has recorded that event and if so match the recorded event to the newly bound expression. FAST can then clean up the original event attribute so that it will no longer record events after upgrading is complete. Then once all components are upgraded FAST can trigger the Command Buffer to replay the events in the order that they were received.
The Command Buffering process will then be:
Phase 2 - CLI / Tooling
A command line interface would be beneficial for facilitating SSR as part of the project creation and a continuing use as part of a pipeline.
Testing Plan
Renderer
The renderer will largely leverage playwright to test the product of the render process. This will allow navigating to a real browser page containing the SSR result, testing real elements. We should capture tests for all the following:
a. Unbound and bound
a. Unbound and bound
Hydration
Hydration will be a feature of fast-element, so tests for hydration should exist in that package. Test cases will be added for:
FASTStyle Element
Tests for the FASTStyle element will be relatively trivial because we’ll just be testing isolated custom element behavior. We should use playwright to avoid requiring multiple unit testing architectures in the SSR package. Tests should include:
The text was updated successfully, but these errors were encountered: