Plug static only loads public assets or nothing

Continuing the discussion from a few weeks ago Phoenix Plug static only delivers uncompiled assets but not any folder inside priv/static/assets:

I’m still on this unwanted behavior. My Plug.Static is delivering all my assets from my public assets directory instead of the ones on the priv.
If I use

 plug Plug.Static,
  at: "/",
  from: :testespay,
  gzip: false,
  only: ~w(css fonts images js favicon.ico robots.txt)

just my images folder from priv/static are loades, now if I put

a
only: ~w(css fonts assets images js favicon.ico robots.txt)
a

I can get my digested files under priv/static, but my uncompilled files too


What is weird because the doc says only assets from priv/static should be delivered
I already tried to put my css and js files only under /priv/static, priv/static/js, priv/static/css, even under priv/static/assets/css(or js). The only way I can get it working it putting assets folder under plug, and pushing my undigested files as well. I decided to link my previous post about this with the LostKobrakai explanation about Plug.Static that I didn’t understand very well or how to solve my issue itself, since I just want to get the base assets of my application

I think I understand your confusion (I used to be confused by this too).

TL;DR, assets/ is for files you want to be processed. They are compiled/transpiled/whatever and saved into priv/static/. Out of the box, this is configured for just CSS and JS. If you take a look at your .gitignore file you’ll see that /priv/static/assets is added by phx_new. Otherwise, anything you put in priv/static/ is going to be delivered as is.

It may help to know:

assets/ is a Phoenix-specific directory. It only exists in development.

priv/ is a special directory (like lib/) that is part of an OTP release (I’m sorry but I’m having a hard time finding the docs for it). Its for “files your project needs that aren’t BEAM bytecode” (there are also other ways to do this, like how co-located heex works). Its name is a bit unfortunate but as I understand it, it made more sense a couple of decades ago before its usage expanded.

Apologies if this was not what you were looking for.

2 Likes

As mentionned by @sodapopcan assets is the source code, it needs to be bundle into a javascript file.

You have many bundlers available, and by default it is esbuild. You have many alternative, like vite, bun, rsbuild, webpack…

They all take an entry point, usually assets/js/app.js, or index.js

But You are using typescript, with something that looks like react code, You can compile your ts files with the TS compiler, and output the result into priv/static. Anyway You need to transform your ts into js, otherwise it won’t work.

You should also bundle your stylesheets, maybe with postcss

2 Likes

Images don’t need to be bundled, so it’s better if You move your assets/images folder to priv/static.

unless You want to inline them…

Yes that is what i’m doing in

# Configure esbuild (the version is required)
config :esbuild,
  version: "0.17.11",
  testespay: [
    args:
    ~w(js/app.js js/home.ts --bundle --target=es2020 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*),
    cd: Path.expand("../assets", __DIR__),
    env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
  ]

# Configure tailwind (the version is required)
config :tailwind,
  version: "3.4.3",
  testespay: [
    args: ~w(
      --config=tailwind.config.js
      --input=css/app.css
      --output=../priv/static/assets/app.css
      --input=css/home.css
       --output=../priv/static/assets/home.css
    ),
    cd: Path.expand("../assets", __DIR__)
  ]

but from my understanding, the plug would only deliver my bundled files, not the source of them together

Hm, the first part of you answes it is what I understood as well: I need to compile my source files to priv/static, and i’m at the moment doing exactly that. In fact, (maybe I didnt point this on my post) my compiled file in priv/static/assets is being correctly delivered. Maybe i’m seeing the source TS files from the default /assets folder bcs i’m not running as a OTP release?

Oh ya ok, I understand more now reading it a little closer.

Take a look in root.html.heex (assuming you haven’t changed it). You should see these lines:

<link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
<script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}>

You’ll notice these are verified routes (~p) and are linked to /assets. These are URLs which point to priv/static/ on the filesystem. Your priv/static/css and priv/static/js are there but you need to actually link them as well in your HTML:

<link phx-track-static rel="stylesheet" href={~p"/css/my-css-file.css"} />
<script defer phx-track-static type="text/javascript" src={~p"/css/my-js-file.js"}>

Keep in mind that nothing inside priv/ is getting bundled so you will need to add those lines for each css/js file you have inside priv.

1 Like

i’m not using reex and liveview, its this relevant for my case?

   <link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
    <link phx-track-static rel="stylesheet2" href={~p"/assets/home.css"} />
    <script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}>
    </script>
``` or 
` <link phx-track-static rel="stylesheet2" href={~p"/assets/css/home.css"} />`
sill doesnt deliver my assets unless I put /assets into plug static

I could fix it renaming assets to p_assets
renaming the configs to point to the correctly p_assets dir

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

but p_assets it’s still beind delivered ‘-’
so I renamed p_assets to /fuck_it
also continue to deliver everything

Could it be that those aren’t actually files served by the Plug, but instead just the browser showing what it learned from sourcemaps in development? That’s a feature to make debugging easier.

Did you actually try to HTTP GET such a typescript file, for example using curl?

My esbuild hasnt the sourcemap option, and if it was for development generating the realse with env=prod shoudlt disable it?
I try to add the flag --sourcemap=external and run, /assets continues delivered
So I tried do delete the sourcemap generated on the priv/static/js folder, again delivered
I tried to make cul to assets and got nil, so probably no

### Request info

  * URI: http://localhost:4000/assets/js/home.ts
  * Query string:

### Headers

  * accept: */*
  * host: localhost:4000
  * user-agent: curl/8.9.1

### Session

    nil
</textarea>
            <div class="code-snippets">

                  <div class="frame-info" data-index="0" role="stack-trace-details">
                    <div class="file">
                      <a href="">deps/phoenix/lib/phoenix/router.ex</a>
                    </div>

I tried * URI: http://localhost:4000/home.ts as well and got the same output

Now I could get it working, the sourcemap was being generated even without the --sourcemap flag on esbuild
a inline sourcemap it’s auto generated everytime I run mix phx.server with dev env (even with the external flag set up)
running with miv_env=prod does not generate the inline source map, which gives me the behavior i want

Fix: the ESBUILD was generating sourcemap even without the --sourcemap flag when mix_env=dev
I think the workflow problem was when I run mix phx.server as --dev, an inline sourcemap it’s auto generated on digested files
so when I ran mix_env=PROD without regenerating the assets, the file with the sourcemap generated was loaded

1 Like