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

Custom elements support in domino #96

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

majo44
Copy link

@majo44 majo44 commented Feb 14, 2017

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 majo44 changed the title [WIP] Custom elements support in domino Custom elements support in domino Feb 17, 2017
return !name || !xml.isValidQName(name) || name.indexOf('-') < 0 || forbiddenNames.indexOf(name) > -1 || name.toLowerCase() !== name;
}

function CustomElementRegistry(registry, document) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am totally new to domino, but shouldn't you just use Class?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also new :) but as I see domino should work with node 0.8 so in code the class syntax is not used, unfortunately, I had to use class syntax in one place and I do not know how to avoid it :(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't noticed anything regarding this at package.json or in the readme.
@fgnass
Though it makes sense to have engine key in package json. Semantic increment of version shouldn't hurt anyone since Classes supported from 4th version.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rootical
Please look at travis :(

@majo44
Copy link
Author

majo44 commented Feb 28, 2017

Any feedback ?

@greaterweb
Copy link

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

@ricardocasares
Copy link

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

@cronon
Copy link

cronon commented Apr 11, 2017

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 :)

@majo44
Copy link
Author

majo44 commented Apr 11, 2017

@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
Copy link
Author

majo44 commented Apr 18, 2017

@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 '#' the whole api of Node, Element is not configurable/writable :(

@intellix
Copy link

intellix commented Jan 15, 2021

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

@bob-walters
Copy link

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.

@Draykee
Copy link

Draykee commented Oct 26, 2023

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants