AngularJS
Ember.js
jQuery
40kb
100kb
35kb
mithril
7kb
react
35kb
AngularJS
Ember.js
jQuery
200+
100+
200+
mithril
20
react
~ 50
???
AngularJS
Ember.js
Knockout
800ms
1000ms
300ms
mithril
80ms
react
600ms
http://matt-esch.github.io/mercury-perf/
var todos = {
controller: function() {
},
view: function() {
return m('h1.random-css-class#some-id', 'huhu');
}
};
m.route(document.body , '/', {
'/': todos
});
<!doctype html>
<html lang="en">
<head>
<title>Mithril Example</title>
<script src="mithril.js"></script>
<script src="index.js"></script>
</head>
<body></body>
</html>
function headerView() {}
function footerView() {}
function mainView() {
return m('main', [
m('ul', [
m('li', [
m('input[type=checkbox]'),
m('input', {
value: 'learn mithril'
}),
m('button.destroy', 'remove')
])
])
]);
}
var todos = {
controller: function() {},
view: function() {
return [
headerView(),
mainView(),
footerView()
]
}
};
function todoView(todo) {
return m('li', [
m('.view', [
m('input[type=checkbox]),
m('input.edit', {
value: 'learn mithril'
}),
m('button.destroy', 'remove')
]),
]);
}
function mainView(scope) {
return m('main', [
m('ul', scope.todos.map(todoView)),
m('.countUndone', scope.countUndone())
]);
}
function undone(todo) {
return !todo.done;
}
var todos = {
controller: function() {
var scope = {
todos: [{
label: 'learn mithril!',
done: false
}, {
label: 'relax!',
done: false
}],
countUndone: function() {
return scope.todos.filter(undone).length;
}
};
return scope;
},
view: function(scope) {
return [
headerView(scope),
mainView(scope),
footerView(scope),
];
}
};
function todoView(scope) {
return function(todo) {
return m('li', [
m('.view', [
m('input[type=checkbox], {
onchange: scope.markDone(todo)
}),
m('input.edit', {
value: 'learn mithril'
}),
m('button.destroy', 'remove')
]),
]);
}
}
function mainView(scope) {
return m('main', [
m('button', {
onclick: function() {
scope.addTodo()
}
}, 'New todo'),
m('ul', scope.todos.map(todoView(scope)))
m('.countUndone', scope.countUndone())
]);
}
var todos = {
controller: function() {
var scope = {
todos: [],
countUndone: function() {
return scope.todos.filter(undone).length;
}
addTodo: function(label) {
scope.todos.push({
label: label || 'new todo',
done: false
};
},
markDone: function(todo) {
return function(event) {
todo.done = event.target.checked;
}
}
};
return scope;
},
view: function(scope) {
return [
headerView(scope),
mainView(scope),
footerView(scope),
];
}
};
var todoComponent = {
controller: function() {
var todos = [];
var scope = {
get todos() {
return todos.filter(function(todo) {
return (m.route() == '/completed' && todo.done) ||
(m.route() == '/active' && !todo.done) ||
(m.route() === '/');
});
}),
// ...
};
return scope;
},
view: function(scope) {
return [
headerView(scope),
mainView(scope),
footerView(scope),
];
}
};
m.route.mode = 'hash';
m.route(document.body , '/', {
'/': todoComponent,
'/active': todoComponent,
'/completed': todoComponent
});
var todoComponent = {
controller: function(todos) {
var scope = {
get todos() {
return todos.filter(function(todo) {
return (m.route() == '/completed' && todo.done) ||
(m.route() == '/active' && !todo.done) ||
(m.route() === '/');
});
}),
// ...
};
return scope;
},
view: function(scope) {
return [
headerView(scope),
mainView(scope),
footerView(scope),
];
}
};
function someOtherAppsView() {
return m('.random-container', [
m.component(todoComponent, somePredefinedTodos)
]);
}
with the help of mithril-node-render
so only pre-render indexed pages
since mithril rerenders everything on startup
var out = mithrilQuery(nameComponent, 'Catwoman');
out.should.have('.name');
out.should.not.have('.address');
out.should.have(1, '.name');
out.should.contain('Catwomen');
nameComponent = {
controller: function(initialName) {
return {
name: initialName || 'Batman'
};
},
view: function(scope) {
return m('.name', scope.name);
}
};
var out = mithrilQuery(nameComponent, 'Catwoman');
out.should.contain('Catwomen');
out.click('.clear');
out.should.not.contain('Catwomen');
nameComponent = {
controller: function(initialName) {
var scope = {
name: initialName || 'Batman'
clearName: function() {
scope.name = '';
}
};
return scope;
},
view: function(scope) {
return m('.name', scope.name);
return m('.clear', {
onclick: scope.clearName
}, 'clear');
}
};
function drawCanvas(element, isInitialized) {
//don't redraw if we did once already
if (isInitialized) return;
var ctx = element.getContext("2d");
/* draws stuff */
}
var app = {
controller: function() {
// ...
},
view: {
return m("canvas", {
config: drawCanvas
})
}
]
m.mount(document.body, app);
var Sortable = require('sortablejs');
var app = {
controller: function() {
return {
onSort: function(sortEvent) {
// ....
}
}
},
view: {
return m("ul", {
config: function(el, isInitialized) {
if (isInitialized) return;
new Sortable(el, {
animation: 150,
onSort: scope.onSort
});
}
}, [
m('li', 'one'),
m('li', 'two'),
m('li', 'three')
])
}
]
m.mount(document.body, app);
*except other VDOM libs, most are quite good ;)