DEV Community

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

Posted on โ€ข Edited on

I built the same app 7 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 seven different frontend frameworks.

I'll build a simple To-Do app 6 times using:

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

1: First love: 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. It was my first frontend framework I fell in love with. I tried knockout and few others, didnt like those. But AngularJS won my heart.

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.

2: React. The mainstreamer. โš›๏ธ

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) or seeing our browser freeze once an angularjs app got too much data or constant refresh loops.

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

3: My second wife: Vue.js ๐Ÿ’š

Vue.js entered our lives as this cool kid on the block who 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

I lost my feeling to VUE once they came up with composition API. Sorry VUE.

4: Svelte-ing into Simplicity ๐Ÿงก

Svelte arrived fashionably late but was worth the wait! This framework promised something different - no virtual DOM! (I know lately they turned into react by adding almost same stuff, but I don't use that stuff, I'm still using the old svelte).

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

5: Elm-inator ๐ŸŒณ

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, form, h1, input, li, text, ul)
import Html.Attributes exposing (value)
import Html.Events exposing (onInput, onSubmit)

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

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

-- MESSAGES
type Msg
    = AddTodo
    | SetNewTodo String

-- UPDATE
update : Msg -> Model -> Model
update msg model =
    case msg of 
        AddTodo ->
            { model | todos = model.todos ++ [model.newTodo], newTodo = "" }
        SetNewTodo newTodo ->
            { model | newTodo = newTodo }

-- VIEW
view : Model -> Html Msg
view model =
    div []
        [ h1 [] [text "To-Do App"]
        , ul [] (List.map (\todo -> li [] [text todo]) model.todos)
        , form [onSubmit AddTodo]
            [ input [value model.newTodo, onInput SetNewTodo] []
            , button [] [text "Add"]
            ]
        ]

