Getting Started with Malina.js

Chidume Nnamdi 🔥💻🎵🎮
Bits and Pieces
Published in
8 min readOct 14, 2020

--

Yet another JavaScript framework. The JavaScript ecosystem is rapidly evolving and with it is the release of several JS frameworks to help developers build and ship faster and robust apps with ease tailored to their needs.

Each JS framework brings its unique super-power to the game. In this post, we will learn about Malina.js, a new JS framework, and the goodies it brings to frontend development.

Malina.js

Malina.js is based on Svelte design. It is extremely lightweight as it produces (on compiling) nothing more than the app’s implementation code. That’s in contrast to many of the more popular frameworks. For example, in Angular, on compilation and bundling, the following files are produced:

vendor.******.js: which contains core Angular functions, classes, APIs.

main.******.js: the app’s implementation code.

polyfills.***.js: the polyfills for legacy browsers support.

styles.****.js: The CSS styling in our app.

Using Malina.js is very easy. It has a Malina CLI tool that enables a fast scaffolding of a Malina.js app.

To start a Malina.js project, you need to run the below command:

npm init malina

It will present you with options to select. These options are features, settings you want your Malina.js project to have. You can choose the directory where to create the new Malina.js project, you can choose the type of Malina.js template to create.

OR

You can install the Malina CLI tool create-malina:

npm i create-malina -g

The -g flag means to install the create-malina lib globally in the system, so it can be accessed from anywhere in your machine.

You can now use the malina command to scaffold a Malina.js project.

malina my-app

This will create a Malina.js project my-app, Malina.js will install the dependencies.

The my-app directory will look like this:

my-app
docker/
src/
public/
index.html
malinajs.svg
App.html
main.js
package.json
rollup.config.js
.gitignore

To start the dev server, run this command:

npm run dev

Open your fav browser and navigate to http://localhost:7000/.

To compile and build your project for production, use this command:

npm run build

You have learned how to scaffold a quick Malina.js project, let’s look at the basic features Malina.js possesses.

Tip: Share reusable components between projects using Bit (Github). Bit makes it simple to share, document, and organize independent components from any project.

Use it to maximize code reuse, collaborate on independent components, and build apps that scale.

Bit supports Node, TypeScript, React, Vue, Angular, and more.

Example: exploring reusable React components shared on Bit.dev

Expression

Expressions are written in Malina.js in between curly braces: {}. These expressions are pieces of Malina language statements that are embedded in HTML and are executed when the app runs.

Example:

<div>
My name is {getMyName()}.
I am {20 + 8} years old.
</div>

We have two expressions here {getMyName()} and {20 + 8}. These expressions are evaluated and the results are injected into the HTML.

{getMyName()} is a function call, Malina will call the getMyName function and set the returned value back in the HTML.

{20 + 8} is an addition expression, Malina will evaluate it and set the result 28 in the HTML.

Binding — One-way

Binding in JS frameworks means connecting a variable to the HTML view. So the HTML view reflects/uses the variables’ value in its DOM, a change in the variable’s value causes the DOM to re-render to display the new value. It is simple but yet it is one big essential feature in frontend development.

One-way binding is now the binding of a variable from the script to the HTML view. It is in one direction. A change in the variable reflects in the HTML DOM it is bound to.

Example:

<script>
let name = "Chidume Nnamdi"
</script>
<div>
My name is {name}.
</div>

The name in the {} is a variable in the script tag. It is bound to the HTML view using the {}, the value will be displayed there in the DOM, and any change in the name value will be reflected in the DOM.

Example:

<script>
let name = "Chidume Nnamdi"
let placeholderValue = "What's your name?"
</script>
<div>
<input value={name} placeholder={placeholderValue} type="text" />
</div>

Here, we bound name and placeholderValue variables to input's value and placeholder attributes. value and placeholder attributes values will be "Chidume Nnamdi" and "What's your name?" respectively.

In the DOM, it will be this:

<div>
<input value="Chidume Nnamdi" placeholder="What's your name?" type="text" />
</div>

Binding — Two-way

Two-way binding is like one-way binding but in this case, the variable can be changed from both the script and view. It flows in both directions.

Let’s see an example:

<script>
let name = "Nnamdi"
</script>
<body>
<div>
<input type="text" :value={name}>
</div>
</body>

The value attribute in the input box is two-way bound to the name variable. On initial rendering the input box will have a value "Nnamdi" inside the input box, when we type in text like "Nnamdi Chidume", the value of the input box will change and so the name variable will change from "Nnamdi" to "Nnamdi Chidume". In fact, the name variable is changed to the current value of the input box as we type in it. If the name variable is changed, the value of the input box will reflect the change. Do you see it? the data flow from the script to the view, changes to any side change the bound data value.

Two-way binding in Malina.js is done using the bind:value={value} or shortcut :value={value}. If the property name is the same as the bound variable name we can omit the variable name.

Binding — Event

We can attach or listen to events in Malina.js. Events like click, hover, key events, mouse events, etc can be attached to elements using the formats:

