Posted 8 days ago. Visible to the public.

esbuild: Make your Rails application show build errors

Building application assets with esbuild is the new way to do it, and it's great, especially in combination with Sprockets (or Propshaft on Rails 7).
You might be missing some convenience features, though.

Here we cover one specific issue:
Once you have started your development Rails server and esbuild with the --watch option (if you used jsbundling-rails to set up, you probably use bin/dev), esbuild will recompile your assets upon change, but build errors will only be printed to the terminal. Your application won't complain about them -- instead it just delivers the files that were previously built and you might not notice something went wrong.

Cry no more, here is how to solve that.

  1. Have esbuild write errors to a file,
  2. make the Rails app render such errors,
  3. automatically reload to show errors immediately (optional).

Make esbuild write errors to a file

In your esbuild.config.js, you probably have something like this:

Copy
const watch = process.argv.includes('--watch') require('esbuild').build({ ... watch: watch, ... })

Now tell it to write errors to a file esbuild_error_development.txt in your project root:

Copy
const watch = process.argv.includes('--watch') const railsEnv = process.env.RAILS_ENV || 'development' const errorFilePath = `esbuild_error_${railsEnv}.txt` const path = require('path') const fs = require('fs') function handleError(error) { if (error) fs.writeFileSync(errorFilePath, error.toString()) else if (fs.existsSync(errorFilePath)) fs.truncate(errorFilePath, 0, () => {}) } require('esbuild').build({ ... watch: watch && { onRebuild: handleError }, ... })

Tell your Rails application about esbuild errors

We now tell our Rails app to render contents from that file, if there are any.
That should only happen in development, since tests or production environments will fail when trying to compile their assets up front.

Copy
class ApplicationController < ActionController::Base include EsbuildErrorRendering if Rails.env.development? end
Copy
module ApplicationController::EsbuildErrorRendering ESBUILD_ERROR = Rails.root.join("esbuild_error_#{Rails.env}.txt") # see esbuild.config.js def self.included(base) base.before_action :render_esbuild_error, if: :render_esbuild_error? end private def render_esbuild_error heading, errors = ESBUILD_ERROR.read.split("\n", 2) # Render error as HTML so rack-livereload can inject its code into <head> # and refresh the error page when assets are modified. render html: <<~HTML.html_safe, layout: false <html> <head></head> <body> <h1>#{ERB::Util.html_escape(heading)}</h1> <pre>#{ERB::Util.html_escape(errors)}</pre> </body> </html> HTML end def render_esbuild_error? ESBUILD_ERROR.size > 0 end end

Note how we are rendering HTML. We don't do that because it's pretty, but to allow tools like Rack::LiveReload to inject themselves into the HTML response, and trigger a reload when the error page is shown (and show the application when the error has been fixed).

Optional: Configure Guard / Rack::LiveReload

If you use Guard with Rack::LiveReload to reload your application when assets change, tell it about that new file. Add to your Guardfile:

Copy
watch(%r(^esbuild_error_development\.txt$))

Note that the file must exist when Guard starts, but we'll take care of that in the next step.

Configure git

As mentioned above, the esbuild_error_development.txt file must exist for Guard to watch it. [1]
We simply add an empty file to the repo:

  1. Create an empty error file:
    Copy
    touch esbuild_error_development.txt
  2. Stage it
    Copy
    git add esbuild_error_development.txt
  3. To avoid developers accidentally commiting their error messages, ignore any further changes to it.
    Add /esbuild_error_* to your project's .gitignore.

Try it out

That's it! Restart your application and esbuild, and break stuff. You should see error messages be delivered by your application.

Demo


[1] Side note: Our implementation of the controller module also expects the file to exist. If you don't use Guard and consider that requirement annoying, you could change render_esbuild_error? to just check for ESBUILD_ERROR.exist? and not add an empty error file to your repo.

Flaky tests are tests that sometimes fail for no obvious reason. They are the plague of many end-to-end (E2E) test suites that automate the browser through tools like Capybara and Selenium.

Join our free training event and learn to fix any flaky test suite, even in large legacy applications.

Owner of this card:

Avatar
Arne Hartherz
Last edit:
4 days ago
by Arne Hartherz
Attachments:
esbuild-error-demo.gif
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Arne Hartherz to makandra dev
This website uses short-lived cookies to improve usability.
Accept or learn more