I created the same app in Svelte.js and Malina.js. Here are the differences.

Oleg Nechaev
JavaScript in Plain English
5 min readJul 5, 2020

--

I like Svelte.js. Since I’ve tried it, I wanted to try another way to detect changes/mutations, current change detector is one of the keys of Svelte, without it Svelte would not be itself. So to experience another change-detector I made a little “sister” of Svelte is Malina.js, which instead of checking if a variable was changed, it checks if a binding was changed (bind-checking). Below are a few examples how it’s better.

To be able to see a difference I made the same todo-app on Svelte.js and Malina.js (a code style for Svelte to work with an array is taken from official svelte-todomvc).

Links: Svelte todo-app, Malina todo-app.

Let’s start with function “add” where we append todo item in array:

Svelte on the left. Malina on the right.

Code for removing an item:

Svelte on the left. Malina on the right.

You can notice that code for Malina.js is more compact, it detects mutations, so you can use any approach in Malina.js.

And the most interesting case, when we choose one item on:click={() => active=todo}, after this a todo-object presents in 2 places - in array todos and variable active, and rendered in 2 places. So if you mutate this object bind:value={active.name}, Svelte will not detect it, and you need to trigger an update manually, Svelte:

<input on:keydown={enterEdit} bind:value={active.name} />const enterEdit = (e) => {
if(e.keyCode == 13) active=null;
todos=todos; // trigger updating todos
}

In Malina:

<input on:keydown|enter={active=null} bind:value={active.name} />

You don’t need extra code here, it works as expected — active.name is changed by input and rendered in the list automatically, because change-detector checks bindings. Also you could notify an event modifier “enter” which works only for key “Enter” - it’s very helpful, I think it would be good if Svelte will have it (vue.js also has it).

One more example is to change (reverse) todo.name, Svelte:

const reverse = todo => {
let newName = todo.name.split("").reverse().join("");
todos = todos.map(item => ({
name: item==todo?newName:item.name
}));
}

Malina.js, just change a name and it works:

const reverse = todo => {
todo.name = todo.name.split("").reverse().join("");
}

So you can see that code in Svelte look like pure JS, but I can’t use JS freely.

Svelte offers an immutable way — but it’s just a mask to hide “assignment”, because assignment triggers an update, but not immutability. So it’s enough to write todos=todos, after that Svelte triggers an update.

So the main reason for immutability in Svelte is to make JS looks more natural, to escape from valueless todos=todos, which is similar to command setValue/setState from other frameworks.

Malina.js lets me mutate objects and arrays, it works as I expect it from JavaScript.

What else is different?

It’s an another way to build DOM, let’s look at this small snippet:

<div class="some class">
<span on:click={click}>
<b>a lot of <i>html</i> can be here</b>
</span>
</div>

How it looks in Svelte after compilation (Svelte builds it element by element):

div = element("div");
span = element("span");
b = element("b");
t0 = text("a lot of ");
i = element("i");
i.textContent = "html";
t2 = text(" can be here");
attr_dev(div, "class", "some class");
...
insert_dev(target, div, anchor);
append_dev(div, span);
append_dev(span, b);
append_dev(b, t0);
append_dev(b, i);
append_dev(b, t2);
...
dispose = listen(span, "click", click, false, false, false);

How it looks in Malina.js:

$element.innerHTML = `<div class="some class"> <span> <b>a lot of <i>html</i> can be here</b> </span> </div>`;$element.childNodes[0].childNodes[1].addEventListener('click', ...);

A template is inserted as one operation, and node.cloneNode(true) is used for repeatable blocks in #each and #if (Solid.js works similar way).

It gives smaller bundle size and slightly better performance (twice faster re-rendering list in Firefox), e.g. I compiled the same TodoMVC app:

  • Svelte: 3.7kb gzipped (a generation of uuid was removed to be equal),
  • Malina: 2.7kb gzipped (source).

Last thing which was changed is a style for event bindings, it is taken from Angular, so in Malina.js it looks like on:click={reverse(todo)} when in Svelte it’s on:click={() => {reverse(todo)}}, but it’s not decided finally.

What Malina.js can do today

Malina.js is too young (I started it just a 2 weeks ago), so it has not many features yet, but the most important features are available which are needed for simple apps and widgets.

For now there is: bindings, binding events, class/style, if-else block, for-each blocks, custom directives/actions, reactivity (detecting changes), all these things you can see in examples here.

Try Malina.js

  • You can try it online in REPL (which is also built with Malina.js — just 140 lines of code)
  • Or you can run it via docker with live-reloading, if you don’t want to install nodejs and stuff: docker run — rm -it — user ${UID} -p 7000:7000 -p 35729:35729 -v `pwd`:/app/src lega911/malina
  • Or install a template via npm/npx:
npx degit malinajs/template myapp
cd myapp
npm install
npm run dev
# open http://localhost:7000/

Conclusion

Malina.js is like Svelte with another change-detector. It helps to use JavaScript more freely, with more expected behavior. More simple JavaScript gives easier developing process.

Thank you for reading, please leave feedback.

Rich has said that Svelte is not a just compiler, it’s a language, Svelte-language, but I still want to use JavaScript.

Links

JavaScript In Plain English

Enjoyed this article? If so, get more similar content by subscribing to our YouTube channel!

--

--