Official, up-to-date boilerplate for `tailwind` and `esbuild`?

Hi there,

I am trying to migrate a mid-size project from Phoenix 1.5.13 to 1.6.6. The Phoenix/LiveView part went smoothly, but after two days I can’t get my asset pipeline to work:

  • tailwind and esbuild seem to cancel one another: I can have the “tailwind CSS” working or the “esbuild CSS” working, but not both ;

  • It seems I can’t import external CSS files (font-awesome, flatpickr, etc.) from a CSS file managed by tailwind ;

  • Also, a lot of other assets (images, etc.) are not compiled anymore.

So I have a few questions for the community:

  • Should I remove import css from "../css/app.css"; from my app.js? (some answers say yes, others say no)

  • Why do I have to move my static assets from assets/static to priv/static?

  • In what dir should I put my external CSS? Do the import from app.css still work?

  • In config.exs, should esbuild default --minify come first, or tailwind default --minify? If it doesn’t matter because there are two separate pipelines, does it even mean I have two different CSS files to import (one from priv/static/assets, the other from priv/static/css?

  • Do I have to keep npm/yarn to manage my JS dependencies?

  • Do I need to keep using postcss?

  • In app.css, should I use the @import "tailwindcss/base"; syntax, or the @tailwind base; one?

I have been navigating issues, PR and elixirforum answers for a while, so any help on any of the above questions would be greatly appreciated :slight_smile:

Your tailwind config should look something like this:

config :tailwind,
  version: "3.0.10",
  default: [
    args: ~w(
    cd: Path.expand("../assets", __DIR__)

As you can see app.css is already referenced there so no need to have it in app.js.

Webpack conf has one approach, esbuild has another, but really it’s up to you to configure. The new consensus seems to be (logically thinking) that files that don’t get transformed anyway have no reason to start in one place and end in another. And static files are the ones that aren’t compiled or anything.

If you want to import CSS files you should have them in assets/css/, but i haven’t yet had to import them so ot going to assume i know how to import.

I usually put tailwind first, but I’m not sure if it makes a difference.

if you have dependencies in package.json, then yes you need all of node.js still. i try to avoid it, but Alpine.JS for example requires it.

I don’t seem to have it installed. I’m using Tailwind.

The ‘official’ Tailwind integration uses @import "tailwindcss/base";

The fastest way to get a Tailwind LiveView project up and most ‘official’ way is

mix local.hex
mix archive.install hex phx_new
mix app_name --live --binary-id
mix phx.gen.auth Accounts User users

That repo is semi-automated and I suggest you go through the steps with a new project, commit every step. This way you’ll understand better what is the current accepted standard and how things work.

I included the auth stuff just because it’s a common need and can be part of the boilerplate.

Disclaimer: I’m still a noob with bad memory. Especially the npm part I’m not fully sure of, even though I have projects with and without package.json.


Hey @KristerV, thank you so much for this detailed answer! It fixed 90% of my issues :slight_smile:

I keep having two problems though:

  • None of my external CSS files are loaded, I need to manually load them through <link rel="stylesheet" href={Routes.static_path(@conn, "/css/font_awesome.css")} /> and others (which is ok, but feels slightly unclean - there must be a better way, right?)
  • I get a lot of compiled files in priv/static, even with --outdir=../priv/static/assets. This clutters my git repo a lot (since only priv/static/assets is ignored and not the whole priv/static): I end up versioning .gz files of all my assets…

The weird thing is that I checked and it doesn’t load phoenix.css :confused:

There is a good reason for using Routes. static_path which I’ve touched on previously here Loading images and assets in phoenix 1.6.2 - #8 by 03juan.

Have a look at the rest of that thread to see if anything else there can help with your issues.

Using Routes is indeed a great idea. If I understood correctly you don’t like having that string as the second argument and I don’t like it either. I guess one way of solving this would be to add multiple CSS files to the tailwind conf.

Not sure how to @import though. Let me know if you find out :slight_smile:

In this case you need to be more specific either with showing us what files are generated there or showing us your configurations in terms of generated outputs.

My guess would be that you’re still using the old system, where more files were moved. Check your conf that you only move the app.js (esbuild) and app.css (tailwind) files.

1 Like

Hi @03juan, thanks for your response.

My question wasn’t specifically about Routes.static_path vs a hardcoded path, but rather about the fact that I needed several <link ...> for loading my CSS instead of importing a bundled app.css once and for all :slight_smile:

Oh right, my bad, sorry I can’t help. I’m using dart_sass for bulma so it’s conveniently bundling all my vanilla css too.

@KristerV thanks again.

I was hoping to get a single CSS file to link, but that may be too much to ask with such a complex system. Honestly having to link two files doesn’t matter that much!

The compiled files are the .gz ones generated by mix phx.digest. But I just need to phx.digest.clean --all before git add ., so problem solved I guess ^^