Koszal

Koszal

Browsers tricked to use an outdated app.css

I encountered a weird bug(?) with Plug.Static(?) where browsers sometimes are tricked to use an outdated app.css file. I first noticed this a couple of months ago while experimenting with Phoenix and Tailwind CSS for a CSS animation effect. I’m not really a web guy, it was my first encounter with Tailwind and I found this extremely confusing. The animation worked inconsistently, and I eventually realized it depended on specific CSS classes I used. Some classes were missing from the app.css file loaded by the browser, if I happened to use one, the animation would not work.

To debug, I used a JavaScript function to scan the DOM and identify undefined CSS classes. After much trial and error, I resolved the issue (mix digest.clean (?)) and eventually forgot about it until it resurfaced yesterday. I was tweaking styles with an AI agent. It fixed most things but some elements still displayed incorrectly. The problem was - again - missing classes. The agent tried whitelisting Tailwind classes, modifying App.Endpoint, etc.—the problem persisted.

Here is what I found:

  • Tailwind correctly generates app.css.
  • Fetching the file via curl or wget returns the fresh, correct version.
  • In the browser, requests contain etag headers, the response from the server is 304 - not modified.

Hard reloads, recompiling, restarting the app, switching browsers does not solve the issue.

This happened on 1.7 but on that day I tried upgrading to 1.8 (in a separate branch) - not sure if that is related. I would appreciate some guidance on how to troubleshoot it and/or confirm the problem.

First Post!

pupdogg

pupdogg

I’ve used this trick with Ruby on Rails assets in the past, but I’m not sure if it will work in your situation. Could you try appending an epoch timestamp to your stylesheet tag in root.html.heex so that it looks like this:

<link phx-track-static rel="stylesheet" href={"#{~p"/assets/css/app.css"}?v=#{System.system_time(:second)}"} />

Last Post!

arcanemachine

arcanemachine

For Tailwind v3, you would add a safelist to ensure such classes were generated:

assets/tailwind.config.js

module.exports = {
  content: ["./js/**/*.js", "../lib/*_web.ex", "../lib/*_web/**/*.*ex"],
  // ...
  safelist: [
    {
      pattern:
        /(alert|bg|btn)-(primary|secondary|info|success|warning|error)/,
    },
    {
      pattern:
        /text-(primary|secondary|info|success|warning|error)-content/,
    },
  ],
  // ...
}

Source: Content Configuration - Tailwind CSS

For Tailwind v4, it looks like this:

assets/css/app.css

@import "tailwindcss" source(none);
@source "../css";
@source "../js";
@source "../../lib/your_project_web/";

/* Other stuff skipped... /*

/* Safelist - Ensure that these Tailwind classes are always generated */
@source inline('{alert,bg,btn}-{primary,secondary,info,success,warning,error}');
@source inline('text-{primary,secondary,info,success,warning,error}-content');

Source: Detecting classes in source files - Core concepts - Tailwind CSS

Where Next?

Popular in Questions Top

RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
Lily
In templates/appointment/index.html.eex: &lt;%= for appointment &lt;- @appointments do %&gt; &lt;tr&gt; &lt;td&gt;&lt;%= appoi...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New

Other popular topics Top

grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 54006 488
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New

We're in Beta

About us Mission Statement