mcrumm

mcrumm

Phoenix Core Team

If you would like to migrate away from node/npm/webpack while still using sass, the dart_sass package provides a installer and runner for Dart Sass via Mix.

This package follows the same structure esbuild– you add your configuration to config.exs:

config :dart_sass,
  version: "1.36.0",
  default: [
    args: ~w(css/app.scss ../priv/static/assets/app.css),
    cd: Path.expand("../assets", __DIR__)
  ]

and then you can run it from your command line:

$ mix sass default --version
1.36.0

For any Phoenix projects currently using Sass via webpack, you can use dart_sass to model your asset pipeline in the upcoming style of the Phoenix v1.6 installer.

First, add DartSass as a watcher in config/dev.exs:

sass: {
    DartSass,
    :install_and_run,
    [:default, ~w(--embed-source-map --source-map-urls=absolute --watch)]
  }

Note: this requires Phoenix > v1.5.9.

…and then create or add sass to your "assets.deploy" alias in mix.exs:

"assets.deploy": ["sass default --no-source-map --style=compressed", "phx.digest"]

You may refer to the README for more details, and if you are using dart_sass in a project, please let us know!

https://github.com/CargoSense/dart_sass

Showing Posts 36 to 27

mcrumm

mcrumm OP

Phoenix Core Team

v0.7.0 (2023-06-27)

This release should be fully compatible with Elixir v1.15+

  • Require Elixir v1.11+
  • Mark inets and ssl as optional apps
  • Ensure the install task only loads the runtime config with --runtime-config
tj0

tj0

PSA:

For those using SASS because of nesting and variables, esbuild might just be enough now. Using 0.17.18 atm.

By setting the target to be chrome58, it will rewrite the new css nesting rules to be functional on browsers that don’t support it. BEM won’t work anymore as the & operator no longer does a strict append in all cases. However, by using CSS variables, I got rid of SASS with a bit of rewriting.

The details

config.exs
config :esbuild,
  version: "0.17.18",
  default: [
    args: ~w(js/app.js --bundle --target=es2016,chrome58 --outdir=../priv/static/assets --external:*.woff2 --external:*.svg),
    cd: Path.expand("../assets", __DIR__),
    env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
  ]

app.js

App.js includes the css file for esbuild to generate and dump everything into priv/static/assets

import "../css/app.css"
mcrumm

mcrumm OP

Phoenix Core Team

v0.6.0 (2023-04-19)

Potentially breaking change: Due to a change in the upstream package structure, you must specify a :version >= 1.58.0 on Linux platforms.

  • Depend on inets and ssl by josevalim in #30
  • Updated Sass version to 1.61.0 by azizk in #31
  • Renames DartSass.bin_path/0 to DartSass.bin_paths/0.
  • Supports installation of newer upstream packages on Linux platforms. (h/t azizk)
  • Overriding :path disables version checking.
mcrumm

mcrumm OP

Phoenix Core Team

v0.5.1 (2022-08-26)

  • Update Sass version to 1.54.5
  • Skip platform check when given a custom path (h/t @jgelens)
  • Use only TLS 1.2 on OTP versions less than 25.
mcrumm

mcrumm OP

Phoenix Core Team

v0.5.0 (2022-04-28)

  • Support upstream arm64 binaries
  • Update Sass version to 1.49.11

A note about the Sass version
While there are newer releases of the dart-sass package available, v1.50.0+ currently has a broken --watch implementation and must not be used until it is fixed and a new version is released. Fortunately once that happens we should be able to remove the bash runner script from the Elixir package.

hxgdzyuyi

hxgdzyuyi

thanks !

hxgdzyuyi

hxgdzyuyi

Then I used it like this


  watchers: [
    # Start the esbuild watcher by calling Esbuild.install_and_run(:default, args)
    esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]},
    tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]},
    sass: {
      DartSass,
      :install_and_run,
      [:default, ~w(--embed-source-map --source-map-urls=absolute --watch)]
    }
  ]
mikeclark

