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
 
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
 
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
 
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
 
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
 
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
 
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.