-- MAIN
main : Program () Model Msg
main =
    Browser.sandbox
        { init = init
        , 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.

6: Alpine, the most underrated one.

<html>
<head>
    <script src="https://cdn.jsdelivr.net/npm/alpinejs@3/dist/alpine.min.js" defer></script>
</head>
<body>

<div x-data="todoApp()" class="todo-container">
    <h1>To-Do App</h1>
    <form @submit.prevent="addTodo">
        <input type="text" x-model="newTodo" placeholder="Add new todo">
        <button type="submit">Add</button>
    </form>
    <ul>
        <template x-for="todo in todos" :key="todo">
            <li x-text="todo"></li>
        </template>
    </ul>
</div>

<script>
    function todoApp() {
        return {
            newTodo: '',
            todos: [],

            addTodo() {
                if (this.newTodo.trim() === '') {
                    return;
                }
                this.todos.push(this.newTodo);
                this.newTodo = '';
            }
        }
    }
</script>

</body>
</html>

Enter fullscreen mode Exit fullscreen mode

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

Disclamer, I'm the author of marsx, so feel free to ignore this, but it's not bad I'd say.

<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! ๐Ÿ˜„


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

Top comments (62)

Collapse
ย 
marco_43 profile image
Marco โ€ข

Hello Angular, my old friend <3 currently I am checking out react, but honestly it doesn't feel like "home", so I think I will stick in angular for later projects until a shiny knight.. eeh framework comes around and saves me from my angular tower. ;-)

Collapse
ย 
shinesanthosh profile image
Shine Santhosh โ€ข

I have the opposite experience ๐Ÿ˜…. Attempted some projects in Angular, but it didn't quite feel like home. I'm leaning towards React ๐Ÿคฃ.

Each has its pros and cons. As you delve deeper into learning, you'll likely discover which suits different projects best. ๐Ÿ˜ฌ

Collapse
ย 
johnrushx profile image
John Rush โ€ข

for simple projects, alpine is great. so easy to get started

Collapse
ย 
johnrushx profile image
John Rush โ€ข

I loved angularjs, but lost the love once it moved past Angular 2

Collapse
ย 
disane profile image
Marco โ€ข

Could be the name but I love angular too โค๏ธ

Collapse
ย 
starswan profile image
Stephen Dicks โ€ข โ€ข Edited

The Elm version shows off very nicely was is possible if you let a smart person design things rather than a company - we wouldn't have Python or Ruby without these sorts of people.

Collapse
ย 
gktim profile image
gkTim โ€ข

Vue is simply the best in my point of view. Composition API is nice. Itโ€™s fast and have a great DX. But everyone is different which is nice. If there are multiple JS-Frameworks we have competition which benefits all and brings new innovations.

Collapse
ย 
johnrushx profile image
John Rush โ€ข

my fav is VUE too

Collapse
ย 
dreamxinxcode profile image
Brandon Lecky โ€ข

Point of Vue ๐Ÿ˜‰

Collapse
ย 
dawosch profile image
Dawosch โ€ข

But then you are not using TypeScript in your Vue JS project.

Collapse
ย 
gktim profile image
gkTim โ€ข

Iโ€˜m using typescript in all of my projects and actually vue is a great fit and itโ€™s a pleasure to work with.

Collapse
ย 
nikunjbhatt profile image
Nikunj Bhatt โ€ข

Markup for Angular and Vue are understandable even if one doesn't know about them and who is familiar with HTML. Other looks like assembly language code. The difference seems like simple & affordable things vs flashy & costly things, both working well for a same purpose.

Collapse
ย 
johnrushx profile image
John Rush โ€ข

I have same feeling tbh

Collapse
ย 
brense profile image
Rense Bakker โ€ข

ngIf looks like html? This is news to me.

Collapse
ย 
brense profile image
Rense Bakker โ€ข

Really so a student fresh out of school who learned html, css and nothing else, is going to understand how something like ngFor works? Tbh that's just a factual lie...

Collapse
ย 
nikunjbhatt profile image
Nikunj Bhatt โ€ข

You missed a factual reality. What happens when a web browser encounters an unknown tag or attribute within HTML code? The HTML developer can consider the same (obviously, if he knows how HTML and web browser work).

Thread Thread
ย 
brense profile image
Rense Bakker โ€ข

Nothing in HTML spec or documentation will prepare you for the nightmare that is ngFor syntax. What the developer has to do is go to the angular documentation site and learn how it works, which is knowledge that is only applicable to angular and nothing else. Same goes for vue and htmx. All these frameworks face the same issue of wanting to make something dynamic that was never intended to be dynamic (html). Its a markup language, let's keep it that way.

Thread Thread
ย 
nikunjbhatt profile image
Nikunj Bhatt โ€ข

It seems you misinterpreted my previous comment. What I mean by

What happens when a web browser encounters an unknown tag or attribute within HTML code?

is - a web browser will ignore the unknown tag and attributes; so similarly, the HTML-CSS designer can ignore unknown code too.

The problem with React is a traditional web designer would wonder about where the HTML and CSS code is!

I agree with your other concerns, though.

Collapse
ย 
mellis481 profile image
Mike E โ€ข

Angular != AngularJS

Collapse
ย 
johnrushx profile image
John Rush โ€ข

true

Collapse
ย 
mellis481 profile image
Mike E โ€ข

The point I was making is that it seems like framework #1 you list is Angular, but then you say "AngularJS won my heart." It seems like you don't understand there is a difference.

Collapse
ย 
horaceshmorace profile image
Horace Nelson โ€ข

Angular !== AngularJS. Code reviewed! ๐Ÿ˜†๐Ÿ˜œ

Collapse
ย 
efpage profile image
Eckehard โ€ข

Iยดm curious to see, which bundle size each package delivers...

Collapse
ย 
johnrushx profile image
John Rush โ€ข

with the modern internet speed and device perf, the size doesn't matter as much as it did in old days

Collapse
ย 
efpage profile image
Eckehard โ€ข โ€ข Edited

If you are talking about application performance and responsiveness, you're probably right. I donยดt think there is a direct relation between bundle size and performance. I am just curious to see, how much overhead a framework will pack ontop of a relatively small application.

Anyway, comparing start up performance and responsiveness would be an interestion comparison too!

Collapse
ย 
kyoukhana profile image
kyoukhana โ€ข โ€ข Edited

Also what is wrong with using pure JavaScript and HTML

<h1>To-Do App</h1>
    <ul id="todoList"></ul>

    <form id="todoForm">
      <input id="newTodo" />
      <button type="submit">Add</button>
    </form>
Enter fullscreen mode Exit fullscreen mode
 document.addEventListener('DOMContentLoaded', () => {
      /* Initialize an empty array for todos */
      const todos = [];

      /* Get DOM elements */
      const todoList = document.getElementById('todoList');
      const todoForm = document.getElementById('todoForm');
      const newTodoInput = document.getElementById('newTodo');

      /* Function to render todos */
      const renderTodos = () => {
        todoList.innerHTML = '';
        todos.forEach((todo, index) => {
          const li = document.createElement('li');
          li.textContent = todo;

          /* Add a click event listener to remove the todo item when clicked */
          li.addEventListener('click', () => {
            todos.splice(index, 1);
            renderTodos();
          });

          todoList.appendChild(li);
        });
      };

      /* Function to add a todo */
      const addTodo = () => {
        const newTodo = newTodoInput.value.trim();
        if (newTodo !== '') {
          todos.push(newTodo);
          newTodoInput.value = '';
          renderTodos();
        }
      };

      /* Event listener for form submission */
      todoForm.addEventListener('submit', (e) => {
        e.preventDefault();
        addTodo();
      });

      /* Initial rendering */
      renderTodos();
    });
Enter fullscreen mode Exit fullscreen mode
Collapse
ย 
eerk profile image
eerk โ€ข

The best solution for a todolist if you ask me :) The only counterpoint is that in the previous code snippets, the todolist state can also be modified by other processes and then the DOM would automatically be updated.

