domino icon indicating copy to clipboard operation
domino copied to clipboard

Custom elements support in domino

Open majo44 opened this issue 8 years ago • 9 comments

Hello

Firstly let me thanks for awesome work on domino.

Some time ago I started work on some idea, about 'universal custom elements' General idea is to create custom-elements once and use them (render) on server (node) and on client (browser) side.

I found the server-components which is using domino for rendering the content. But it is using very tricky way to use the domino because domino itself do not implements custom-elements spec.

On other hand I found the skate.js which is using incremental-dom for rendering but just for browser.

Based on that ides I made some POC where:

  1. I patched domino to support the custom-elements by self. So I modified the base types members for play well with custom-elements. But this was also very tricky.
  2. I created JSX pragma (h) function which is detecting the env (node or browser) and if it is node it is using domino on server (something similar to jsx-to-dom) and on client is using incremental-dom I'm using JSX because it is simple to decide later how the markup have to be rendered, and it plays well with domino and incremental-dom This works nice, I have now real progressive enhancement solution where the markup is prerendered on server and can be enhanced on client (eg attach events handlers ect..). Enhanced means not rerendered again but really updated with the changes (thanks to incremental-dom)

But I think this can be done much better. So I comes to conclusion that domino itself can support custom-elements :) Later I want to talk with skate.js about integrate this work there.

So about this PR. This PR contains some almost done work of implementing the custom-elements in domino. The code is maybe not brilliant, but I tried to explain the all changes in comments. Firstly I want to know your opinion, about integrate this to master, and later I can polish the code. I used platform web-platform-tests for test the solution and most critical now passed. Some of the not working because of lack of some api support in domino (eg document.createAttribute ...)

I decided to expose the customElements registry outside of document and window because I think there should be a way to define custom elements globally instead of doing this on each document creation (each server request).

Waiting for your feedback. Best Regards Pawel.

majo44 avatar Feb 14 '17 18:02 majo44

Any feedback ?

majo44 avatar Feb 28 '17 13:02 majo44

Any feedback on this PR? We would love to see custom element support in domino!

greaterweb avatar Mar 23 '17 00:03 greaterweb

I'd really like to see this merged, it looks pretty good. Any feedback from domino?

ricardocasares avatar Apr 04 '17 19:04 ricardocasares

Have you tried this?

var domino = require('domino')
window = domino.createWindow();
document = window.document;
HTMLElement = domino.impl.HTMLElement;

require('@webcomponents/custom-elements')
window.customElements.define('x-tag', class extends HTMLElement {
constructor(){
  super();
  console.log('constructing')
}
connectedCallback(){
  this.innerHTML += 'content';
  this.classList.add('x-class');
}
})

document.body.innerHTML += '<x-tag></x-tag>'
console.log(document.body.innerHTML);

Seemingly, it works. On the other hand, why it shouldn't work :)

cronon avatar Apr 11 '17 07:04 cronon

@cronon The problem with domino + @webcomponents/custom-elements is that polyfill requires global window ( so the document will be also global). For server side rendering, where you will want to have async rendering (eg some custom elements will load by self some data), you should have separate document for each separate request.

majo44 avatar Apr 11 '17 10:04 majo44

@cronon I figured out there is possibility to have separate window/document for each request by using eg Zone.js:

function runInDomZone(fn) {
    let window = domino.createWindow(' ');
    let document: any = window.document;
    return Zone.current.fork({
        name: 'DOMZone',
        properties: {
            window: window,
            document: document
        }
    }).run(fn);
}

Object.defineProperty(global, 'window', {
    get: () => {
        return Zone.current.get('window');
    }
});

Object.defineProperty(window, 'document', {
    get: () => {
        return Zone.current.get('document');
    }
});

So I tried to "patch" domino by @webcomponents/custom-elements, and unfortunately it doesn't work :(, There is error: Cannot assign to read only property 'insertBefore' of object '#<Object>' the whole api of Node, Element is not configurable/writable :(

majo44 avatar Apr 18 '17 11:04 majo44

Any plans to continue with support for Custom Elements?? PR looks fairly simple but was abandoned 3 years ago. Hoping to use @angular/elements and have them rendered on the server

intellix avatar Jan 15 '21 13:01 intellix

Wanted to indicate that I was seeing the same need as a result of using Angular Universal (server-side rendering.) Custom CSS elements have been used as a way to theme the app, and suporting that in domino would permit the server-side equivalent.

bob-walters avatar May 06 '21 23:05 bob-walters

I believe many people still would love to see this one merged.

Draykee avatar Oct 26 '23 09:10 Draykee