How I Handle Static Assets in my Phoenix apps

June 07, 2021 • 3 minute read • @mitchhanbergAnalytics

I no longer use Webpack.

Now I use esbuild, postcss-cli, and cpx.

  • esbuild bundles and transpiles my JavaScript files extremely fast.
  • postcss-cli processes my CSS and can run the TailwindCSS JIT mode without any problems.
  • cpx copies other static files from the assets directory into the priv directory.

Running each of these tools in development is just as easy as running Webpack.

# config/dev.exs

esbuild = Path.expand("../assets/node_modules/.bin/esbuild", __DIR__)
config :my_app, MyAppWeb.Endpoint,
  http: [port: 4000],
  debug_errors: true,
  code_reloader: true,
  check_origin: false,
  watchers: [
    "#{esbuild}": [
      "./js/app.js",
      "--target=es2015",
      "--bundle",
      "--outdir=../priv/static/js",
      "--sourcemap",
      "--watch",
      cd: Path.expand("../assets", __DIR__)
    ],
    node: [
      "./node_modules/.bin/postcss",
      "./css/app.css",
      "--dir",
      "../priv/static/css",
      "-w",
      cd: Path.expand("../assets", __DIR__),
      env: [{"NODE_ENV", "development"}, {"TAILWIND_MODE", "watch"}]
    ],
    node: [
      "./node_modules/.bin/cpx",
      "'static/**/*'",
      "../priv/static",
      "--watch",
      cd: Path.expand("../assets", __DIR__)
    ]
  ]

esbuild

esbuild home page

esbuild is part of the newest generation of JavaScript tooling. It is built in Go and is extremely fast. All I really need is my JavaScript to be bundled and transpiled to some degree, and esbuild does just that.

Since esbuild is not available in our path, we'll have to declare our watcher with the absolute path to the binary. To make this legible, I have pulled out the absolute path to a variable so it reads more like what we are used to.

PostCSS

Since I'm are no longer using Webpack, I just use the postcss-cli.

The third highlighted line demonstrates that this configuration is really just a declarative way to run commands with System.cmd/3. This means I can use all the same options! I am using the new TailwindCSS JIT, which requires a couple of environment variables to be set, so I pass the :env option to include variables in the environment of PostCSS.

cpx

Once I ditched Webpack, I realized that in addition to bundling my JS and CSS, it was responsible for copying my other static assets to the priv directory. Luckily there is this handy npm package called cpx that will watch a glob of directories and copy them somewhere else when it notices changes.

Wrapping Up

The speed increase from switching from Webpack to esbuild is well worth the effort to make the switch.

Do you use something other than Webpack in your Phoenix applications? Let me know on Twitter!


If you want to stay current with what I'm working on and articles I write, join my mailing list!

I seldom send emails, and I will never share your email address with anyone else.