Just Another Tech Blog Filippos Karailanidis

Choosing Between React, Elm and Svelte

Utilizing JS frameworks to enhance existing web applications
9 September, 2019

Current State of Affairs

My current projects are all built using PHP frameworks and sprinkling some JS/jQuery on top.

It’s not that I have been living in a cave. I am fully aware of javascript frameworks, and specifically at work I mostly write React these days.

Converting to one of these just for the sake of it would not be practical. And to be honest I am not entirely convinced it is appropriate for my specific use case.

On the other hand, there come times when the jQuery spaghetti starts to emerge when you want to go juuuust a little bit further with javascript, and you would really like to use a single React component right there.

So, what I am currently searching for, and what this post is about, is to find the best way to introduce small JS widgets inside the application. These widgets should be easy to write, easy to maintain, and not take up more space than they need to.

The JS framework era

React (and js frameworks in general) offers a very smooth user experience by loading the whole app once and then working from the client. It manages to do that while at the same time saving the developer a lot of trouble, and making development honestly quite enjoyable.

That’s the enormous value the JS frameworks have brought to the market in my opinion: Scale.

Multiple people can work on a big React codebase which can be neatly organized with components. This would be unthinkable in the jQuery age.

The reason is that they have made it possible to write in a declarative way for the browser.

Utilizing Declarative Programming

Traditional imperative programming requires you (the developer) to instruct the browser command-by-command what you want it to do.

For example, this is imperative:

const button = document.getElementById('button');
button.setAttribute('style','color:#f00');
button.text = "Submit button"

This on the other hand, has the same result but is declarative:

<button style='color: #f00'>
    Submit button
</button>

In a broad sense, declarative programming means you just describe the result, and let the underlying engine take care of it for you.

React. Elm. Svelte.

I have chosen three rather unlikely companions.

All three of them want to build Single Page web applications, and all three of them use different ways to accomplish that goal.

We are going to try and use each one to inject some functionality into an existing codebase.

Let’s build a counter

We will try to build something simple, which at the same time utilizes one of the most shought out features of these frameworks: state management

The resulting application will look like this:

React

React is built by Facebook to create large Single Page Applications while at the same time being as simple as possible.

Setup

We will be using a utility called nano-react-app that makes the setup process as painless and optimal as possible.

npx nano-react-app counter-react
cd counter-react
npm install

This will install all project dependencies needed

This is the code for the React application (using hooks to be more compact)

Code

src/App.js

import React, {useState} from "react";

export default function Counter(props) { 
  const [count, setCount] = useState(0);

    return (
      <div>
        <h1>Count: {count}</h1>
        <button onClick={() => setCount(count+1)}>Increase Count</button>
      </div>
    );
}

We need to specify here the id of the node where our application will be mounted. Here I used the id “counter-react”

src/index.js

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

ReactDOM.render(<App />, document.getElementById("counter-react"));

And now we build our application for production.

Nano-react-app is using parcel (default build settings)

npm run build

Results

node_modules size: 111MB
counter-react.min.js size (minified, uncompressed): 126KB

We see that the resulting js file is quite big for such a small “application”.

This is because this includes the whole react library that’s needed in order to run our code.

In a fully-fledged application this of course would be not much overhead, but here in our case this feels quite bloated for the simple function we are trying to achieve. For comparison, the whole jQuery library that it’s so hip to hate on, comes up at 86KB

Elm

Elm is not as popular as react, in fact most of you might not even have heard it before.

Elm also compiles to JS, just like React does, and results in a standalone web application.

Unlike React though, Elm has its own syntax which is heavily influenced by functional programming.

What makes Elm a very attractive option to me as a developer, is that it offers incredible type safety that JS is not able to provide on its own. Functional programming is a paradigm that I really want to look into in the coming years and Elm is a perfect starting point.

Setup

npm install -g elm
mkdir counter-elm
cd counter-elm
elm init

Code

Create the main application file.

The syntax might look weird at first, but for someone who already writes React it’s not so hard to figure things out.

src/Main.elm

module Main exposing (Model, Msg(..), init, main, update, view)

import Browser
import Html exposing (Html, button, div, h1, text)
import Html.Events exposing (onClick)

