arcanemachine

arcanemachine

Tailwind CSS RISC-V Node Wrapper - a Linux RISC-V compatible Tailwind CSS v4 CLI distribution

I (with the help of an LLM-based agent) put together a Node-backed Tailwind CSS v4.3.1 wrapper for Linux RISC-V GNU systems:

This repo offers a prebuilt binary and a simple tailwindcss CLI wrapper. The binary is reproducible using a simple Docker-based workflow.

This came out of trying to run a Phoenix app on a Scaleway RISC-V server running Ubuntu 24.04. Phoenix’s tailwind package could not download an official Tailwind binary for riscv64-unknown-linux-gnu, and Tailwind’s official standalone binary path depends on Bun. Bun does not currently provide a Linux RISC-V target, so the official single-file Tailwind standalone binary is not available there.

DISCLAIMER: I built this to scratch an itch for a weekend project, and have only run this in a :dev config environment. Everything appears to work, but this is presented as an experimental proof-of-concept, and nothing more. I just thought it was cool and wanted to share it.


This package is not Tailwind’s official standalone binary. It is a self-contained tarball distribution with:

  • A wrapper (bin/tailwindcss) that provides a compatible interface for the :tailwind Mix package.
  • bundled Node
  • pinned @tailwindcss/cli / tailwindcss
  • the Linux RISC-V native addons needed by the Node CLI

It does not need npm at runtime, and it does not require app-local Tailwind node_modules. It does need the extracted package directory to remain intact, because bin/tailwindcss is a wrapper around the bundled runtime.

For Phoenix, the important part is to point the Elixir Tailwind config at the wrapper and disable the version check.

config/config.exs

  config :tailwind,
    version: "4.3.1",
+   path: "/path/to/tailwindcss-riscv64-linux-gnu-v4.3.1/bin/tailwindcss",
+   version_check: false,
    hello_phoenix: [
      args: ~w(
        --input=assets/css/app.css
        --output=priv/static/assets/css/app.css
      ),
      cd: Path.expand("..", __DIR__),
      env: %{"NODE_PATH" => [Path.expand("../deps", __DIR__), Mix.Project.build_path()]}
   ]

Also remove tailwind.install --if-missing, because the Elixir Tailwind downloader does not provide a Linux RISC-V binary.

mix.exs

defp aliases do
  [
-   "assets.setup": ["tailwind.install --if-missing", "esbuild.install --if-missing"],
+   "assets.setup": ["esbuild.install --if-missing"],
    "assets.build": ["compile", "tailwind hello_phoenix", "esbuild hello_phoenix"],
    "assets.deploy": [
      "tailwind hello_phoenix --minify",
      "esbuild hello_phoenix --minify",
      "phx.digest"
    ]
  ]
end

I built and verified this on Ubuntu 24.04 LTS on a Scaleway RISC-V server. Phoenix asset build/deploy worked, and the rendered page was styled correctly in the browser, and works correctly with Phoenix’s built-in hot reload feature.

The long-term upstream fix is still Bun support for Linux RISC-V, or a different official Tailwind standalone build path that does not depend on Bun. Until then, this gives Phoenix apps a technically-usable Tailwind v4 path on Linux RISC-V.

Most Liked

olivermt

olivermt

Hi,

You could also pr risc support (if zig needs it?) into BeaconCMS’s compiler.

Once Brian merges my pr ( Add streaming candidate extraction by olivermt · Pull Request #2 · BeaconCMS/tailwind_compiler · GitHub ) then you should have all of tailwind in a box without needing node.

Where Next?

Popular in Announcing Top

zorbash
I created Kitto a framework for dashboards inspired by Dashing. The distributed characteristics of Elixir and the low memory footprint...
New
mischov
import Meeseeks.CSS html = HTTPoison.get!("https://news.ycombinator.com/").body for story <- Meeseeks.all(html, css("tr.athing")) do...
New
Azolo
Hey everyone, I just released WebSockex which is a Elixir WebSocket client. WebSockex strives to work as a OTP special process, be RFC6...
New
tmbb
PhoenixWS - Websockets over Phoenix Channels Source code on Github here: GitHub - tmbb/phoenix_ws: Websockets implemented over Phoenix Ch...
New
kevinlang
Hey all, We have made an Ecto3 Adapter for SQLite3, ecto_sqlite3! We have successfully on-boarded the full suite of integration tests (...
New
trisolaran
Hi! :waving_hand: I would like to present LiveSelect, a little library that I wrote to easily add a dynamic selection input to your LV f...
198 11220 107
New
type1fool
WebAuthnLiveComponent WebAuthnComponents See this post about renaming the package. Passwordless authentication for Phoenix LiveView app...
New

Other popular topics Top

KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36654 110
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 44532 311
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

We're in Beta

About us Mission Statement