Elixir Phoenix 1.6 Esbuild + SCSS
One day I was trying to upgrade one of my Phoenix 1.5 apps to Phoenix 1.6. In that app, I customize Bootstrap styles using SCSS. I want to talk about what I found and stumbled on when setting up SCSS.
TIL
- All explained in Phoenix 1.6 Asset Management documentation.
- For JS and plain CSS, phoenixframework/esbuild with default settings is good
- For SCSS, we can use both phoenixframework/esbuild and CargoSense/dart_sass, but we need to think through how we want build our assets rather than just copy snippets.
phoenixdiff.org
If we want to migrate an app from Phoenix 1.5 to Phoenix 1.6, phoenixdiff.org is a nice tool. It reveals all the changes between different versions.
phoenixframework/esbuild
- builds and bundles JS and CSS files
- preconfigured in a Phoenix 1.6 app
- installation of the esbuild executable is done automatically as long as phoenixframework/esbuild is configured correctly
- for SCSS we need use either:
- CargoSense/dart_sass
- esbuild plugins
- typically in development, we use 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 configuration
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
- watcher-specific settings for development
For example, here is what we would do when we want to use flatpickr (javascript datetime picker).
install the library from NPM
cd my-phoenix-app
npm install --prefix assets --save flatpickr
import the library in JS
- Esbuild will find libraries from
node_modules
. - CSS can be imported to a JS file as well.
// some js file where we want to use flatpickr
// import js
import flatpickr from 'flatpickr'
// import css
import 'flatpickr/dist/flatpickr.css'
// do something with flatpickr
flatpickr(this.el, {})
It is a lot easier than I expected. But one is that by default exbuild does not know how to handle SCSS files.
CargoSense/dart_sass
- similar to phoenixframework/esbuild, but specially for SCSS
- Three files are involved for configuration just like phoenixframework/esbuild
mix.exs
config/config.exs
config/dev.exs
Initially I just copied and pasted all the snippets thoughtlessly and one issue occurred.
Because I use both phoenixframework/esbuild and CargoSense/dart_sass and they both output the CSS build result to the same file priv/static/assets/app.css
, which means they keep on overriding that same file.
After all, I ended up on this strategy.
- make
assets/scss
directory and put all the.scss
files in it - let CargoSense/dart_sass compile
assets/scss/index.scss
and outputassets/scss/index.css
- import
assets/scss/index.css
inassets/js/app.js
This way there will be no conflict between phoenixframework/esbuild and CargoSense/dart_sass. CargoSense/dart_sass is in the position of helping phoenixframework/esbuild with comiling SCSS, and once SCSS is converted to CSS, the rest of work is done by phoenixframework/esbuild.
Finally, my config/config.exs
looks like this.
# config/config.exs
...
# Configure esbuild (the version is required)
config :esbuild,
version: "0.14.1",
default: [
args: [
"js/app.js",
"--bundle",
"--target=es2016",
"--outdir=../priv/static/assets",
"--external:/fonts/*",
"--external:/images/*"
],
cd: Path.expand("../assets", __DIR__),
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]
# https://github.com/CargoSense/dart_sass
config :dart_sass,
version: "1.44.0",
default: [
args: ["scss/index.scss", "scss/index.css"],
cd: Path.expand("../assets", __DIR__)
]
...
And I add the intermediate assets/scss/index.css
file in .gitignore
# Ignore assets that are produced by build tools.
/priv/static/assets/
/assets/scss/*.css
:tada::tada::tada: