DEV Community

Masatoshi Nishiguchi
Masatoshi Nishiguchi

Posted on • Updated on

Elixir Phoenix 1.6 Esbuild + SCSS

I want to leave a note about what I stumbled on in my setting up SCSS for my Phoenix 1.6 app.
I need SCSS because I enjoy customizing Bootstrap styles using SCSS. I am not planning to use Tailwind.




  • preconfigured in a newly-generated Phoenix 1.6 app
  • bundles JS files into priv/static/assets/assets/app.js
  • bundles CSS files into priv/static/assets/assets/app.css in case CSS files are imported into some JS files
  • the esbuild executable gets installed automatically as long as phoenixframework/esbuild is configured correctly
  • for SCSS we need use either:
  • typically in development, we use Phoenix.Endpoint watcher so esbuild can build assets every time we make changes in our assets
  • typically in production, we compile assets

configure esbuild

Three files are involved for configuring phoenixframework/esbuild.

  • mix.exs
    • elixir-related settings
  • config/config.exs
    • esbuild-related settings
    • we need to specify as args:
    • the version of the esbuild executable we want to use
    • input file
    • output dir
    • etc
  • config/dev.exs

It is a lot easier than I expected. But by default esbuild does not know how to handle SCSS files. CargoSense/dart_sass comes in handy when we really want to use SCSS.


configure esbuild

Just like phoenixframework/esbuild, three files are involved for configuring CargoSense/dart_sass.

  • mix.exs
  • config/config.exs
  • config/dev.exs

Initially I just copied and pasted all the snippets from the ducumentation thoughtlessly and one issue occurred. Because when both phoenixframework/esbuild and CargoSense/dart_sass are used and they both output the CSS build results to the same file priv/static/assets/app.css, which means they keep on overriding that same file.

After all, I realized the following:

  • the easiest way is to use phoenixframework/esbuild for JS only and use CargoSense/dart_sass for SCSS
  • it is nice to give the destination file a name other than assets/app.css for debuggability later on (E.g., "assets/from_scss.css")

Then our HTML template reference those files separately.

<!-- lib/my_app_web/templates/layout/root.html.heex -->

-  <link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/assets/app.css")}/>
+  <link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/assets/from_scss.css")}/>
   <script defer phx-track-static type="text/javascript" src={Routes.static_path(@conn, "/assets/app.js")}></script>
Enter fullscreen mode Exit fullscreen mode

My config/config.exs ended up looking like this.

# config/config.exs


# Configure esbuild (the version is required)
config :esbuild,
  version: "0.14.1",
  default: [
    args: [
    cd: Path.expand("../assets", __DIR__),
    env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}

config :dart_sass,
  version: "1.44.0",
  default: [
    args: [
    cd: Path.expand("../assets", __DIR__)
Enter fullscreen mode Exit fullscreen mode

If we want to migrate an app from Phoenix 1.5 to Phoenix 1.6, is a nice tool. It reveals all the changes between different versions.


Top comments (0)