Mithril vs Aurelia 2: A Comprehensive Comparison

This website is powered by ItGalaxy.io

In the world of frontend development, Mithril and Aurelia 2 represent two different approaches to building web applications. While Mithril offers a lightweight, hyperscript-based approach with functional components, Aurelia 2 provides a modern, convention-based framework with powerful data binding capabilities. Let’s explore their differences and use cases.

Table of Contents

  1. Core Concepts
  2. Reactivity and State Management
  3. Templating and Components
  4. DOM Manipulation
  5. Event Handling
  6. Component Composition
  7. Form Handling
  8. Lifecycle Management
  9. Web App Features
  10. Performance and Bundle Size
  11. Learning Curve
  12. Conclusion

Core Concepts

Mithril and Aurelia 2 take fundamentally different approaches to building web applications:

  • Mithril uses a lightweight hyperscript-based approach with functional components and manual redraw triggers
  • Aurelia 2 is a modern, convention-based framework that emphasizes standards compliance and powerful data binding

Reactivity and State Management

Declare State

Mithril

import m from "mithril";

export default function Name() {
  let name = "John";

  return {
    view: () => m("h1", `Hello ${name}`),
  };
}

Aurelia 2

<!-- name.html -->
<h1>Hello ${name}</h1>

<!-- name.ts -->
export class NameCustomElement { name = "John"; }

Update State

Mithril

import m from "mithril";

export default function Name() {
  let name = "John";
  name = "Jane";
  return {
    view: () => m("h1", `Hello ${name}`),
  };
}

Aurelia 2

<!-- name.html -->
<h1>Hello ${name}</h1>

<!-- name.ts -->
export class NameCustomElement { name = "John"; constructor() { this.name =
"Jane"; } }

Computed State

Mithril

import m from "mithril";

export default function DoubleCount() {
  let count = 10;
  let doubleCount = count * 2;
  return {
    view: () => m("div", doubleCount),
  };
}

Aurelia 2

<!-- double-count.html -->
<div>${doubleCount}</div>

<!-- double-count.ts -->
export class DoubleCountCustomElement { count = 10; get doubleCount() { return
this.count * 2; } }

Templating

Minimal Template

Mithril

import m from "mithril";

export default function HelloWorld() {
  return {
    view: () => m("h1", "Hello World"),
  };
}

Aurelia 2

<!-- hello-world.html -->
<h1>Hello world</h1>

Styling

Mithril

import "./style.css";
import m from "mithril";

export default function CssStyle() {
  return {
    view: () =>
      m(
        "div",
        m("h1.title", "I am red"),
        m("button", { style: { fontSize: "10rem" } }, "I am a button")
      ),
  };
}
/* style.css */
.title {
  color: red;
}

Aurelia 2

/* css-style.css */
.title {
  color: red;
}
<!-- css-style.html -->
<h1 class="title">I am red</h1>
<button style="font-size: 10rem">I am a button</button>

Loop

Mithril

import m from "mithril";

export default function Colors() {
  const colors = ["red", "green", "blue"];
  return {
    view: () =>
      m(
        "ul",
        colors.map((color, idx) => m("li", { key: idx }, color))
      ),
  };
}

Aurelia 2

<!-- colors.html -->
<ul>
  <li repeat.for="color of colors">${color}</li>
</ul>

Event Click

Mithril

import m from "mithril";

export default function Counter() {
  let count = 0;
  const incrementCount = () => (count = count + 1);
  return {
    view: () =>
      m(
        "div",
        m("p", `Counter: ${count}`),
        m("button", { onclick: incrementCount }, "+1")
      ),
  };
}

Aurelia 2

<!-- counter.html -->
<p>Counter: ${count}</p>
<button click.trigger="incrementCount">+1</button>

DOM Reference

Mithril

import m from "mithril";

export default function InputFocused() {
  let value = "";
  return {
    view: () =>
      m("input", {
        oncreate: ({ dom }) => dom.focus(),
        type: "text",
        value,
        oninput: (e) => (value = e.target.value),
      }),
  };
}

Aurelia 2

<!-- input-focused.html -->
<input ref="inputElement" />

Conditional

Mithril

import m from "mithril";
const TRAFFIC_LIGHTS = ["red", "orange", "green"];

export default function TrafficLight() {
  let lightIndex = 0;
  let currentLight = () => TRAFFIC_LIGHTS[lightIndex];

  const nextLight = () => (lightIndex + 1) % TRAFFIC_LIGHTS.length;

  const instructions = () => {
    switch (currentLight()) {
      case "red":
        return "STOP";
      case "orange":
        return "SLOW DOWN";
      case "green":
        return "GO";
    }
  };

  return {
    view: () =>
      m(
        "div",
        m("button", { onclick: nextLight }, "Next light"),
        m("p", `Light is: ${currentLight()}`),
        m("p", "You must ", m("span", instructions()))
      ),
  };
}

