Background-image in CSS not working in Phoenix 1.6

It’s in the esbuild doc…

https://esbuild.github.io/content-types/#external-file

Where is anything about making copies of images like phoenix-HEGEN2FR.png which esbuild is making after adding:

watchers: [
    # Start the esbuild watcher by calling Esbuild.install_and_run(:default, args)
    esbuild:
      {Esbuild, :install_and_run,
       [
         :default,
         ~w(--sourcemap=inline --watch --loader:.jpg=file --loader:.png=file --loader:.gif=file --loader:.svg=file)
       ]}
  ]

Also, there is NOT A SINGLE MENTION about the background-image problem in CSS files in the docs you linked.

Please, try it on your own with the clean install of Pheonix 1.6. I mentioned all the steps to reproduce this issue a few comments above.

Hmm, I don’t understand it. Could you explain further how to solve it with my problem? Thank you.

The problem was obviously a path problem…
You did not put the right path (relative to the css, as mentionned above by @kip)

And then, You did not use the appropriate loader.

Now You know how to do it properly.

Again, my problems are that:

This “loader”, whatever it is (a program, method, whatever…) of esbuild creates another copy of my existing image phoenix.png that is already here: /priv/static/images/phoenix.png. /images is a place I want to have all images that are design related - and I suppose that is standard in webdev world.

The copy is being put here: /priv/static/assets/phoenix-HEGEN2FR.png.

The suffix is probably some mechanism to prevent duplicates or something, I don’t know esbuild at all.

But I don’t want to have what I have now, which is this:

/priv
  /static
    /assets
      app.css
      app.js
      phoenix-HEGEN2FR.png   <-- I DO NOT WANT THIS HERE
    /images
      phoenix.png
    favicon.ico
    robots.txt

I want to have:

/priv
  /static
    /assets
      app.css
      app.js
    /images
      phoenix.png  <-- I WANT ONLY THIS
    favicon.ico
    robots.txt

Any idea how to do this?

How to disable the creation of duplicit files by esbuild?

I am completely stuck.

All I wanted was to show an image via background-image on my html element.

And I ended up debugging my app and trying to search through the esbuild go source code.

Please, could somebody try to install a vanilla fresh Phoenix 1.6 install and try to use background-image in the phoenix.css or app.css file (using e.g. the included Phoenix logo image in priv/static/images/phoeinx.png) without creating an additional duplicate image in priv/static/assets as I have described in more details in my previous post?

Thank you in advance.

i’ve created a fresh install in 1.6 on mac and i get the same problem

[watch] build started (change: "css/phoenix.css")
 > css/phoenix.css:41:24: error: Could not resolve "../images/phoenix.png"
    41 │   background-image: url("../images/phoenix.png");

I’ve other project where i’m experimenting with talwind and alpine and it works
maybe trying to add them to your project and remove after.
Don’t know, i’m new to this.
i’ve followed this Adding Tailwind CSS to Phoenix 1.6

1 Like

Thanks, finally somebody who can reproduce this problem on his machine. I thought I was crazy.

Perhaps the devs who are more intimate with Phoenix development will notice this post and will be able to help.

When you are serving assets to a website, they should get bundled first - this will take the raw files and output them to a separate file/directory, where they are then delivered to the client efficiently. This is what esbuild is for - it is a bundler. You can control the output directory in config.exs:

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

Notice --outdir=../priv/static/assets

I have already images in my static folder. Again, I don’t want to duplicate my images.

Now I have dupllicates (pheonix.png and phoenix-HEGEN2FR.png are duplicates of the same file):

/priv
  /static
    /assets
      app.css
      app.js
      phoenix-HEGEN2FR.png   <-- I DO NOT WANT THIS HERE
    /images
      phoenix.png
    favicon.ico
    robots.txt

I want to have:

/priv
  /static
    /assets
      app.css
      app.js
    /images
      phoenix.png  <-- I WANT ONLY THIS
    favicon.ico
    robots.txt

/priv/static is an output dir, not a source dir. likewise, it is in the .gitignore file. You images should live in /assets/static/images/, and something in your build pipeline should copy them into /priv/static/images/

Your css should looks like /assets/css/app.css. So it should reference the images with relative dir like ../static/images/bluh.jpg

During the build process the images will be copied, the css will be built, and part of the building is to fix up the file reference to point to the final dir.

Then why is the default phoenix.png - distributed by the phoenix team image in /priv/static/images/phoenix.png and not in /assets/static/images/phoenix.png as you are suggesting?

