Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the custom element instance responsible for rendering. #65

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 35 additions & 5 deletions src/lib/dom-shim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,49 @@ import fetch from 'node-fetch';
*/
export const getWindow = (props: {[key: string]: any} = {}): {[key: string]: any} => {

const HTMLElement = class HTMLElement {
const attributes: WeakMap<any, Map<string, string>> = new WeakMap();
const attributesFor = (element: any) => {
let attrs = attributes.get(element);
if (!attrs) {
attributes.set(element, attrs = new Map());
}
return attrs;
}

abstract class HTMLElement {
get attributes() {
return Array.from(attributesFor(this)).map(([name, value]) => ({name, value}));
}
abstract attributeChangedCallback?(name: string, old: string | null, value: string | null): void;
setAttribute(name: string, value: string) {
const old = attributesFor(this).get(name) || null;
attributesFor(this).set(name, value);
if (this.attributeChangedCallback) {
this.attributeChangedCallback(name, old, value);
}
}
removeAttribute(name: string) {
const old = attributesFor(this).get(name) || null;
attributesFor(this).delete(name);
if (this.attributeChangedCallback) {
this.attributeChangedCallback(name, old, null);
}
}
hasAttribute(name: string) {
return attributesFor(this).has(name);
}
attachShadow() {
return {};
return { host: this };
}
};

const Document = class Document {
class Document {
get adoptedStyleSheets() {
return [];
}
};

const CSSStyleSheet = class CSSStyleSheet {
class CSSStyleSheet {
replace() {}
};

Expand All @@ -51,7 +81,7 @@ export const getWindow = (props: {[key: string]: any} = {}): {[key: string]: any
observedAttributes: string[];
};

const CustomElementRegistry = class CustomElementRegistry {
class CustomElementRegistry {
__definitions = new Map<string, CustomElementRegistration>();

define(name: string, ctor: {new (): HTMLElement}) {
Expand Down
44 changes: 0 additions & 44 deletions src/lib/element-renderer.ts

This file was deleted.

76 changes: 30 additions & 46 deletions src/lib/lit-element-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,60 +12,44 @@
* http://polymer.github.io/PATENTS.txt
*/

import {ElementRenderer} from './element-renderer.js';
import {LitElement, TemplateResult, CSSResult} from 'lit-element';
import {render, renderValue, RenderInfo} from './render-lit-html.js';
import {LitElement, CSSResult} from 'lit-element';
import {render} from './render-lit-html.js';

export type Constructor<T> = {new (): T};

/**
* An object that renders elements of a certain type.
*/
export class LitElementRenderer implements ElementRenderer {
constructor(public element: LitElement) {}

*renderElement(): IterableIterator<string> {
const renderResult = ((this.element as unknown) as {
render(): TemplateResult;
}).render();
function *renderChildren(element: LitElement, result: any, useShadowRoot: boolean): IterableIterator<string> {
if (useShadowRoot) {
yield '<template shadowroot="open">';
// Render styles.
const ctor = customElements.get(this.element.tagName!);
const styles = [(ctor as any).styles].flat(Infinity);
let hasCssResult = false;
}
// Render styles
const styles = [(element.constructor as typeof LitElement).styles]
.flat(Infinity)
.filter(style => style instanceof CSSResult);
if (styles.length) {
yield '<style>';
for (const style of styles) {
if (style instanceof CSSResult) {
if (!hasCssResult) {
hasCssResult = true;
yield '<style>';
}
// TODO(sorvell): support ShadyCSS transformed styles. These should
// be written once.
//const scoped = StyleTransformer.css(style.cssText, tagName);
yield style.cssText;
}
}
if (hasCssResult) {
yield '</style>';
yield (style as CSSResult).cssText;
}
yield* render(renderResult);
yield '</template>';
yield '</style>';
}

setProperty(name: string, value: unknown) {
(this.element as any)[name] = value;
// Render html
yield* render(result, {deferChildHydration: true});
if (useShadowRoot) {
yield '</template>';
}
}

setAttribute(name: string, value: string | null) {
// Note, this should always exist for LitElement, but we're not yet
// explicitly checking for LitElement.
if (this.element.attributeChangedCallback) {
this.element.attributeChangedCallback(name, null, value as string);
}
// Install SSR render hook
LitElement.render = function(result: unknown, container: Element | DocumentFragment, _options: any) {
const instance = (container as ShadowRoot).host ? (container as ShadowRoot).host : container;
if (!(instance instanceof LitElement)) {
throw new Error('For compatibiltiy with SSR, renderRoot must either be the shadowRoot of the LitElement or the LitElement itself.')
}
instance.ssrRenderChildren = renderChildren(instance, result, Boolean((container as ShadowRoot).host));
};

renderLight(renderInfo: RenderInfo) {
const templateResult = (this.element as any)?.renderLight();
return templateResult ? renderValue(templateResult, renderInfo) : '';
}
// Make rendering synchronous to connectedCallback()
const connectedCallback = LitElement.prototype.connectedCallback;
LitElement.prototype.connectedCallback = function() {
connectedCallback.call(this);
this.performUpdate(true);
}
1 change: 0 additions & 1 deletion src/lib/render-html-file-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export async function renderFile(options: RenderAppOptions) {
fetch,
process: {env: {NODE_ENV: 'production', ...options.env || {}}}
});
debugger
// Make sure file exists; if not, use fallback
let file = path.join(options.root, url.pathname);
let exists = false;
Expand Down
Loading