How do I make phoenix server refuse to serve pages when there's an error in assets?

Phoenix server refuses to serve pages when there are pending migrations. That’s great! If it didn’t, it would often not really matter, often it would crash in an obvious way, but sometimes it would be difficult to realize what’s going on.

How can I have the same behaviour when assets fail to build? I always want to know if there’s an error in the javascript or CSS I’m playing with. Always. Otherwise I’m just debugging whatever previous version of the code I had working and I waste much time trying to figuring out why nothing works.

We’re using esbuild:

config :esbuild,
  version: "0.19.5",
  default: [
    args: ~w(
      js/app.js
      --bundle
      --define:global=window
      --target=es2017
      --outdir=../priv/static/assets
      --external:/fonts/*
      --external:/images/*
      --external:/favicons/*
    ),
    cd: Path.expand("../assets", __DIR__),
    env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
  ],

All I get are errors in the server console, e.g.

✘ [ERROR] Could not resolve "./auto_focus"

    js/app.js:215:26:
      215 │ import { Autofocus } from "./auto_focus"
 
[watch] build finished, watching for changes...
3 Likes

Perhaps a github issue is in order since this post got zero traction? It doesn’t look like there is a tenable way to make this happen without changing Phoenix itself (I could be wrong, though). I get burned by this often enough and would also love an option to upgrade these warnings to errors.

The problem here is that phoenix is completely unaware of what happens in the asset build pipeline. It just starts a process and that’s it. It can have a plug to check ecto migration status, because it can and knows how to talk to ecto. The same is not present for the assets pipeline. It’s also less likely to be added in phoenix itself given the assets pipeline is generally expected to be switched out easily.

The only “contract” assets pipelines have with phoenix is that they can be started as an external process (watchers) and that they eventually create/update files in /priv/static.

4 Likes

Good info, thank you.

Interesting question! Looking at the esbuild docs you should be hook something up with your own esbuild plugin: esbuild - Plugins

Actually that’s an interesting little problem so I’ve created an example phoenix app that creates a little plugin that raises an error if there are currently any errors in the esbuild build:

It works by writing the build status to assets/esbuild_build_status and then a AssetStatusWeb.CheckAssetStatusPlug plug reads that in development mode, and if there are any errors the plug raises the errors. Here’s the commit that shows how it works:

And this is what the error looks like:

The format could definitely be improved, the command line version is much more compact and useful:

Rebuilding...
[watch] build started (change: "js/app.js")
✘ [ERROR] Could not resolve "./auto_focus"

    js/app.js:26:26:
      26 │ import { Autofocus } from "./auto_focus"
         ╵                           ~~~~~~~~~~~~~~

build ended with 1 errors
1 error
[watch] build finished

I’ve released the above project under the MIT license so feel free to copy it into your project or release a library for it!

9 Likes

WHOA! Thanks!!! :heart:

1 Like

Thanks @axelson :heart:

We’re probably going to go that way then.

I also opened an issue for esbuild, in case they decide to make things easier.

2 Likes