Collapse
ย 
kyoukhana profile image
kyoukhana โ€ข

You think in 2024 is maybe minimize the use of front-end frameworks? There was a good article I read. Today Astro and tomorrow another solution. We need to write code so that we can switch out frameworks easy not lock yourself into one.

Thread Thread
ย 
eerk profile image
eerk โ€ข โ€ข Edited

I often miss the part where a new framework actually explains why we need it at all. Is it only so we don't have to type document.querySelector() anymore? Is a framework actually faster than native js+html without any framework? Can't you have a design system that just works with native js+html? (MVC, MVVM, etc).

Collapse
ย 
chasm profile image
Charles F. Munat โ€ข

Awesome. Saved me the trouble.

Collapse
ย 
manankateshiya profile image
MananKateshiya โ€ข

"Well, my friend, that's like asking a parent to pick their favorite child - it just doesn't work that way."
Love it ๐Ÿ˜‚

I don't care what anyone says I love React <3

Collapse
ย 
johnrushx profile image
John Rush โ€ข

your first kid is often your favorite kid ;)

Collapse
ย 
pengeszikra profile image
Peter Vivo โ€ข

I missing the qwik from the list

Collapse
ย 
johnrushx profile image
John Rush โ€ข

I can add, if you help me with the code snippet

Collapse
ย 
tharakamts profile image
Tharaka Sandaruwan โ€ข

Well said

Each framework has its strengths and weaknesses; what works for me may not work for you.

Collapse
ย 
johnrushx profile image
John Rush โ€ข

just to make sure I don't start a framework war

Collapse
ย 
thorstenhirsch profile image
Thorsten Hirsch โ€ข โ€ข Edited

Aren't there any frameworks besides React which just allow Javascript in "HTML"? I know, it's not really HTML but JSX, and I still think it's the best feature of React.

<ul>{todos.map(todo => (<li key={todo}>{todo}</li>))}</ul>
Enter fullscreen mode Exit fullscreen mode

In all other frameworks presented here you have to learn a templating language and write things like #each, x-for or *ngFor="let todo of todos"

Collapse
ย 
i_am_abhaysalvi profile image
Abhay โ€ข โ€ข Edited

SolidJS has JSX.
It's like Svelte and React had a baby

Collapse
ย 
eerk profile image
eerk โ€ข

That's because React doesn't even have a ngFor :( You have to write a whole loop yourself... I still can't believe it...

Collapse
ย 
brense profile image
Rense Bakker โ€ข

You don't have to invent the for loop yourself, JavaScript has many different ways to loop over things built in.

Collapse
ย 
brense profile image
Rense Bakker โ€ข

Solidjs uses jsx natively and a lot of frameworks like Astro support mdx files, which support jsx.