mikeclark

Thanks!

The new bit for me is stepping outside the realm of PostCSS (which requires Node) to handle the nesting. For example, typically I’d have a postcss.config.js that puts postcss-nesting in the pipeline:

module.exports = {
  plugins: {
    "postcss-nesting": {},
    tailwindcss: {}
  }
}

But yeah, using DartSass and Tailwind as described is effectively doing the same thing, just without PostCSS (and therefore Node) in the mix. And that’s my primary reason for going this route. :grinning_face:

mcrumm

mcrumm OP

Phoenix Core Team

This looks great to me!

Honestly I am not sure there is much room for improvement on this pattern. It’s essentially what’s recommended by Tailwind when using a preprocessor, whatever the flavor: Using with Preprocessors - Tailwind CSS

mikeclark

mikeclark

First, this DartSass installer is awesome. Thank you, @mcrumm!

In terms of using standalone Tailwind and DartSass together, here’s something I’ve been experimenting with that might help…

In educational apps specifically, I often want to avoid using a lot of Tailwind utility classes in templates. To do that, I rely on Tailwind’s @apply directive. And when it’s a fairly significant amount of CSS, it’s often handy to use CSS nesting which is where DartSass comes in.

Here’s an example css/app.scss file that demonstrates the problem in an abbreviated form:

@tailwind base;
@tailwind components;
@tailwind utilities;

.card {
  @apply p-4 bg-blue-300 text-blue-800 rounded-lg;

  & .title {
    @apply text-2xl tracking-tight font-bold;
  }

  & .details {
    @apply pt-4 text-lg font-medium;

    & a {
      @apply underline;
    }
  }
}

Now if you run that file through the Tailwind CLI alone, it won’t flatten out the nesting. (The @tailwind/nesting package isn’t baked into the Tailwind CLI as far as I can tell).

However, you can first run that file through DartSass and then run the result through the Tailwind CLI. In other words, pipe the output of one into the other.

Here’s how I’ve been doing it:

First, setup the watchers in the right order:

  watchers: [
    dartsass: {DartSass, :install_and_run, [:default, ~w(--watch)]},
    tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]}
  ]

Then configure dart_sass to process app.scss and drop the result in an intermediate file named app.tailwind.css for example:

config :dart_sass,
  version: "1.49.0",
  default: [
    args: ~w(css/app.scss ../priv/static/assets/app.tailwind.css),
    cd: Path.expand("../assets", __DIR__)
  ]

Finally, configure tailwind to use the DartSass output file as its input and spit out the final output in app.css:

config :tailwind,
  version: "3.0.18",
  default: [
    args: ~w(
      --config=tailwind.config.js
      --input=../priv/static/assets/app.tailwind.css
      --output=../priv/static/assets/app.css
    ),
    cd: Path.expand("../assets", __DIR__)
  ]

I’ve only been experimenting with this for a couple days, so there are likely limitations I haven’t bumped into yet.

Is that the sort of thing you’re trying to do, @hxgdzyuyi?

I look forward to hearing of better ways to do this. :wink:

Where Next? Top

Trending in Announcing Top

woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New
MRdotB
I needed to reuse React components from my Chrome extension in my Phoenix/LiveView backend. I noticed that for Svelte/Vue, there are live...
New
woylie
I released Doggo, a collection of unstyled Phoenix components. https://github.com/woylie/doggo Features Unstyled Phoenix components....
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
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
anuaralfetahe
Hello Published a new library - ProcessHub! ProcessHub is a library designed to manage process distribution within the Elixir cluster. ...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New
AstonJ
This showed up on my feed.. anyone heard of it? Just hype? Ox Alpha is a reasoning model designed for coding, sustained ag...
New
bartblast
Hey folks, I just published a post about Hologram’s funding and where the project goes next - the short version: Curiosum as Main Spons...
New
CodeSync
:microphone: ElixirConf 2026 - Call for Talks is open! We’re heading to Chicago :united_states: :round_pushpin: In person + virtual :d...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews