Skip to content

Instantly share code, notes, and snippets.

@evancz
Last active December 15, 2023 14:38
Show Gist options
  • Save evancz/fc6ff4995395a1643155593a182e2de7 to your computer and use it in GitHub Desktop.
Save evancz/fc6ff4995395a1643155593a182e2de7 to your computer and use it in GitHub Desktop.
Provide data on large Elm projects

Experience Reports for Large Projects

Elm 0.19 introduced a bunch of optimizations to improve compile times and to make assets small. See the announcement here. It is conceivable to be a bit fancier, but we need to collect some user data.

For example, we can do even better on asset size if we have some sort of “code splitting” mechanism. Instead of turning 50k lines of code into one 114kb file, we can cut it into smaller chunks to get faster page loads overall. But as you you dig into this idea, it reveals itself to be extremely complex. Do you cut along packages? Modules? Functions? How do you draw those lines? For fastest first load? For caching that makes all subsequent loads faster? Should it work different for HTTP1 and HTTP2 clients? Are there nice defaults that cover 99% of cases? My goal is to end up with a design like --optimize that makes all this easy by default, but instead of designing purely on instinct, we will first gather information about the people running large Elm applications.


Gathering Data

If you have 50k+ lines of Elm at your company, you can help by sharing some information on the elm-dev mailing list:

  1. Real-life measurements of Elm’s contribution to page load times
  2. Screenshots or descriptions of two or three different pages
  3. The exact output of the summarize.sh script that appears below

I know folks have theories on the design they want, but please leave that out. The goal is just to get experience reports and knowledgable contacts.

The main benefit of this information is that we now have a basis for more specific questions. Maybe we find patterns that help improve compile times. Maybe they show a certain design will be difficult for some uses. Maybe it is actually a font that is causing slow loads, not Elm. Maybe there is no particular action to take at this time.


Advice

As always, we do not rush the design or implementation of language changes. Language changes are extremely costly. Packages need updateds, editor plugins need updates, applications need updates, etc. That means tens of thousands of people spending weeks of work. So I will prioritize based on what I think makes sense for the ecosystem overall, even if it is not the exact preference of specific individuals.

As a result of these constraints, there is no specific timeline for supporting code splitting. Finding a thoughtful and deliberate solution will be prioritized over finding stopgap measures. These designs can take a long time, tying together different problems in unpredictable ways, so it is likely that other projects will happen before this.

In the meantime, if you are running into measurable page load problems when compiling 100k or 200k lines into one file, I recommend creating a couple of independent files. Maybe your server can send different JS for /profile/*, /settings/*, and /*. This will create some unsightly seams in your application, but it will also get sizes down. Perhaps you can preload things with service workers to smooth this out a bit. I think this should work for most cases, especially considering that the asset sizes are already exceptionally small. I also recommend optimizing things like font loading and CSS to see how far you can go with that. If you do not think that will work for your company, I recommend against using Elm right now.

#!/bin/sh
set -e
## CHECK FOR BINARIES
if ! [ -x "$(command -v uglifyjs)" ]
then
echo 'Error: need uglifyjs to be available for asset size test.'
echo 'You can run `npm install --global uglify-js` to get it.'
exit 1
fi
if [ ! -x elm ] || [ "$(elm --version)" != "0.19.0" ]
then
echo 'Error: need version 0.19 of `elm` binary available on your PATH'
exit
fi
## ACTUALLY MEASURE THINGS
js="elm.js"
min="elm.min.js"
echo "======== DEPENDENCIES ====================="
cat elm.json
echo ""
echo "======== SETUP ============================"
elm make --output=$js $@
rm -rf elm-stuff
echo ""
echo "======== COMPILE TIME ====================="
time elm make --optimize --output=$js $@
echo ""
echo "======== ASSET SIZE ======================="
uglifyjs $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=$min
echo "Initial size: $(cat $js | wc -c) bytes ($js)"
echo "Minified size:$(cat $min | wc -c) bytes ($min)"
echo "Gzipped size: $(cat $min | gzip -c | wc -c) bytes"
rm $js $min
echo ""
echo "======== PROJECT SIZE ====================="
find . -name '*.elm' | xargs wc -l
@evancz
Copy link
Author

evancz commented Aug 29, 2018

If you have thoughts on this, please share them on https://discourse.elm-lang.org/ instead.

No one gets notified about any of the comments here, so it is like hiding a message in a tree in the woods. Someone may see it someday, but there are better ways to communicate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment