bem / bem-xjst

bem-xjst (eXtensible JavaScript Templates): declarative template engine for the browser and server
https://bem.github.io/bem-xjst
Other
116 stars 48 forks source link

Normalize mix #316

Closed a-x- closed 8 years ago

a-x- commented 8 years ago

Hey there, Why bemhtml does not provide normalized this.mix (typed as {BEMHTML[]})?

miripiruni commented 8 years ago

@a-x- what difference this.mix and this.ctx.mix you see?

a-x- commented 8 years ago

as I see:

I even recheck it with bem-xjst playground now (bemhtml 6.2.0)

expected: this.mix is always exist and typed as BEMJSON[]

miripiruni commented 8 years ago

@a-x-

expected: this.mix is always exist and typed as BEMJSON[]

Sounds reasonable. I’ll think about it.

qfox commented 8 years ago

Same feelings. I'm for it until performance will be affected.

mishaberezin commented 8 years ago

It would be very convenient if this.mix always existed in normalized form. Just yesterday received bug related to this.

mishaberezin commented 8 years ago

Of course if it could be implemented without significant performance tradeoff.

miripiruni commented 8 years ago

OK, I’ll try to check the cost.

a-x- commented 8 years ago

use cases

synthetic (my demo)

common/foobar.bemhtml:

block('foobar').mod('a','1').mix()({ block: 'bazqux' });
block('foobar').mod('a','2').mix()('happy-life-to-up-levels');
block('foobar').mod('a','3').content()('foobar');

desktop/foobar.bemhtml:

block('foobar').mix()(function(){
    return applyNext().concat({block:'bem'})
});

in fact, safe desktop code is:

block('foobar').mix()(function(){
    var mix = applyNext();
    if (!mix) {
        mix = [];
    } else if (Array.isArray(mix)) {
        mix = mix;
    } else if (mix.toString() === '[object Object]') {
        mix = [mix];
    } else if (typeof mix === 'string') {
        mix = [{ block: mix }];
    }
    mix.push({block:'bem'});
    console.log('mix', mix)
    return mix;
});

in practice, you may see next examples:

practice

block('service').elem('url').mix()(function() {
    var mix = applyNext() || [];

    // @FIXME: XXXXX-885
    // на уровне XXX возвращается не массив
    if (!Array.isArray(mix) && mix) {
        mix = [mix];
    }

    mix.push({
        block: 'XXXXX',
        elem: 'label'
    });
    return mix;
});
block('b-page').match(function() {
    return !this.mods.pumpkin;
}).mix()(function() {
    var mixins = applyNext() || [];

    if (!_.isArray(mixins)) {
        mixins = [mixins];
    }

    mixins.push({
        block: 'i-cbir-controller'
    }, {
        block: 'i-cbir-initer',
        js: true
    });

    return mixins;
});
    elem('popup').def()(function() {
        var ctx = this.ctx,
            mix = [{block: 'dropdown', elem: 'popup'}];

        ctx.mix && (mix = mix.concat(ctx.mix));
       // ...
    })
block('images-touch-viewer').replace()(function() {
    var mix = this.ctx.mix || [], // а тут нельзя использовать `this.mix`
        mods = this.ctx.mods || {}; // тут можно использовать `this.mods`
    // ...
});

followed snippet is most used: (this.ctx.mix || []).concat(...) in case of undefined mix: this.ctx.mix && (ctx.mix = ctx.mix.concat(this.ctx.mix));


And So On

a-x- commented 8 years ago

also, services (bemhtml users) use «Always enclose mixes in function and array literal» rule for self-safety and restful nights

mix()({'block'}) vs mix()(function(){ return [{block:'block'}] })

it brings to us bloated code

a-x- commented 8 years ago

I propose also as a hacky perf solution followed trick: Declare in any conf black list of bottleneck blocks of switched off this.mix

Same for functions declarations (uses for preventing repeating pushing)

miripiruni commented 8 years ago

Look like relevant with #242

a-x- commented 8 years ago

Yep, but I disagree with creating helpers if we can normalize mix.

miripiruni commented 8 years ago

Since we have addMix() you should use it. The same for addAttrs(), appendContent(), prependContent(), addJs() and etc.

All magic with type checking, push(), extend and etc will perform add*() mode for you.