wavesoft / dot-dom

.dom is a tiny (512 byte) template engine that uses virtual DOM and some of react principles
Apache License 2.0
806 stars 53 forks source link

Feature: Accept arrays as children #6

Closed SilentCicero closed 7 years ago

SilentCicero commented 7 years ago

Many rendering engines accept arrays as children, they just flatten them out.

For example:

H('div', {}, ['something']);

This throws an error. Many virtual dom/actual dom builders accept this. I think this would be easy to add, small in size and enable everyone to use this module with things like hyperx.

wavesoft commented 7 years ago

Hello @SilentCicero , by design I try to keep this library at max 512 bytes, meaning that I cut scope when functionality is not impaired.

On this context, I will try to find a smart way to achieve this, but you are more than welcome to contribute or discuss ideas :-)

wavesoft commented 7 years ago

Ps you can always use the spread operator (without babel transformations) instead

SilentCicero commented 7 years ago
const flatten = (ary) => ary.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);

;-)

SilentCicero commented 7 years ago

How I use it now:

P: props[vnodeFlag]                                               // If the props argument is a renderable VNode,
        && children.unshift(props) && {C: flatten(children)}                   // ... prepend it to the children
        || (props.C = flatten(children)) && props     
SilentCicero commented 7 years ago

works like a charm.

wavesoft commented 7 years ago

Is the library result (after gzip) smaller than or equal to 512 bytes after this addition? :smile:

SilentCicero commented 7 years ago

Not sure, I can check.

SilentCicero commented 7 years ago

That is all valid ES6, you may just want to measure the bytes of that string and add it in.

SilentCicero commented 7 years ago

I think it may be over, but not sure: 84 bytes with this utf-8 bytecounter. Gzipped not sure.

https://mothereff.in/byte-counter

wavesoft commented 7 years ago

Actually, I might be able to satisfy your request. Try this:

    P: props[vnodeFlag]                                               // If the props argument is a renderable VNode,
        ? {C: [].concat(props, children)}                             // ... prepend it to the children
        : (props.C = [].concat(children)) && props                    // ... otherwise append 'C' to the property

This fits in 510 bytes 👍

SilentCicero commented 7 years ago

@wavesoft damn, doesn't seem to work nicely with hyperx. I think because hyperx presents deeply nested arrays as well.

wavesoft commented 7 years ago

Ouch, what kind of structure is that 😑 I guess we have to go with the flattening version if we want to support hyperx. Unless there is another way to configure it? I would really like to avoid this...

If you want to test the "512 byte" constraint, try your changes and re-build the library, making sure it never gets bigger than needed.

~$ npm install
~$ npm run build
~$ ls -l dotdom.min.js.gz 
-rw-r--r--  1 foo  bar   510B Feb 13 22:00 dotdom.min.js.gz
wavesoft commented 7 years ago

Hey @SilentCicero , can you give me an example expression with hyperx that is affected?

SilentCicero commented 7 years ago

@wavesoft sure, also, hyperx is huge. Many libs use it. It makes life awesome for template string users.

We may want to consider breaking this module up (without sacrificing size of course), so that we can reuse this good work elsewhere. dot-dom***.

const hyperx = require('hyperx');
require('dot-dom');

function createElement(tag, props, ...children) {
  return global.H(tag, props, children); // double array here
}

module.exports = hyperx(createElement);
const dot = require('../index.js');

R(dot`<div>
        Cool!
        <div onclick=${() => console.log('Yes!')}>Something Else</div>
        <a href="cool">Yes!</a>
      </div>`, document.body);

With flatten it works like a charm. You could also do this.. Export the module for npm nicely, then allow me to plugin a custom child transform. That would solve the problem as well. I just plugin flatten on my side.

wavesoft commented 7 years ago

Hey @SilentCicero , out of curiosity, is the build from #15 working in your case? I realised I had a typo in the snippet I pasted above. It should actually be:

    P: props[vnodeFlag]                                               // If the props argument is a renderable VNode,
        ? {C: [].concat(props, ...children)}                             // ... prepend it to the children
        : (props.C = [].concat(...children)) && props                    // ... otherwise append 'C' to the property

(Note the spread operator on children)

wavesoft commented 7 years ago

@SilentCicero I have just published the 0.2.2 release, that should have a bit better npm support.

wavesoft commented 7 years ago

I just tried the 0.2.2 build with hyperx and it seems to work fine, so I am closing this issue.

const hyperx = require('hyperx');
const {R,H} = require('dot-dom');

const dot = hyperx(H)

R(dot`<div>
        Cool!
        <div onclick=${() => console.log('Yes!')}>Something Else</div>
        <a href="cool">Yes!</a>
      </div>`, document.body)

That's a pretty cool library by the way 👍