Aurelia 2

<!-- traffic-light.html -->
<button click.trigger="nextLight()">Next light</button>
<p>Light is: ${light}</p>
<p switch.bind="light">
  You must
  <span case="red">STOP</span>
  <span case="orange">SLOW DOWN</span>
  <span case="green">GO</span>
</p>

Lifecycle

On Mount

Mithril

import m from "mithril";

export default function PageTitle() {
  return {
    view: () => m("p", `Page title: ${document.title}`),
  };
}

Aurelia 2

<!-- page-title.html -->
<p>Page title is: ${pageTitle}</p>

On Unmount

Mithril

import m from "mithril";

export default function Time() {
  let time = new Date().toLocaleTimeString();

  const timer = setInterval(() => {
    time = new Date().toLocaleTimeString();
    m.redraw();
  }, 1000);

  return {
    view: () => m("p", `Current time: ${time}`),
    onremove: () => clearInterval(timer),
  };
}

Aurelia 2

<!-- time.html -->
<p>Current time: ${time}</p>

Component Composition

Props

Mithril

import m from "mithril";
import UserProfile from "./UserProfile.js";

export default function App() {
  return {
    view: () =>
      m(UserProfile, {
        name: "john",
        age: 20,
        favouriteColors: ["green", "blue", "red"],
        isAvailable: true,
      }),
  };
}

Aurelia 2

<!-- app.html -->
<user-profile
  name.bind
  age.bind
  favourite-colors.bind="colors"
  is-available.bind="available"
></user-profile>

Emit to Parent

Mithril

import m from "mithril";
export const AnswerButton = ({ attrs: { onYes, onNo } }) => ({
  view: () =>
    m(
      "div",
      m("button", { onclick: onYes }, "YES"),
      m("button", { onclick: onNo }, "NO")
    ),
});

Aurelia 2

<!-- app.html -->
<p>Can I come ?</p>
<answer-button action-handler.bind="handleAnswer"></answer-button>
<p style="font-size: 50px">${isHappy ? "😀" : "😥"}</p>

Slot

Mithril

import m from "mithril";
import { FunnyButton } from "./FunnyButton.jsx";

export default function App() {
  return {
    view: () => m(FunnyButton, "Click me!"),
  };
}

Aurelia 2

<!-- app.html -->
<funny-button>Click me !</funny-button>

Slot Fallback

Mithril

import m from "mithril";
import FunnyButton from "./FunnyButton.jsx";

export default function App() {
  return {
    view: () => m("", m(FunnyButton), m(FunnyButton, "I got Content")),
  };
}

Aurelia 2

<!-- app.html -->
<funny-button></funny-button>
<funny-button>Click me !</funny-button>

Form Input

Input Text

Mithril

import m from "mithril";

export default function InputHello() {
  let text = "Hello world";
  const handleChange = ({ target: { value } }) => (text = value);

  return {
    view: () =>
      m("", m("p", text), m("input", { value: text, onchange: handleChange })),
  };
}

Aurelia 2

<!-- input-hello.html -->
<p>${text}</p>
<input value.bind />

Checkbox

Mithril

import m from "mithril";

export default function IsAvailable() {
  let isAvailable = false;
  const onUpdate = () => (isAvailable = !isAvailable);

  return {
    view: () =>
      m(
        "",
        m("input", {
          id: "is-available",
          type: "checkbox",
          checked: isAvailable,
          onchange: onUpdate,
        }),
        m("label", { for: "is-available" }, "Is available")
      ),
  };
}

Aurelia 2

<!-- is-available.html -->
<input id="is-available" type="checkbox" checked.bind="isAvailable" />
<label for="is-available">Is available</label>: ${isAvailable}

Radio

Mithril

import m from "mithril";

export default function PickPill() {
  let picked = "red";
  let pills = ["red", "green", "blue"];
  const handleChange = ({ target: { value } }) => (picked = value);

  return {
    view: () =>
      m(
        "",
        m("", `Picked: ${picked}`),
        pills.map((pill) =>
          m(
            ".",
            m("input", {
              id: pill,
              checked: picked == pill,
              type: "radio",
              value: pill,
              onchange: handleChange,
            }),
            m("label", { for: pill }, pill)
          )
        )
      ),
  };
}

Aurelia 2

<!-- pick-pill.html -->
<div>Picked: ${picked}</div>

