Large bundle size despite use of —optimize

Hey everyone!

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 :wink:).

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).

The numbers mentioned in the article you’re linking to are after minification and gzip. You need to use a minifier and gzip to get comparable numbers.

1 Like

Hi !

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…).

o/

1 Like

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.

See also:

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.

Thank you all, this is insightful. :slightly_smiling_face:

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.

1 Like

Here I am, having learned a thing or two.

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. :grinning_face_with_smiling_eyes:

1 Like

This is interesting! I have never heard of that before.

  • Which set of parameters is that?
  • Can you link to where you got it from?
  • Can you show the error you got?

elm-minify uses terser which is a fork of UglifyJS with basically the same API. It uses the options from the Elm guide.

This makes me somewhat doubtful that UglifyJS would break your code – but you never know! :grinning_face_with_smiling_eyes:

Oh hi!

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 :wink: )

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. :wink: