Structure for multiple small "apps" when using Elm with webpack (elm-webpack-loader)

589 views
Skip to first unread message

Rafał Cieślak

unread,
Nov 19, 2016, 3:58:27 PM11/19/16
to Elm Discuss
The project I'm working on is not a SPA, it's a rather big Rails app that sometimes needs JS to make some part of the page dynamic – usually it's about dynamic forms.

When I was thinking about ways in which I can integrate Elm into the project, I thought about having a separate Elm project for each feature: so there would be an order_form folder with its own elm-package.json, its own versions of dependencies and Elm. Beside it there would be another folder, let's say product_form, also with its own elm-package.json and so on.

I quickly realized it could be a nightmare from the maintainability point of view, since each folder would require its own version of Elm, thus each folder would need to have a separate package.json which would install Elm from npm.

I looked at elm-webpack-loader and found out that it requires me to have a single elm-package.json for the whole project. Separate forms would have an access to the same dependencies and the same version of Elm. At first I was put off by this solution, as it was completely the opposite of what I had in mind (separate elm-package.json for each form). Finally, I had a sudden moment of clarity and I realized that what elm-webpack-loader does is exactly what we already do with our smaller React apps: each lives in its own directory, each has a separate entry point in webpack config, but all share the same package.json and all have access to the same deps.

Do I get it right? If so, how should I structure the apps on the Elm side?

I was thinking about creating a directory app/assets/javascripts/elm. Each Elm "app" would have its main module under app/assets/javascripts/elm/src. Each Elm "app" would also have its own entry point in webpack. app/assets/javascripts/elm/src would be added as a source directory in source-directories in elm-package.json. Then I could "namespace" each "app", so that there's OrderForm (the main module) and everything that is specific to it is nested under OrderForm (OrderForm.Foo, OrderForm.Bar).

This way webpack could easily handle building all the Elm apps along with React apps.

Are there any pitfalls in my thinking? Do you see ways in which this approach could fail? If you use elm-webpack-loader and had a similar problem, I'd love to hear how you handled it!

Rafał Cieślak

unread,
Nov 23, 2016, 1:49:19 PM11/23/16
to Elm Discuss
For the posterity, I implemented said "architecture" in one of my side projects. https://github.com/ravicious/rails-elm-forms/commit/b5ac6964f

The only difference from what I said above is that the Elm apps don't have their own entry points in the webpack config. Instead, the entry points are the JS file which require the Elm file and then embed the app.

I wish I could use Closure Compiler, but I couldn't get the trio (Closure Compiler + webpack + Elm) to work together, for some reason the two webpack Closure Compiler plugins I tried to use mess up the Elm code.

Robin Heggelund Hansen

unread,
Nov 23, 2016, 10:07:12 PM11/23/16
to Elm Discuss
I would just keep everything in one Elm app, then use a router to display the correct page.

When it comes to google closure, Elm only works with SimpleOptimizations. There are two-three lines in the runtime which causes problems with AdvancedOptimizations.
In any case, the difference between Google Closure and Uglify is very small when it comes to Elm. In my app, Uglify brings size down to ~80Kb, while Closure with AdvancedOpts brings it down to ~74Kb. When gzipped, the differences are barely noticeable.

Noah Hall

unread,
Nov 23, 2016, 10:14:43 PM11/23/16
to elm-d...@googlegroups.com
At NoRedInk, we use a single elm code base with multiple entry points
for each different page with a unique elm app. This is ideal in terms
of build time and reliabitly, as everything can be built and once and
share a single lot of packages.

We also use the webpack loader for this style of app (though to be
fair, we made it).
> --
> You received this message because you are subscribed to the Google Groups
> "Elm Discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to elm-discuss...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Rafał Cieślak

unread,
Nov 24, 2016, 7:40:12 AM11/24/16
to Elm Discuss
Robin:

I would just keep everything in one Elm app, then use a router to display the correct page.

The problem I see with this is that our app is not SPA, so each page that needs an Elm app would need to load a big blob of JS with dependencies of all the Elm modules in our source code.

When it comes to google closure, Elm only works with SimpleOptimizations.

Thanks for the info, I was under the impression that it worked okay with advanced optimizations.

In any case, the difference between Google Closure and Uglify is very small when it comes to Elm.

Yeah, that's why I eventually gave up – the few KBs of reduced size were not worth the time I spent figuring out how to make this all work with Closure Compiler. ;)



Noah:

So you use a similar setup to what I described, right? I assume that by "a unique Elm app" you mean "a main module" and that all the main modules share a single elm-package.json.

This is ideal in terms of build time and reliabitly, as everything can be built and once and  share a single lot of packages. 

Yeah, definitely. Another advantage for me is what I mentioned earlier: it can be easily plugged in to our existing workflow with webpack.

Robin Heggelund Hansen

unread,
Nov 24, 2016, 9:44:12 AM11/24/16
to Elm Discuss
Define "big blob of js"

React, the framework alone, is around 54kb gzipped, my elm SPA is currently half that gzipped. Also, you would load the same blob once, as it's cached in your browser.
Currently, if you split your app up into multiple entry points, those would still require the Elm runtime, core library, virtual dom and html library.
Reply all
Reply to author
Forward
0 new messages