DEV Community

Cover image for I built the same app 6 times! Which JS Framework is best?
John Rush
John Rush

Posted on • Edited on

I built the same app 6 times! Which JS Framework is best?

Hi, I'm John, Multi Startup Builder.
I enjoy both coding and marketing.
See all my 20 products here
johnrush.me
my BIO
Say Hi to me On Twitter
Try my website builder


Warning: This post contains a high dose of code, humor, and life-changing revelations. Proceed at your own risk. 😎

When people ask me which frontend framework is my favorite, I usually reply with "all of them." But recently, I decided to put that statement to the test by building the same app using not one or two but five different frontend frameworks.

In this roller-coaster ride of an article, we'll build a simple To-Do app (yeah, another one) in five steps:

  1. Angular
  2. React
  3. Vue.js
  4. Svelte
  5. Elm
  6. MarsX

You might be thinking - what about jQuery? Well...that's so 2010! 🙅‍♂️ Let's dive into some modern stuff!

Step 1: Acing it with Angular 🔥

Angular has been around for quite some time now and is known for being powerful yet opinionated (thanks Google). It gave birth to concepts like components and Dependency Injection while rocking our worlds with Two-Way Data Binding.

ng new todo-app --routing=false --style=css
Enter fullscreen mode Exit fullscreen mode

Inside app.component.ts:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <h1>To-Do App</h1>
    <ul>
      <li *ngFor="let todo of todos">{{todo}}</li>
    </ul>
    <form (submit)="addTodo()">
      <input [(ngModel)]="newTodo" name="newTodo">
      <button type="submit">Add</button>
    </form>`,
})
export class AppComponent {
  todos = [];
  newTodo = '';

  addTodo() {
    this.todos.push(this.newTodo);
    this.newTodo = '';
  }
}
Enter fullscreen mode Exit fullscreen mode

Don't forget to import and include FormsModule in app.module.ts.

Step 2: Reacting with React ⚛️

React came as Facebook's gift 🎁 to us developers who were tired of manually updating DOM elements every single time something changed in the data model (cries in vanilla JS).

npx create-react-app todo-app
Enter fullscreen mode Exit fullscreen mode

Inside App.js:

import React, { useState } from 'react';

function App() {
    const [todos, setTodos] = useState([]);
    const [newTodo, setNewToDo] = useState('');

    const addTodo = e => {
        e.preventDefault();
        setTodos([...todos, newTodo]);
        setNewToDo('');
    };

    return (
        <div className="App">
            <h1>To-Do App</h1>
            <ul>{todos.map(todo => (<li key={todo}>{todo}</li>))}</ul>

            <form onSubmit={add_todo}>
                <input value={new_todo} onChange={(e) => set_new_todo(e.target.value)} />
                submit_button
            </form>
        </div>
    );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Step 3: Viewing it through Vue.js 💚

Vue.js entered our lives as this cool kid on the block that wanted to make things simpler for us developers while giving Angular & React a run for their money.

vue create todo-app
Enter fullscreen mode Exit fullscreen mode

Inside App.vue:

<template>
  <div id="app">
    <h1>To-Do App</h1>
    <ul>
      <li v-for="(todo, index) in todos" :key="index">{{todo}}</li>
    </ul>

    <form @submit.prevent="addTodo">
      <input v-model="newTodo"/>
      <button type="submit">Add</button>
    </form>

  </div>
</template>

<script>
export default {
  data() {
    return {
      todos: [],
      newTodo: '',
    };
  },
  methods: {
    addTodo() {
      this.todos.push(this.newTodo);
      this.newTodo = '';
    },
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

Step 4: Svelte-ing into Simplicity 🧡

Svelte arrived fashionably late but was worth the wait! This framework promised something different - no virtual DOM!

npx degit sveltejs/template todo-app
Enter fullscreen mode Exit fullscreen mode

Inside App.svelte:

<script>
    let todos = [];
    let newTodo = '';

    function add_todo(e) {

        e.preventDefault();
        todos = [...todos, new_todo];
        new_todo= '';

}
</script>

<main>
    <h1>To-Do App</h1>
    <ul>{#each todos as todo}<li>{todo}</li>{/each}</ul>

<form on_submit|prevent_default={add_todo}>
<input bind:value={new_todo} />
<button type="submit">Add</button>
</form>
</main>

<style>
  /* Add your styles here */
</style>
Enter fullscreen mode Exit fullscreen mode

Step 5: Elm-inating Complexity with Elm 🌳

Elm stepped into our journey as this purely functional language based on Haskell offering "no runtime exceptions" (cue angelic music).

Inside src/Main.elm:

module Main exposing (..)

import Browser
import Html exposing (Html, button, div, h1, input, li, text, ul)
import Html.Attributes as Attrs exposing (value)
import Html.Events as Events exposing (onClick)


type alias Model =
    { todos : List String
    , newTodo : String
    }


init : Model
init =
    { todos = []
    , newTodo = ""
    }


type Msg
    = AddTodo


update msg model =
     case msg of 
        AddTodo ->
            { model | todos=model.todos++[model.newTodo],new_todo=""}


view model =
      div []
          [ h1 [] [text "To-Do App"]
          , ul [] <| List.map (\todo -> li [] [text todo]) <| model.todos 
          , form [Events.onSubmit |> Events.preventDefault |> onClick add_todo]
              [
                inputAttr [ value model.new_todo,
                           on_input set_new_to_do] [],
                submit_button []
             ]
         ]


main=
Browser.sandbox{
    init=initial_model,
    update=update,
    view=view}
Enter fullscreen mode Exit fullscreen mode

Although Elm took some getting used to, its type system & pattern matching helped us build robust components along with The Elm Architecture(T.E.A) making sure everything stayed organized even when complexity increased.

Step 6: MarsX - It took less time to code the todo list here than it took time to write this sentence :D

<schema>
  <array name="todo">
    <object>
      <string name="title" />
    </object>
  </array>
</schema>
Enter fullscreen mode Exit fullscreen mode

Now that you've witnessed how I built the same app using different frontend frameworks, you might be wondering which one is the best. Well, my friend, that's like asking a parent to pick their favorite child - it just doesn't work that way.

Each framework has its strengths and weaknesses; what works for me may not work for you. So go ahead, take your pick and start building some amazing apps! 🚀

And remember: no matter which framework you choose, don't forget to have fun while coding! 😄

Follow me on twitter
Credits to fireship


Thx for reading, check out my projects:

Hi, I'm John, Multi Startup Builder.
I enjoy both coding and marketing.
See all my 20 products here
johnrush.me
my BIO
Say Hi to me On Twitter
Try my website builder

Oldest comments (39)

Collapse
 
bkpecho profile image
Bryan King Pecho

Engaging and informative article, John. 👏 Loved the humor!

Collapse
 
laurentpayot profile image
Laurent Payot

I personally moved from Vue to Svelte, then from Svelte to Elm. The problem with Elm is that once you get a bite of that Functional Programming drug you can’t go back to JS or even TS 😉

Collapse
 
johnrushx profile image
John Rush

whats best tutorial to get into ELM?

Collapse
 
raguay profile image
Richard Guay

I did the opposite. I went from Vue, to Elm, to Svelte. I had trouble getting some things to work with Vue and Elm that worked out easy with Svelte. Also, my Svelte code did more work with less code (after compiling Svelte). But, that was my experience. Mileage may vary.

Collapse
 
laurentpayot profile image
Laurent Payot

Not really the opposite, as I also moved from Vue to Svelte, just without the Elm step 😉
So we agree we had a better developer experience with Svelte compared to Vue. I love Elm for its fearless refactoring capabilities and its ML-like syntax.

Collapse
 
eshimischi profile image
eshimischi

SolidJS is absent here. Would love to see it also in your list. Lots of upsides.

Collapse
 
frappuccino_o profile image
Ilya Shigabeev

What about writing it yourself and submitting here?

Collapse
 
fridaycandours profile image
Friday candour

I built something for everyone.

It's the fastest,
We can prove over again.
It easy normal and nothing else.
No virtual Dom.

Welcome to cradova.

Here's a basic Todo app example.

import _, {
  button,
  createSignal,
  css,
  div,
  input,
  main,
  p,
  Ref,
  reference,
} from "cradova";

function TodoList() {
  // can be used to hold multiple references
  const referenceSet = new reference();

  // creating a store
  const todoStore = new createSignal([
    "take bath",
    "code code code",
    "take a break",
  ]);

  // create actions
  todoStore.createAction("add-todo", function (todo) {
    this.set([...this.value, todo]);
  });

  todoStore.createAction("remove-todo", function (todo) {
    const ind = this.value.indexOf(todo);
    this.value.splice(ind, 1);
    this.set(this.value);
  });

  // bind Ref to Signal
  todoStore.bindRef(todoList);

  // markup
  return main(
    _`|Todo List`,
    div(
      input({
        placeholder: "type in todo",
        reference: referenceSet.bindAs("todoInput"),
      }),
      button("Add todo", {
        onclick() {
          todoStore.fireAction("add-todo", referenceSet.todoInput.value);
          referenceSet.todoInput.value = "";
        },
      })
    ),
    todoList.render
  );
}

const todoList = new Ref(function () {
  const self = this;
  return div(
    self.Signal.value.map((item) =>
      p(item, {
        title: "click to remove",
        onclick() {
          self.Signal.fireAction("remove-todo", item);
        },
      })
    )
  );
});

document.body.appendChild(TodoList());

css`
  body {
    box-sizing: border-box;
    display: flex;
  }
  main {
    margin: auto;
  }
  main > p {
    font-size: 2rem;
  }
