4

Not specifically a Rails question, but a question within a Rails app.

In my app I am using the jsbundling-rails gem configured with esbuild.

This gem adds a build line to my package.json file. It works and compiles all my JS and runs fine. However, I found that the generated file is rather large so I started looking at ways to optimise it.

My esbuild statement at this point looks like:

"build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds"

Firstly I thought I could try making my imports conditional. Eg, only import them when they are actually required. I asked another question on how to do that here.

I learned quite a lot digging into that, but at the end of the day it's made no difference to the output of my JS weirdly.

Chrome currently says that my main JS file has 91% code unused. It looks like all the imports are still being compiled together, whether they are statically or dynamically imported. Why can this be?

I then looked further into esbuild, I spotted the --splitting flag. It sounded reasonably correct so I updated my build script to be:

"build": "esbuild app/javascript/*.* --bundle --splitting --format=esm --sourcemap --outdir=app/assets/builds"

This caused a huge amount of outputted JS files (I think they are referred to as "chunks".

I ran my app, and the JS failed to load. The console stated that

Uncaught SyntaxError: Cannot use import statement outside a module

I wasn't 100% sure why was the case but I just guessed that I needed to add type: "module" to my javascript_include_tag in my Rails application layout view.

This made the JS load (which is good :-) )

BUT... The percentage of unused JS code is still 84% of my application.js

So..... my questions are as follows:

  1. Are my dynamic importing of modules working?
  2. Why does static or dynamic importing appear to make no difference?
  3. How can I effectively reduce the size of the output code and reduce the unused percentage of JS on my home page?

This all started because I ran Google's Lighthouse test on my site and it reported my Structure and Accessibility to be practically perfect but performance was < 40. I am aiming to solve this.

I look forward to hearing from you with ideas on how I can try to fix this and improve my Lighthouse Performance score.

rctneil
  • 7,016
  • 10
  • 40
  • 83

1 Answers1

1

Are my dynamic importing of modules working? Why does static or

The paradigm you want is called Propshaft. Try looking at the SProckets -> Propshaft https://github.com/rails/propshaft/blob/main/UPGRADING.md

Why dynamic importing appear to make no difference?

Because even though ESBuild allows for ES Module syntax (import statements), it still bundles everything into "1" big file. (1 big file for each javascript_include_tag you have, of course).

How can I effectively reduce the size of the output code and reduce the unused percentage of JS on my home page?

The sprockets paradigm was built for the HTTP1 web when keeping connections open and progressive download wasn't realistic. HTTP2 changed all that and now it's more efficient to do code splitting as you want to do. But the Rails world is still very behind and most apps still use Sprockets and try to optimize/minify was much as possible.

I'd recommend you take this course of action:

(1) Try the old-style way first. Remove anything unnecessary, split your app into different sections and load different manifest files for different sections. Use minification. See how far that gets you.

(2) Start experimenting with the new Propshaft for a few weeks until you fully understand it. If you feel it is solid, migrate to that.

Jason FB
  • 4,752
  • 3
  • 38
  • 69