@eventName:handler @eventName={handler} @eventName={(e) => {}}

The eventName is the name of the event like click, hover, key(keyup, keydown) events, mouse(mouseup, mouseover) events, etc.

Example:

<script>
function handler(e) {
console.log("Clicked !!")
}
</script>
<div>
<button @click:handler>Click Me!</button>
<button @click={handler}>Click Me!</button>
<button @click={(e) => console.log("Clicked me.")}>Click Me!</button>
</div>

Here, we demonstrated ways to register click events in an element.

Reference

We can get hold of the DOM instance of an element or an object instance of the Malina Component. This is done using the hashtag # followed by the name of the reference variable.

Example:

<script>
let divRef
function handler() {
console.log(divRef.innerHTML)
}
</script>
<div>
<div #divRef>I'm a DIV</div>
<button @click={handler}>Click Me!</button>
</div>

We have a reference variable divRef in the script and also set on the div element using the #divRef. Malina will get the DOM instance of the div element(an object of HTMLDivElement) and assign it to the divRef variable.

See in the handler function, we know that the divRef variable we have the object of the HTMLDivElement so we can access the DOM APIs. There we are logging the inner HTML of the div element using the innerHTML property. So in our console, we will see I'm a DIV text logged.

Control block — #if-else

Conditional rendering can be achieved in Malina.js. This enables a portion of the DOM to be rendered when a condition is met.

The #if-else does the job in Malina.

Example:

<script>
let render = true
function renderHandler() {
render = false
}
</script>
<div>
{#if render}
<div>True Condition</div>
{:else}
<div>False Condition</div>
{/if}
<div>
<button @click:renderHandler>Change Render</button>
</div>
</div>

The condition here is dependent on the render variable. On initial rendering, the <div>True Condition</div> will be rendered because the render variable is initially set to true. If we click the Change Render button will change the render variable value to false, this will cause the <div>True Condition</div> to be removed from the DOM and the <div>True Condition</div> will be rendered. This is conditional rendering.

Control block — #each

We can iterate over a list and render them in Malina just like we do in Angular, React, etc.

Example:

<script>
let shoppingLists = [ "Candy", "Monster Energy", "Chocolate" ]
</script>
<div>
<h3>Shopping List</h3>
<ul>
{#each shoppingLists as shoppingList}
<li>{shoppingList}</li>
{/each}
</ul>
</div>

We have an array of shopping lists in the shoppingLists variable. We use the #each to iterate over the shoppingLists array, the as keyword is used to assign a single item in the array to a variable. Here every single current iteration is set to the shoppingList variable, so we use it in the HTML to render the item.

With this our DOM will render the above like this:

<div>
<h3>Shopping List</h3>
<ul>
<li>Candy</li>
<li>Monster Energy</li>
<li>Chocolate</li>
</ul>
</div>

Control block — @html

An HTML block can be rendered by using the @html syntax.

Example:

<script>
let htmlContent = "<div>Rendered content</div>"
</script>
<div>
{@html htmlContent}
</div>

The htmlContent variable holds the HTML string, then we use the @html followed with the htmlContent inside the {} brackets. These will make Malina render the "<div>Rendered content</div>" inside the div element.

It’ll look like this:

<div>
<div>Rendered content</div>
</div>

Components

Malina.js also supports component-driven design.

Components have their own .html file. It has a script block, style block and the rest content become a template.

Example:

<!-- NameComponent.html --><script>
let name = "Malina demo"
</script>
<style>
h3 {
margin: 0;
}
</style>
<div>
<h3>I'm a Malina component</h3>
<div>
This is a {name}
</div>
</div>

The script block will contain the controller logic of the Component. The style block will contain the CSS styling of the Component.

We can now use the import statement in the script block in an HTML file we want to use the component.

<!-- index.html --><script>
import NameComponent from "./NameComponent.html"
</script>
<div>
Malina component demo
<NameComponent />
</div>

You see how we name exported the NameComponent from the NameComponent.html. In Malina, the name of the HTML file becomes the name of the component. That is why NameComponent will be the component name of NameComponent.html.

The contents of the NameComponent will be rendered where the <NameComponent /> is placed in the index.html file. Also, its styling and controller logic will only affect the DOM rendered by the component.

Malina.js REPL

For quick test or usage of Malina.js, you can use its online REPL tool at https://malinajs.github.io/repl

Resources

For more resources on Malina.js, check out its docs at:

Conclusion

We covered a lot here. We started from the goodies of Malinajs to how we can scaffold a Malina project using the NPM and its Malina CLI tool. Next, we saw its basic features binding(one-way to two-way), event binding, references, and how to create and use components just like any other JS framework.

No doubt Malina.js is awesome. It has a low memory footprint and it is pretty fast with a low file size bundle.

It is a library you would want to try out.

If you have any questions regarding this or anything I should add, correct or remove, feel free to comment, email, or DM me.

Follow me on:

Learn More

--

--

JS | Blockchain dev | Author of “Understanding JavaScript” and “Array Methods in JavaScript” - https://app.gumroad.com/chidumennamdi 📕