node package manager

maskjs

Template / Markup / HMVC Engine


MaskJS — is a markup | template | HMVC engine for modern and fast web(Browser), server(NodeJS) or mobile(PhoneGap) applications. Component-based architecture simplifies defining, implementing and composing loosely coupled independent elements into a single application.

Resources:



1 Markup

We support mask and html syntax for writing your templates. And you can even mix them within one template, as each of them has its advantages.

  • Component and element-based markup
  • Statements, Expressions, Interpolations
  • Performance. No precompilation is required
  • Small size. ~30% smaller than HTML Additionaly, there is a minification tool - Optimizer.
  • DOM Builder [Template → Mask AST → Shadow DOM → Live DOM]
  • HTML Builder (nodejs) [Template → Mask AST → HTML]
import CustomComponent from 'Foo.mask'
 
.container {
    h4 > 'Title'
    section.content {
        span > 'Hello ~name!'
 
        if (admins.indexOf(name) > -1) {
            em > 'Admin'
        }
    }
    CustomComponent {
        button x-tap='changeName' >
            '~[bind: name]'
 
        for (tag of tags) {
            h4 > '~tag.title'
        }
    }
}

Here is nothing new for you. Old good HTML syntax to define the templates. But we highly encourage the use of the mask syntax, as the templates are smaller, cleaner and with additional features.

<h4>~[name]</h4>
<Dialog>
    <div>Hello Foo</div>
</Dialog>

You can even use html blocks in a mask syntax

ul {
    <li> Foo
    <li> Bar
}

MaskJS has extremely extendable API based on interfaces and contracts. It supports Custom Tag Handlers, Custom Attribute Handlers, Model Utils.

MaskJS default build contains sub projects: CompoJS, Bindings, jMask.

2 Libaries

📦 All packages are already embedded into MaskJS sources.

📙 Read more...

Core of the HMVC engine. Simple compo sample:

mask.registerHandler('CustomComponent', mask.Compo({
    slots: {
        refreshDate: function(){
            this.model.date = new Date();
        },
        domInsert: function(){
            alert(this.$.innerWidth());
        }
    },
    events: {
        'click: button': function(){
            alert(this.model.date);
        }
    },
    onRenderStart: function(model, ctx){
        // override model 
        this.model = { date: new Date(); }
    },
    onRenderEnd: function(elements, model, ctx){
        this.$ // is a domLibrary (jQuery-lite, jQuery/Zepto/Kimbo) wrapper over `elements` 
    },
    dispose: function(){
        // do some cleanup 
    }
})

2.2 Bindings

📙 Read more... IE9+

MaskJS itself supports simple interpolations. It means the models are only accessed while render, but with this feature you can define single or dual bindings. As MaskJS is a DOM based engine, the bindings are instant.

Simple bindings sample:

h4 > '~[bind: fooDate.getSeconds() * barAge ]'
 
input type=date >
    :dualbind value='fooDate';
 
input type=number >
    :dualbind
        value='barAge'
        x-signal='dom: ageChanged';
/*
 * `ageChanged` is emitted in this sample each time `barAge` changes
 * `:dualbind` component also supports much more properties and configurations
\*/

2.3 jMask

📙 Read more...

jMask offers jQuery-alike syntax for the dynamic MaskDOM Manipulations.

2.4 jQuery

MaskJS is loosely coupled with the DOM Library, like jQuery-Zepto-Kimbo. It means, that it does not depend on any DOM library, but it is highly recommended to use one. Additionally there are some extensions, like

$.fn.appendMask
$.fn.prependMask
$.fn.beforeMask
$.fn.afterMask
$.fn.emptyAndDispose
$.fn.removeAndDispose
//e.g. 
$('.foo').appendMask('h4 > "~[title]"', { title: 'Hello' });

So you would never need to use the HTML.

3 Performance

We thoroughly pay attention to the performance, especially on the mobile CPU. The DOM based and the Shadow DOM approach is the fastest way to create hierarchical component structure.

Some benchmarks:

4 Node.JS

MaskJS on the server

📙 Mask.Node Server.Lib

  • HMVC benefits
  • Models serialization/de-serialization
  • Components render mode - server, client or both
  • HTML rendered output with further bootstrapping on the client, so that the components are initialized, all events and bindings are attached
  • Application start performance: browser receives ready html for rendering.
  • SEO

5 Browser Support

  • IE7+

6 Plugins

There are already many plugins, components and useful utilities. Some of them worth to checking out:

7 Quick Start

Most simple MaskJS sample to show where you could start from:

<!DOCTYPE html>
<html>
    <body>
        <header>
            <!-- e.g add menu into header -->
            <script type='text/mask' data-run='true'>
                ul {
                    for(page of pages) {
                        log('Rendering item:', page);
                        li > a
                            href='/~[page].html'
                            x-tap='fooAction' > '~[page]'
                    }
                    // nested components 
                    BazCompo > QuxCompo;
                }
            </script> 
        </header>
        <!-- ... other html, or mask blocks -->
        <!--
            usually you would have only one Mask block, which is the entry point
            for the app, and you would use nested component composition to
            encapsulate logic, models, templates and the behaviour
        -->
        <script src='http://cdn.jsdelivr.net/g/maskjs'></script> 
        <script type='text/javascript'>
            var App = mask.Compo({
                model: {
                    pages: [ 'blog', 'about', 'contact' ]
                },
                slots: {
                    fooAction: function(event){
                        event.preventDefault();
                        console.log(this instanceof App);
                        // ... 
                    }
                }
            });
            mask.registerHandler('BazCompo', mask.Compo({/*implement*/}));
            mask.registerHandler('QuxCompo', mask.Compo({/*implement*/}));
            mask.run(App);
        </script> 
    </body>
</html>

8 Contribute

$ git submodule init && git submodule update
$ npm install
$ npm run build
$ npm install
$ npm test

9 Changelog


🔖 View complete list...

@latest

  • Function scope: imports and define arguments

    import * as Service from '/services/UserService.js';
    define UserEditor (user) {
        
        slot save () {
            Service
                .changeUserName(user.id, user.name)
                .then(() => console.log('saved!'));
        }
     
        input > dualbind value='user.name';
        button x-tap=save > 'Save'
    }
  • sync imports, as import loading for better performance is parallel, but bundles should be loaded in sync, as they register all resources then.

import sync from './MyComponentsBundle';
import FooCompo from './Foo';
// ...
  • 0.55.1

    • HTML markup within Mask templates
  • 0.55.0

    • Async imports.

      import async Foo from './Foo.mask';
      h4 > 'MyHeader'
      await Foo;

      h4 header is rendered during the Foo may still being loaded.

    • define and let support arguments

      define Foo (user) {
          h4 > '~user.name'
      }
       
      Foo(me);
      mask.render(template, { me: { name: 'TestUser' }});

©️ MIT - 2016 Atma.js Project