`;
Enter fullscreen mode Exit fullscreen mode
Collapse
 
fridaycandours profile image
Friday candour

No transpiliing needed, faster tooling as a result and more performant apps.

Cradova was originally built for performant pwa, but for that you can use it for any web project.

github.com/FridayCandour/cradova

Collapse
 
codeworldindustries profile image
CodeWorldIndustries

Angular is king

Collapse
 
besmaili profile image
besmaili

Yea , as far as productivity doesn't matter.

Collapse
 
dannyengelman profile image
Danny Engelman

or hiring new teammembers who actually understand Angular

Collapse
 
cjsmocjsmo profile image
Charlie J Smotherman

Astro is missing from this list

Collapse
 
johnrushx profile image
John Rush

gonna add it into a new tutorial

Collapse
 
zirkelc profile image
Chris Cook

Cool comparison! 👍🏻

Collapse
 
johnrushx profile image
John Rush

thx Chris

Collapse
 
wuleicanada profile image
Lei Wu

From time to time I read about Elm being inspired by Haskell. Always curious where this claim originated from. Elm's syntax looks much more similar to ML-family languages such as OCaml and F# than to Haskell.

Collapse
 
mahendrarao profile image
Raavan • Edited

Cool information on JS frameworks

Collapse
 
johnrushx profile image
John Rush

thx

Collapse
 
eljayadobe profile image
Eljay-Adobe

I wish VanillaJS was in the mix. (Although I readily admit I'm partial to Elm.)

Collapse
 
dannyengelman profile image
Danny Engelman

Why more dependencies with VanillaJS?

You can do it in 3 lines of fairly readable native JavaScript, see my comment below

Collapse
 
eljayadobe profile image
Eljay-Adobe

It appears you are not familiar with VanillaJS.