main =
    Browser.sandbox { init = init, update = update, view = view }

-- MODEL

type alias Model =
    Int

init : Model
init =
    0

-- UPDATE

type Msg
    = Increment

update : Msg -> Model -> Model
update msg model =
    case msg of
        Increment ->
            model + 1

-- VIEW

view : Model -> Html Msg
view model =
    div []
        [ h1 [] [ text ("Counter: " ++ String.fromInt model) ]
        , button [ onClick Increment ] [ text "Increment Count" ]
        ]

By default, elm make builds an HTML file with the whole SPA.

We just want the js though, which we can specify with the --output flag

elm make src/Main.elm --optimize --output=counter-elm.js
uglifyjs counter-elm.js --compress 'pure_funcs="F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9",pure_getters,keep_fargs=false,unsafe_comps,unsafe' | uglifyjs --mangle --output=counter-elm.min.js

Afterwards you can mount the app like this

  <script src="counter-elm.min.js"></script>

  <div id="elm"></div>
  <script>
    var app = Elm.Main.init({
        node: document.getElementById('elm')
    });
  </script>

Results

node_modules size: 0B
counter-elm.min.js size (minified, uncompressed): 28KB

Now we’re getting there. Even though we include the whole Elm engine, the bundle size is much smaller and more representative of what we’re trying to achieve.

Svelte

I am not sure Svelte should be called a web framework because it’s on a whole category of its own, much closer to bare metal from what I can tell.

It challenges a lot of things we take for granted and I’m curious to see if it gains traction in the future.

Setup

The simplest way I found to get started, is to just play in the REPL and then download the code and build it for production locally.

https://svelte.dev/repl/

Code

Svelte looks a lot like javascript but has a few unique identifiers. Not that hard to get used to.

<script>
	let count = 0;
	function increaseCount() {
		count = count + 1
	}
</script>

<h1>Count: {count}</h1>
<button on:click={increaseCount}>Increase Count</button>

After downloading from the REPL, run

Svelte is using rollup (default build settings)

npm install
npm run build

Results

node_modules: 25MB
counter-svelte.min.js (minified, uncompressed): 3KB

Now we’re talking.

Svelte is clearly the winner, being able to provide the most optimized declarative programming experience in JS.

Overview

This was a very nice experiment for me and gave me some perspective for what is out there. Here is how I would rank each of the frameworks and where I would use each one.

React

https://reactjs.org/

React has some very powerful pros on its list. Since it’s the most popular framework out there, it makes it ideal for big projects.

All of these are very compelling reasons if you are a company looking to develop your next big thing.

React was built to create large Single Page Applications by many developers, and that’s where it shines.

Elm

https://elm-lang.org/

I love Elm. The whole concept of functional programming with strict types and type inference just draws me. I feel it’s a higher form of programming, where you have a whole science (math) to back you up and make sure you eliminate a whole class of bugs.

I’m not claiming it’s a silver bullet, obviously you can write bad code at any language. This is just a personal preference and I definitely think I’m moving towards Elm.

Downsides? I havent’ developed anything big in Elm yet, but from what I can tell it’s a bit cumbersome to deal with sideffect-y things like web sockets etc.

Svelte

https://svelte.dev/

Svelte is very cool. I like its bare-minimum approach and the way it give you exactly what you need. If I need a small widget to go into an existing project of mine, this is how I’m building it.

However, I wouldn’t pick it for a large Single Page Application.

I don’t doubt it can fare well, there are a lot of things built in the language to handle the task. It’s just as I mentioned above, I’m moving towards functional programming and if I wanted to build a fully-fledged app, then Elm would be my language of choice.

Conclusions

This article presents arguably a superficial view of each language and does not get into the nitty gritty. It’s meant to document the process I went through and save you a couple of hours of going through the same.

Bundle size is just one metric. The reason I’m choosing to focus on size, is that I want to deliver functionality to the user in the most performant way possible.

For me and for the near future, svelte will probably be my goto for small js widgets, and Elm for SPAs.

Is this the best for you?

In the case of a Single Page Application there are many other variables to consider:

These are not in the scope of this article, but could be of another one in the future