I’m building a small page to learn Elm over here (sorry for the language in the app itself being only German, but that’s how my potential user base would roll ).
Everything works kind of fine so far, but when I inspect my deployed page with the dev tools in the browser, I can see that the application code takes up more than 400 kilobytes even though I build with the optimisation flag set:
elm make src/TidesWater.elm --optimize --output out/index.html
Reading up on minification in Elm, I would expect to be lighter than 25 kB because I have only around 500 loc.
Do external minification and gzip make up for the difference or am I doing something wrong? I already tried compiling to a JavaScript file and embedding it into a separate handcrafted index.html, but that didn’t change anything (as I assumed).
I’m using Parcel as a dev tool and packager, and I strongly recommend it. It’s a zero config tool, and defaults are super nice for Elm. You use parcel watch index.html for dev, then parcel build index.html for prod and it will automatically build and minify your sources (elm, js, rust, typerscript, less or sass…).
Yeah, gzipping makes a huge difference. Normally compression is done by the web server, so you publish your minified JS bundle, the server compresses upon serving and browser decompress it on the fly. Of course you can gzip your bundle manually to see how much you can save but in my experience you let that phase to the deploy web server.
500 LOC with dependency only on core & elm/html would probably result in something around 10-15k minified-gzipped bundle.
500 LOC with a lot of functionality brought in from various dependencies is a different story. You have to take into account the code from the libraries you import. Your current code is around 26k (minified-gzipped) for 363 total LOC. In any case, this is a starting point. From here, if the dependencies remain the same, extra code should only increment the final bundle by minimal amounts.
To point one thing out: My goal is not to squeeze the bundle size as far as it can go & down to the last bit, just getting into the order of magnitude of less than 50 KByte or so is absolutely fine for me. Therefore, I think I’ll give parcel a try, that one looks promising with its easy setup, requiring no extra plugin for Elm.
Also, I’ll mark this as solved as soon as I get somewhere.
First, I tried out good old uglify-js, but that didn’t play together with Elm as nicely as promised (the set of parameters recommended everywhere gave me an error about not defined functions).
Next, I looked into parcel, which was more invasive on my package.json than I expected, adding for instance the node-elm-compiler on its own, which I was not too happy about - also, I felt somewhat forced to wrap my entire dev environment in parcel, which doesn’t suit my taste too well because I like the shallow simplicity of the Elm setup I have.
So after all, I settled with elm-minify. The GitHub repo is archived and the last commit is from 2019, but it does what it is supposed to: With one simple call, it reduces my compiled JavaScript from about 400 to something in the figures of 80 KBytes.
Because GitLab Pages does not offer server side gzip compression, I’m now doing this myself as well. And because I was already at it, I even added brotli to the fold. So now my deploy stage looks something like this:
pages:
stage: deploy
artifacts:
paths:
- public
only:
- main
script:
- elm-minify out/elm.js --overwrite
- mkdir -p public
- cp out/elm.js public/.
- cp index.html public/.
- find public -type f -regex '.*\.\(htm\|html\|txt\|text\|js\|css\)$' -exec gzip -f -k {} \;
- find public -type f -regex '.*\.\(htm\|html\|txt\|text\|js\|css\)$' -exec brotli -f -k {} \;
This process brings my bundle size down to just above 22 KBytes, which makes loading the page practically instantaneous on a normal connection and bearable even on the most throttled one browsers do simulate. Being situated in a rural area in Germany, this really is a selling point.
I’m sorry to have caused a misunderstanding, but you’ve got me wrong: Uglify didn’t break my code, rather did running the recommended set of arguments already return the described error. The command used was basically this one: 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 (and yes, I replaced variables with actual file names and whatnot )
I’ve read through multiple guides, including the official one, and couldn’t make Uglify work. elm-minify gives me what I want, so I don’t spend too much thought on whether it implements something on itself or just encapsulates existing tools.
That’s not to say you can’t make it work, it just took me longer than I hoped to be stuck on a cryptic error.