Nicd

Nicd

tl;dr

MBU is a collection of functions and a few macros that I wrote to help in using Mix as a build tool for e.g. frontend building. It supports task dependencies, and watching paths (either with watchers built in to different tools or custom watchers using file_system). You can find it on Hex, documentation on Hexdocs, and code on GitLab.

Motivation

This blog post explains my motivations best (has old code samples but the motivations are the same). The short version is that I was tired of learning different frontend build systems that all seemed to be magical, fragile, or difficult to maintain. I thought about Make and NPM scripts but ended up with my own solution that would serve my own needs: use Mix as a build tool to call the usual Node tools, so that I can write my build scripts in Elixir and know how they work.

If I succeeded in creating anything useful is left up to the reader. :sweat_smile:

How it works

Let’s suppose the following config:

config :mbu,
  auto_paths: true, # Autogenerate output path for tasks
  create_out_paths: true, # Create output path when task runs
  tmp_path: Path.expand(".tmp") # Path under which autogenerated output paths are, i.e. where task output is stored

Then we could have the following build task:

defmodule Mix.Task.Css.Compile do
  use MBU.BuildTask

  @deps ["css.autoprefix", "assets.copy"]

  def in_path(), do: Path.join("assets", "css") |> Path.expand()
  def in_file(), do: Path.join(in_path(), "frontend.scss")

  def args() do
    [
      "--source-map-embed",
      "--output",
      out_path(),
      in_file()
    ]
  end

  task _ do
    exec("node_modules/.bin/node-sass", args()) |> listen()

    out_file = Path.basename(in_file(), "scss") <> "css"
    print_size(Path.join(out_path(), out_file))
  end
end

What this task does is:

  1. Runs the dependencies listed in @deps in parallel before the task is run.
  2. Creates an output directory for the build artifacts based on the task name and :tmp_path, in this case it would be something like /path/to/proj/.tmp/css.compile. This path is returned by out_path/0.
  3. Executes the node-sass command with the given arguments, waits for it to complete and prints the output.
  4. Prints the size of the compiled file using print_size/1.

Now if we wanted to watch the assets/css directory for changes, we could create another task and in that task’s task block, we can do:

watch("FrontendCompileCSS", Mix.Task.Css.Compile.in_path(), Mix.Task.Css.Compile)
|> listen(watch: true)

What this does is it listens to the path given in the second argument for changes, and then runs the task given in the third argument (the first argument is for logging purposes). The last argument could also be an anonymous function to call. The watch: true option makes the listen/2 function also listen for an enter key from the user, which will stop the watching.

This was just a small example, for more realistic usage, see my website’s build tasks at lib/mix/tasks · master · CodeStats / code-stats · GitLab (probably a bit overengineered at the moment as it will have more complex targets in the future).

Pros & cons

I am obviously biased and blind to my own creation but here’s what I think of it:

  • Pros:
    • Minimal features & magic
    • Get to write Elixir, no external deps
    • Easier to fix/debug when build breaks because it’s just small Elixir tasks
  • Cons:
    • Minimal features & magic
    • Verbose especially for small tasks
    • Some tools don’t have command line interfaces to call
    • Needs more testing on Windows

I hope it can be useful to someone or at least can inspire for better Mix helpers in the future (since the code is really not that nice). I use it in my own projects and it seems to work well for me, and now at least I can only blame myself if something goes wrong in the build. If you use it for something, please let me know any feedback you have in this thread. I will also use this thread to notify if I update MBU with new stuff.

Most Liked

Nicd

Nicd OP

Well, I changed the name to MBU: Mix Build Utilities and put it on hex.pm: mbu | Hex

Hope someone finds it useful for something. :slight_smile:

Nicd

Nicd OP

First post has been updated with the latest info :slight_smile:

3.0.0 release brings automatic folder handling, so that you don’t need to write your own out_path/0 for tasks that store things in temporary output folders.

christiansakai

christiansakai

I like the concept! I think this is valuable not only for building JS/CSS, but any front end assets in general, such as Elm.

What is the downside of this approach rather than with the basic Brunch configuration that comes with Phoenix?

Where Next? Top

Trending in Announcing Top

restlessronin
The repo is at GitHub - cyberchitta/openai_ex: Community maintained Elixir library for OpenAI API · GitHub. Docs are at OpenaiEx User Gu...
152 12366 136
New
type1fool
WebAuthnLiveComponent WebAuthnComponents See this post about renaming the package. Passwordless authentication for Phoenix LiveView app...
New
GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
ausimian
Castle is a package I put together to assist with building Elixir releases capable of being live-upgraded via the ‘official’ release hand...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
drozdzynski
Storex is a frontend store with state management handled on the backend. It allows you to update the store state both from the frontend a...
New

Other Trending Topics Top

budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New
Null-logic-0
What IDE or editor are you using for Elixir development? Personally, I use Zed, and I really like it, but sometimes I wish there were a ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews