Walkthrough: Introducing Elm to a JS Web App

When we introduced Elm to our production front-end at [NoRedInk](https://www.noredink.com/jobs), we knew what to expect: the productivity benefits of an incredibly well-built language, and the intrinsic risk of integrating a cutting-edge technology for the first time. Knowing these risks, we came up with a minimally invasive way to introduce Elm to our stack, which let us get a sense of its benefits without having to make a serious commitment. Since several people have asked me about this, I’d like to share how we did it! This walkthrough assumes only a beginner level of Elm familiarity. I won’t be spending much time on syntax (though I will link to the [syntax guide](http://elm-lang.org/docs/syntax) as a reference) or functional programming staples like [map](http://package.elm-lang.org/packages/elm-lang/core/2.1.0/List#map) and [filter](http://package.elm-lang.org/packages/elm-lang/core/2.1.0/List#filter), so I can go into more depth on introducing Elm to an existing JS codebase. Let’s dive in! ## Elm for…business logic? Elm is known for its UI-crafting capabilities (both as [an improvement over React](http://elm-lang.org/blog/blazing-fast-html) as well as for [game programming](https://github.com/BlackBrane/destroid)), but building out an entire UI in a new language was more commitment than we wanted to tackle as a starting point. We didn’t want a drink from the fire hose; we just wanted a little sip. Fortunately, it turns out Elm is also a phenomenal language for writing business logic. Besides making it easy to write clear, expressive code, Elm also makes it easy to write code that’s rock-solid reliable. How reliable? Here are some numbers: * Students answer over 2.5 million questions per day on NoRedInk. Needless to say, edge cases happen. * [3% of our code base](https://twitter.com/rtfeldman/status/628433529538412544) (so far!) is Elm code. Not a ton, but a substantial chunk. * We have yet to see our production Elm code cause a single runtime exception. This is not because we sheltered it; our production Elm code implements some of the most complicated parts of our most mission-critical features. Despite that level of exposure, every runtime browser exception we’ve ever encountered—in the history of the company—has been fixed by changing CoffeeScript or Ruby code. Never by changing Elm code. This is also not because we have some particularly unusual code base; rather, it’s because Elm’s compiler is astonishingly helpful. Let’s get a taste for that by introducing Elm to an existing JavaScript code base! **Adding a hint of Elm to a JS TodoMVC app** We’ve been using [React](http://reactjs.com/) and [Flux](https://facebook.github.io/flux/docs/overview.html) at NoRedInk since they came out in 2014. Flux stores are a convenient place to introduce Elm to your code base, because they’re all about business logic and are not concerned with UI rendering. Porting a single Flux store to Elm proved a great starting point for us; it was enough to start seeing real benefits, but not such a big commitment that we couldn’t have changed our minds and turned back if we’d wanted to. Let’s walk through doing the same thing: porting a store from the [Flux TodoMVC](https://github.com/facebook/flux/blob/master/examples/flux-todomvc/js/stores/TodoStore.js) example to Elm. First, grab Facebook’s [Flux](https://github.com/rtfeldman/flux) repo. (I’m linking to a fork of their repo, in case theirs has changed since I wrote this.) and `cd` into its directory. At this point you should be able to [follow the instructions for building the TodoMVC example](https://github.com/rtfeldman/flux/tree/35b040e213149b9577dc253d9ca1a4ba086f1159/examples/flux-todomvc#running).

git clone git@github.com:rtfeldman/flux.git
cd examples/flux-todomvc
npm install
npm start

Once you have npm start running, you should be able to open the index.html file in your current directory and see a working app.

If you’re not familiar with the Flux architecture (it’s conceptually similar to The Elm Architecture), now might be a good time to read about it. You don’t need a ton of experience with it to follow along, but having a general idea what’s going on should help.

Now you’ll want to grab yourself a copy of Elm. Either use npm install -g elm or visit elm-lang.org/install to get an installer. When you’re finished, run elm make --help in your terminal and make sure it says Elm Platform 0.15.1 at the top!

Integrating Elm at a basic level requires three things:

  1. A .elm file containing our Elm code.
  2. An elm-package.json file specifying our dependencies.
  3. A JavaScript command to invoke our Elm code.

Let’s create examples/flux-todomvc/TodoStore.elm with the following code:

module TodoStore where

port dispatchCreate : Signal String

Now let’s build it by running this command in the examples/flux-todomvc/ directory:

$ elm make TodoStore.elm --output elm-todomvc.js

The first time you build, you should see this prompt:

Some new packages are needed. Here is the upgrade plan.

 Install:

 elm-lang/core 2.1.0

Do you approve of this plan? (y/n)

After you answer y, Elm will install your dependencies. When it’s done, you should see this message:

Successfully generated elm-todomvc.js.

So far, so good!

Your directory should now contain an elm-package.json file and the compiled elm-todomvc.js file generated by elm make, as well as an an elm-stuff/ folder which holds downloaded packages and the like. I always add elm-stuff/ to .gitignore.

Next we need to add our compiled Elm code to the page.

If we’d incorporated gulp-elm into our project’s Gulpfile (see also grunt-elm, elm-webpack-loader, and this Gist for Sprockets integration), then our compiled Elm code would already be included as part of bundle.js. However, we’re avoiding build tool plugins for this example, so we need to tell our index.html file about elm-todomvc.js by adding a new <script> tag above the one that imports "js/bundle.js" like so:

...

  <script src="elm-todomvc.js"></script><script src="js/bundle.js"></script>

22 notes

  1. vantischen reblogged this from noredinktech
  2. evandrix reblogged this from noredinktech
  3. noredinktech posted this