Support for custom elements#121
Support for custom elements#121diffcunha wants to merge 9 commits intochoojs:masterfrom nearform:custom-elements
Conversation
|
Very cool! |
lib/browser.js
Outdated
| if (props.is) { | ||
| if (typeof props.is === 'function') { | ||
| if (!customElements.get(props.is.tagName)) { | ||
| customElements.define(props.is.tagName, props.is, props.is.options) |
There was a problem hiding this comment.
I'm not feeling great about this line - the spec really just wants you to register elements once. This would register an element on every call.
There was a problem hiding this comment.
It only registers if it isn't register yet if (!customElements.get(props.is.tagName))
|
I'm open to landing this, but in order to do so it would need to include tests for client, server & transforms too. It's a pretty big patch, and I suspect there might be a few rough edges. |
|
@yoshuawuyts PR updated, only babel transform is missing. @goto-bus-stop and @AndyOGo pushed a few commits replacing |
|
@diffcunha Correct I refactored all tests, which where using |
|
@AndyOGo I rebased already. I have a question: how did you made the |
|
@diffcunha That's weird. Actually I did nothing... just run |
|
@diffcunha the transform output didn't use the main |
|
@goto-bus-stop that’s it! Thanks |
| }) | ||
| }) | ||
|
|
||
| test('xlink:href', function (t) { |
There was a problem hiding this comment.
These tests (svg and xlink:href) were removed since the createElement function is now responsible for handling those and not the transform itself
| var x = 'disabled' | ||
| var x = { disabled: 'disabled' } | ||
| html` | ||
| <button ${x} id="lol" /> |
There was a problem hiding this comment.
I'm not sure if this is supposed to be allowed as it creates ambiguity with props spread
var obj = { prop: 'value' }
var tree = html`<button ${obj}>foobar</button>`There is also some inconsistency within the previous implementations:
var x = 'disabled'
var tx = html`<button ${x}>foobar</button>`
// tx.outerHTML == <button disabled="disabled">foobar</button>
var y = false
var ty = html`<button disabled=${x}>foobar</button>`
// ty.outerHTML == <button>foobar</button>
tx.outerHTML !== ty.outerHTMLRegardless, I can spend some time making prop spread and this shorthand notation to work together
There was a problem hiding this comment.
It is supposed to be allowed, yes
|
@yoshuawuyts PR updated. The major change here is that transformed code is generated around our |
|
Had to take some time to get used to this massive refactor, but I like the |
goto-bus-stop
left a comment
There was a problem hiding this comment.
some comments and q's. thanks!
| if (typeof props.is === 'function') { | ||
| if (!window.customElements.get(props.is.tagName)) { | ||
| window.customElements.define(props.is.tagName, props.is, props.is.options) | ||
| } |
There was a problem hiding this comment.
I don't think the renderer should be in charge of defining custom elements. I'm also worried about introducing nonstandard static properties on HTML element classes but it doesn't seem like there's a way around that. Having Component.tagName is fine, but IMO automagic registration and Component.options is not nanohtml's business
There was a problem hiding this comment.
OK. In fact the tagName prop only serves the purpose of registration. I understand that registration shouldn't not be a concern of nanohtml, it will be then up to the dev to register the components before rendering
There was a problem hiding this comment.
Sure registration is out of scope from nanohtml
| objectProperty: function (key, value, computed) { | ||
| return computed | ||
| ? ('[' + key + ']' + ':' + value) | ||
| : (key + ':' + value) |
There was a problem hiding this comment.
choo aims to work in IE 11 + so we can't use ES6+ syntax in the transform output
| return html + '.createElement(' + tag + ',' + props + ',' + children + ')' | ||
| }, | ||
| callObjectAssign (objects) { | ||
| return 'Object.assign(' + objects.join(',') + ')' |
There was a problem hiding this comment.
Object.assign also doesn't exist yet in IE11 … choo uses the xtend module, that might be good (deduped = no extra bytes 🎉 ). maybe xtend can be exposed as nanohtml/lib/merge or so, and that can be required in the output, that way we don't add a peer dependency.
IE 11 will probably be dropped in choo 7 but not yet: choojs/choo#616
| node.arguments[0].value === 'nanohtml') { | ||
| // html and choo/html have no other exports that may be used | ||
| node.edit.update('{}') | ||
| node.edit.update('{ createElement: require("' + path.join(node.arguments[0].value, '/lib/createElement") }')) |
There was a problem hiding this comment.
would it make sense to just do update('require("/path/to/createElement")') here and call that function directly as html() or createElement() (not renaming the variable is probably easier) instead of doing html.createElement?
choo/html is not going to have an export named choo/html/lib/createElement, and bel didn't have one either. maybe this should use require.resolve('./createElement') instead? or path.relative() from the input file
There was a problem hiding this comment.
Yeah, that was my first idea, but then I thought it wouldn't be a good idea to "reuse" an already existent api. I mean, one might want to:
var html = require('nanohtml')
var foo = function (strings, ...keys) {
// do stuff
return html(strings, ...keys)
}
var bar = html`<span>HELLO</span>`You are absolutely right about bel and choo/html. Regarding choo/html, I could still replace with nanohtml/lib/createElement or something like it. Regarding bel, I'm not so sure but probably it won't be supported in this version on nanohtml given that it doesn't expose a createElement function
| @@ -0,0 +1,98 @@ | |||
| var appendChild = require('./append-child') | |||
There was a problem hiding this comment.
small nit: the other files use dashes rather than camelcase
| var aexpr | ||
| var bexpr | ||
|
|
||
| if (iscexpr(a)) aexpr = a // c-expression |
There was a problem hiding this comment.
what's the c in c-expression?
There was a problem hiding this comment.
c-expression as in concat-expression. They should be probably called meta-expressions since that what they are
| fs.unlinkSync(FIXTURE) | ||
| t.ifError(err) | ||
| t.ok(src.indexOf('document.createElement("div")') !== -1, 'created a tag') | ||
| t.ok(src.indexOf('html.createElement("div",{"class":"whatever "+abc},[xyz])') !== -1, 'created a tag') |
There was a problem hiding this comment.
to only test if the tag is being created checking html.createElement("div", would be good but, not a big deal
| browserField: false, | ||
| transform: path.join(__dirname, '../../') | ||
| }) | ||
| // don't b.require createElement, it will hang this test |
There was a problem hiding this comment.
oops this is probably this browserify bug: browserify/browserify#1707 looks like that might still be an issue after all
| }) | ||
| path.unshiftContainer('body', t.importDeclaration([ | ||
| t.importDefaultSpecifier(createElement) | ||
| ], t.stringLiteral(library + '/lib/createElement'))) |
There was a problem hiding this comment.
I think we should just always output nanohtml/lib/createElement in the babel transform, only nanohtml exposes that. this means that transformed code will have a peer dependency on nanohtml, but that was also a limitation in the yo-yoify babel plugin.
| var transform = require('./transform') | ||
|
|
||
| module.exports = function yoYoify (file, opts) { | ||
| var SUPPORTED_VIEWS = ['nanohtml', 'bel', 'yo-yo', 'choo/html'] |
There was a problem hiding this comment.
good, choo.view is long gone afaik 👍
|
@goto-bus-stop @diffcunha: Kudos on the team work! Where did we land on this? |
|
@diffcunha I think that should be all which is needed. |
|
PS: I also provided tests 💪 |
This PR adds the support for custom components (web components)
Blocked on: choojs/hyperx#68