<input id="blue-pill" checked.bind="picked" type="radio" value="blue" />
<label for="blue-pill">Blue pill</label>

<input id="red-pill" checked.bind="picked" type="radio" value="red" />
<label for="red-pill">Red pill</label>

Select

Mithril

import m from "mithril";
const colors = [
  { id: 1, text: "red" },
  { id: 2, text: "blue" },
  { id: 3, text: "green" },
  { id: 4, text: "gray", isDisabled: true },
];

export default function ColorSelect() {
  let selectedColorId = 2;

  const handleSelect = ({ target: { value } }) => (selectedColorId = value);

  return {
    view: () =>
      m(
        "select",
        { value: selectedColorId, onchange: handleSelect },
        colors.map(({ id, text, isDisabled }) =>
          m("option", { key: id, id, disabled: isDisabled, value: id }, text)
        )
      ),
  };
}

Aurelia 2

<!-- color-select.html -->
<select value.bind="selectedColorId">
  <option value="">Select A Color</option>
  <option
    repeat.for="color of colors"
    value.bind="color.id"
    disabled.bind="color.isDisabled"
  >
    ${color.text}
  </option>
</select>

Web App Features

Render App

Mithril

<!DOCTYPE html>
<html>
  <body>
    <div id="app"></div>
    <script type="module" src="./main.jsx"></script>
  </body>
</html>

Aurelia 2

<!DOCTYPE html>
<html>
  <head>
    <script type="module" src="./main.ts"></script>
  </head>

  <body>
    <app></app>
  </body>
</html>

Fetch Data

Mithril

import m from "mithril";

export default function App() {
  let isLoading = false;
  let error = null;
  let users = [];

  async function fetchUsers() {
    isLoading = true;
    try {
      const { results } = await m.request(
        "https://randomuser.me/api/?results=3"
      );
      users = results;
    } catch (err) {
      error = err;
    }
    isLoading = false;
  }

  return {
    oninit: fetchUsers,
    view() {
      if (isLoading) return m("p", "Fetching users...");
      if (error) return m("p", "An error occurred while fetching users");
      return users.map((user) =>
        m(
          "li",
          { key: user.login.uuid },
          m("img", { src: user.picture.thumbnail, alt: "user" }),
          m("p", `${user.name.first} ${user.name.last}`)
        )
      );
    },
  };
}

Aurelia 2

<!-- app.html -->
<template promise.bind="useFetchUsers.fetchData()">
  <p pending>Fetching users...</p>
  <p catch>An error ocurred while fetching users</p>
  <ul then.from-view="users">
    <li repeat.for="user of users">
      <img src.bind="user.picture.thumbnail" alt="user" />
      <p>${ user.name.first } ${ user.name.last }</p>
    </li>
  </ul>
</template>

Performance and Bundle Size

Mithril

  • Extremely lightweight (~10KB gzipped)
  • Fast virtual DOM diffing
  • Built-in routing and XHR
  • Minimal API surface

Aurelia 2

  • Modern, optimized architecture
  • Tree-shakeable modules
  • Efficient template compilation
  • Strong performance characteristics

Learning Curve

Mithril

  • Simple and straightforward API
  • Minimal concepts to learn
  • Functional programming approach
  • Excellent documentation

Aurelia 2

  • Convention over configuration
  • Familiar to vanilla JavaScript developers
  • Strong TypeScript support
  • Modern tooling and DX

Conclusion

Choose Mithril if you:

  • Need a minimal, lightweight framework
  • Prefer functional programming
  • Want built-in routing and XHR
  • Value simplicity and performance
  • Are building small to medium applications

Choose Aurelia 2 if you:

  • Want a modern, full-featured framework
  • Need strong TypeScript support
  • Value convention over configuration
  • Need powerful data binding
  • Are building medium to large applications

Both frameworks excel in different scenarios:

  • Mithril is perfect for lightweight applications that need performance and simplicity
  • Aurelia 2 shines in larger applications that benefit from modern features and strong conventions

The choice between Mithril and Aurelia 2 often depends on your specific needs:

  • Use Mithril for small to medium projects that need performance and simplicity
  • Use Aurelia 2 for larger applications that need modern features and strong conventions






Decouvrez plus d’Offres de la plateform ItGalaxy.io :

Découvrez notre gamme complète de services et formations pour accélérer votre carrière.

1. Nous contactez

  • Description: Besoin de Formation et des Solutions cloud complètes pour vos applications
  • Links:

2. Infra as a Service

  • Description: Infrastructure cloud évolutive et sécurisée
  • Links:

3. Projets Développeurs


4. Développeurs


5. Formations Complètes


6. Marketplace

7. Blogs


This website is powered by ItGalaxy.io