Check for yourself if you don’t believe me. Install the Phoenix 1.6 and check the folder and files structure.

That used to be the case pre 1.6. In 1.6 only priv/static/assets are ignored and static assets are indeed meant to go into priv/static directly.

2 Likes

Any idea how to make esbuild stop making copies of the already-existing images in priv/static/images ? Is there any option to ignore budling of images and just leaving them as they are, that is, allowing to linking to them in CSS in background-image with the old way as in Phoenix 1.5?

Haven’t try 1.6 dir structure so I can judge whether I like it or not. One can always use the old dir structure if the new one don’t work out.

We have been looking at it. Just a quick note – I understand that you are currently frustrated that something is causing you problems, but your tone to multiple people trying to help you out is off-putting. It it difficult to find motivation to approach this issue after reading the thread :frowning_face: Please keep that in mind when asking for help and replying to others providing help.

That said, we have a solution that will fit your use case. Before we get there, one other note, for you and future readers: generally the reason that assets like images get duplicated is for the purpose of cache busting, as in the process by which we can tell client browsers to cache assets that rarely change for long periods of time and still allow those assets to be refreshed in a timely manner when they may change. Usually this is done by appending a hash of the file contents to the filename. This necessarily creates (at least) a duplication of your cached-busted (i.e. digested) assets.

So the behaviour you are seeing is esbuild trying to help you out by cache-busting your assets. However it sounds like you may not want that, so here is how you disable it in esbuild.

In your config/config.exs, find the esbuild configuration. It should look something like this:

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

append the external option to the list of args, so it looks like this:

args:
      ~w(js/app.js --bundle --target=es2016 --outdir=../priv/static/assets --external:/images/*)

Now, when you reference your image paths in css, do so with absolute paths just like you would in the browser:

background-image: url("/images/phoenix.png");

and that’s it.

Now let’s say you do want cache-busting. Phoenix has you covered. Run mix assets.deploy, which is an alias in the generated mix.exs from the Phoenix installer. It runs the phx.digest command which will handle cache-busting for all of your assets in priv/static. To remove the digested assets, you can run mix phx.digest.clean --all.

Let us know how it goes!

12 Likes

Wow, thanks. Exactly what I wanted. This --external:/images/* option was all it needed. And as a side bonus I don’t need to now have --loader:.jpg=file --loader:.png=file --loader:.gif=file --loader:.svg=file in dev.exs. At least it works after I removed it, saved and restarted the server.

So, thanks again.

About my behavior, if you look at the answer from people except you, of course, and the one guy who reproduced my problem, all of them were suggesting me to learn esbuild or look into docs but if I asked them if they can be a little bit more specific they didn’t respond or they just told me that the question has already been answered and generally not very helpful things. And I think we all know that no one of them knew about the elegant --external:/images/* solution of yours which would also eliminate the weird ../../priv/static/images/blue.png path in the url() in the CSS file and it also removed the necessity of those --loaders options in dev.exs.

Anyways, thanks for your help.

My guess is this could be somehow explained further in the official Phoenix docs, because I really don’t think I will be the only one who will be very surprised that images in background-image don’t work.

I can only speak for myself, but linking to docs/resouces is usually done quite a bit quicker than providing actual specifics. The github link I provided did use the --external flag, but I didn’t have the time nor project at hand to actually try the flag out to provide a working solution directly.

I think as well, that this should be the default. Cache busting is already provided through mix phx.digest.

1 Like

But did you tell them you read all the docs and learned esbuild? Esbuild is quite new so not many people (at this forum) will have in depth experience. So all they can do is point in a direction. It’s up to you to go have a look and report if/when found an answer.

And in my experience: you will never lose even when you can’t find the answer in docs. Cause even then you have learned a lot by looking though them (so you learned a bit about esbuild) which will improve your broader knowledge.

There is a saying about a man and a fish. Don’t exactly know how it goes; but here you have a direction :slight_smile:

2 Likes

Dude I didn’t even know that flag existed until we started looking into this. So as much as it might not be what you wanted to hear, “check out the esbuild docs” ended up being the correct solution. :slight_smile:

I agree, and I have opened a PR :slight_smile: Add external flag to esbuild for fonts and images by mcrumm · Pull Request #4536 · phoenixframework/phoenix · GitHub

Please try to remember that we are all people, and for the most part all of the work happening here is volunteerism. Sometimes we miss stuff. Sometimes we find better solutions later. It’s all iterative. Have a good one!

8 Likes