Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

public directory css url #9937

Open
keonik opened this issue Oct 28, 2020 · 77 comments
Open

public directory css url #9937

keonik opened this issue Oct 28, 2020 · 77 comments

Comments

@keonik
Copy link

keonik commented Oct 28, 2020

Describe the bug

When trying to import a image using the url method in a css/sass file the path no longer resolves to include the public directory using the prefix /

Did you try recovering your dependencies?

Yes

Which terms did you search for in User Guide?

Environment

  current version of create-react-app: 4.0.0
  running from /Users/jfay/.npm/_npx/12069/lib/node_modules/create-react-app

  System:
    OS: macOS 10.15.7
    CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
  Binaries:
    Node: 12.18.3 - /usr/local/bin/node
    Yarn: 1.21.1 - /usr/local/bin/yarn
    npm: 6.14.6 - /usr/local/bin/npm
  Browsers:
    Chrome: 86.0.4240.75
    Edge: Not Found
    Firefox: 80.0
    Safari: 14.0
  npmPackages:
    react: ^17.0.1 => 17.0.1 
    react-dom: ^17.0.1 => 17.0.1 
    react-scripts: ^4.0.0 => 4.0.0 
  npmGlobalPackages:
    create-react-app: Not Found

Steps to reproduce

  1. Start with a generic cra w/ react-scripts@4.0.0
  2. Open App.css
  3. Set the background to use an image resolved to the public url
.App {
  text-align: center;
  background-image: url("/logo192.png");
}

Expected behavior

Prior to upgrading to react-scripts@latest version 3.4.3 resolved images referenced in css files to include the public directory.

Actual behavior

Screen Shot 2020-10-28 at 12 33 07 PM

@GersonDias
Copy link

GersonDias commented Oct 28, 2020

I was about to make report the same issue. Though I'm trying to update from 3.4.3 to 4.0

@keonik keonik changed the title public directory css url bug public directory css url Oct 28, 2020
@thomasleduc
Copy link

thomasleduc commented Oct 31, 2020

Same here with scss module.
I'm trying to upgrade from 3.4.3 to 4.0

I think I found a related commit by @atlanteh here:
fa648da

  • Support scss absolute path resolution for url()

Adding resolve-url-loader broke all apps using scss with centralized assets folder and all url(./assets/.png) broke (#7023).
This change allows apps to use url(/assets/
.png) and it would map to src/assets/*.png

Does this means that now / refers to the src folder instead of public ? So the size limit to inline image in data url would become irrelevant 🤔 (because, correct me if I'm wrong but I don't think we should serve src)

And what about fonts and other references of file in css ? 🤔

@atlanteh
Copy link
Contributor

atlanteh commented Nov 1, 2020

@thomasleduc No.
My commit fixes an issue I had when using cra with sass after upgrading to cra 3.4.x (don't remember now which version) which caused the exact issue you are describing. The commit causes the loader to correctly load the files during build time from the src folder and copy them to the Public folder.
This is very weird. Can you try reverting my commit locally on your machine and see if that's the culprit?
If this is in fact the one, then it's worth checking with sass as well and if it works there as well then I guess cra made another fix someplace else and these fixes contradict each other

@thomasleduc
Copy link

thomasleduc commented Nov 1, 2020

I use sass module too and this is definitely not working.

I'm glad to do some very little work for create react app, but really the repo needs a proper doc to contribue 😅 I was struggling because yarn pack generate a different .tgz than the one build during the install phase. (react-scripts-v4.0.0.tgz instead of react-scripts-4.0.0.tgz without "v")

So I reverted your commit and I had a different error but it is still here.

With the revert of your commit it has the absolute url /logo192.png :
image

Without the revert, it has the relative url ../../../../logo192.png.

But I confirm, the error remains present in any case. Thanks for your answer @atlanteh but do you have any clues on how to fix it, it seems you have a good understanding of the resolve-url-loader 😅. I want to give a try to fix the issue because we really needs it to work on our project.

I currently investigate this commit 1cbc6f7 from multiple authors that I can't just revert. But there are many changes on from where the file are loaded.

@kidwm
Copy link

kidwm commented Nov 3, 2020

#9833 may be the same bug

@atlanteh
Copy link
Contributor

atlanteh commented Nov 4, 2020

I just upgraded my project to use cra@4.0.0 and it still works.
Are you guys sure you deleted the entire node_modules and reinstalled? Maybe we use things differently?
My project setup is as follows:

  • In my package.json I have "node-sass-chokidar": "1.3.4",
  • I have src/index.scss file which imports styles from styles directory + ../node_modules/... directories
  • in index.js I import this file import './index.scss';
  • I have src/images folder with all kind of images in there
  • In scss files I'm using these images as follows: background: url(/images/login-bg.png) center/cover no-repeat;

This works for me both in development and in production

Upon reading the issue more thoroughly, I think that the issue is that you are referencing images from public directory, which I guess my commit doesn't allow anymore. Actually I think the new solution is better

  • Have all your images inside src/images
  • reference them in the scss files using /images/*.png
  • only the images actually used will be copied to the build /media folder rather than the entire public directory

Can you please check if this solution work for you?

@mgonyan
Copy link

mgonyan commented Nov 4, 2020

@atlanteh I was facing the same issue described by others above, and as you suggested, moving the assets files used by *.scss files from /public/* to src/* fixes the issue (I've migrated from react-scripts@3.4.x to 4.0.0).
example:

  .header-bg {
    background-image: url('/assets/images/home-bg-black.png');
  }

This does not work:

public/
   assets/
      images/
         home-bg-black.png

After moving the files to /src:

src/
    assets/
       images/
          home-bg-black.png

Thanks!
cc @thomasleduc

@GersonDias
Copy link

GersonDias commented Nov 4, 2020

for me only works after I use relative paths to my images folder (that I moved from public folder). maybe something wrong with my tsconfig?

  "compilerOptions": {
    "outDir": "build/dist",
    "module": "esnext",
    "target": "ES2015",
    "downlevelIteration": true,
    "lib": [
      "es6",
      "dom",
      "es2018"
    ],
    "sourceMap": true,
    "allowJs": true,
    "jsx": "react",
    "noFallthroughCasesInSwitch": true,
    "moduleResolution": "node",
    "rootDir": "src",
    "forceConsistentCasingInFileNames": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": false,
    "strictNullChecks": false,
    "suppressImplicitAnyIndexErrors": true,
    "noUnusedLocals": false,
    "allowSyntheticDefaultImports": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "strict": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "experimentalDecorators": true,
    "baseUrl": "src"
  },
  "include": [
    "src"
  ]
}

also I needed to include the noFallthoughtCasesInSwitch: true and changed the key the jsx from preserve to react

@keonik
Copy link
Author

keonik commented Nov 4, 2020

@mgonyan if the fix is to move all assets into the src folder that could be as simple as updating the docs to list that as a breaking change. Also updating the docs here

@thomasleduc
Copy link

if the fix is to move all assets into the src folder that could be as simple as updating the docs to list that as a breaking change. Also updating the docs here

Maybe change the template as well to add some image in src/assets/images

also I needed to include the noFallthoughtCasesInSwitch: true and changed the key the jsx from preserve to react

This is already fixed on master. I'm afraid we have to wait for the next release. ¯_(ツ)_/¯
Does someone knows how to refer to master or an unpublished work on react-scripts ?

Anyway, Thanks a lot for your time @atlanteh. It is greatly appreciated 👍

@makis-spy
Copy link

I thought I was going crazy. 5 mins to get the app running 2 hours of googling to fix this issue :/

Also moving images inside source is not a solution if you want common inline and sass referenced images without duplicating them

@atlanteh
Copy link
Contributor

@makis-spy
First of all, I'm very sorry that you had to go to all this trouble. I guess it's on me. I always used the images in the src and things stopped working for me (and others) when trying to update to 3.4, so I found that solution and made a PR.
Regarding your concern, can you please elaborate on that?
What do you mean by "common inline images"?
If the images are small enough, then they will be inlined for you automatically.
I'm not sure I understand what difference changing the folder makes..

@makis-spy
Copy link

makis-spy commented Nov 13, 2020

@atlanteh oh no worries mate!

Maybe you can shed some light. So I have a public/img folder and a src/img folder

< img src="/img/me.png" /> calls public/img

.avatar {
background:url(//img/me.png) calls src/img
}

Do I need 2 images of me ?

What I am finding works for anyone needing a quick fix is keeping 2 sets of images (ducks a tomato)

One in public for after rendering

One in source just to bypass the file not found by loader

@atlanteh
Copy link
Contributor

I think your < img src="/img/me.png" /> is wrong.
You need to do it this way:

import MyImage from 'src/img/me.png';
...
function MyAvatar() {
  return (<img src={MyImage} />)
}

@thomasleduc
Copy link

thomasleduc commented Nov 18, 2020

@atlanteh If I use an image very often, say a logo that I put everywhere. It seems to me that inline this logo is not the solution even if it's small.

Say I use it 50 times in page, if I fetch the image, it would be cached in browser and reused across the all page.
If instead I inline it, my html bundle would be very huge.
I don't know if gzip would do the work on the bundle since there is a repetition; But it looks not good to me.

I think the developer should have the choice to make a http call or inline the image. don't you think ?

Again, it is not your fault, and I'm glad you're here to help :)

@atlanteh
Copy link
Contributor

atlanteh commented Nov 18, 2020

@thomasleduc If you import this image in a Logo component and use that component everywhere, I think everything should be ok. Since this image is only imported once, and only the Logo reference is being used everywhere, so the bundle should not be affected by the times the Logo is used.
If that's not an option, you can always disable image inlining by setting env IMAGE_INLINE_SIZE_LIMIT=0:

https://create-react-app.dev/docs/adding-images-fonts-and-files/

To reduce the number of requests to the server, importing images that are less than 10,000 bytes returns a data URI instead of a path. This applies to the following file extensions: bmp, gif, jpg, jpeg, and png. SVG files are excluded due to #1153. You can control the 10,000 byte threshold by setting the IMAGE_INLINE_SIZE_LIMIT environment variable as documented in our advanced configuration.

@thomasleduc
Copy link

thomasleduc commented Nov 23, 2020

Ohh ok, I didn't think it this way.
Thanks a lot for all your answers and for your work @atlanteh 🙏

@stale
Copy link

stale bot commented Dec 25, 2020

This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in 5 days if no further activity occurs.

@stale stale bot added the stale label Dec 25, 2020
@sagar7993
Copy link

sagar7993 commented Jan 8, 2021

I'm surprised that more people haven't realised that this is a major concern for SEO.

Lets say that you have a image file within the src folder, and you're using it within your CSS file like this -

.Profile {
text-align: center;
background-image: url("../../images/user/profile.png");
}

If this profile.png file is inside the src > images > user directory, then while creating a build with react-scripts, the URL generated for this file will be something like this -

https://{my-domain.com}/static/media/profile.{hash}.jpg

This {hash} value changes with every build. Therefore, if you use this in a static website, and if your website is crawled by google bot, you may see 404's reported in the google search console the next time you deploy, because Google can take several weeks before indexing your site again.

This is where an image in the public folder would have helped, because that URL will never change, and can safely remain indexed in search engines.

@stale stale bot removed the stale label Jan 8, 2021
@hershkoy
Copy link

hershkoy commented Jan 9, 2021

@jsdev-mario
Copy link

same issue

@itsmatin
Copy link

Been dealing with the same issue for couple of hours now. Uninstalling and reinstalling node_modules didn't do much...

@petro-shkuratenyuk
Copy link

Almost one year. issue isn't fixed yet...

@Morkowski
Copy link

Morkowski commented Oct 13, 2021

I'm using craco to modify my webpack config. I created @images alias for public/images folder and then in my scss code i'm using this syntax:
background-image: url(~@images/rainbow.svg);

Only this one solution worked for me, but it creates hashes for imported files so it is not ideal resolution for problems mentioned above.

@embermann
Copy link

Same problem.
I have all fonts and images in public directory, and until react-scripts 4.x.x all worked well.
I used these fonts and photos in scss files:

background-image: url(/assets/images/#{$name}.svg);
url(/assets/fonts/fontName.ttf) format('truetype'),
url(/assets/fonts/fontName.woff) format('woff'),
url(/assets/fonts/fontName.svg#fontName) format('svg');

I also tried to create assets folder in src, but getting same error:

./src/index.css
Error: Can't resolve '/assets/fonts/fontName.ttf' in '/home/user01/Projects/dir/project-name/widgets/widget-base/src
    at runMicrotasks (<anonymous>)

@stale
Copy link

stale bot commented Jan 8, 2022

This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in 5 days if no further activity occurs.

@stale stale bot added the stale label Jan 8, 2022
@cfecherolle
Copy link

cfecherolle commented Jan 26, 2022

Not stale: I'm having the same issue and looking for a solution that does not imply:

  • copying all of my images in two different places (/src and /public)
  • moving my images to src/ because in most cases, it doesn't belong there
  • relying on yet another third-party lib for such a trivial matter (don't get me wrong: I'm glad we can solve this using Craco in the meantime though and will give this solution a try, but this is clearly not a long-term/acceptable way of solving the issue)

@cherouvim
Copy link
Contributor

Not sure if this is helpful, but I managed to solve this issue by prefixing ~/public to the URLs in my sass files:

background-image: url("~/public/example.svg");

@koga73
Copy link

koga73 commented Feb 2, 2022

Downgraded react-scripts to ^3.4.0 and all is well now.
Please fix this issue already its been over a year!

@Hew007
Copy link

Hew007 commented Mar 10, 2022

Downgraded react-scripts to ^3.4.0 and all is well now. Please fix this issue already its been over a year!

Same issue with me, after I upgrade react-script 4.0.0 from 3.4.0。。。。

@Sebusml
Copy link

Sebusml commented Mar 22, 2022

what is the recommendation here?
The following worked for me but is there a better way?

background-image: url("~/public/example.svg");

@Hew007
Copy link

Hew007 commented Mar 30, 2022

I had

Downgraded react-scripts to ^3.4.0 and all is well now. Please fix this issue already its been over a year!

Same issue with me, after I upgrade react-script 4.0.0 from 3.4.0。。。。

resolved!

{
        loader: 'css-loader',
        options: { url: false }
      },

@metadan
Copy link

metadan commented Mar 30, 2022

@Hew007 ooi where are you adding this?

@Hew007
Copy link

Hew007 commented Mar 31, 2022

@Hew007 ooi where are you adding this?
the location of config your webpack moudule rule.
my project used customize-cra to customize cra webpack-config

module.exports = override(
  addWebpackModuleRule({
    test: /\.scss$/,
    use: [
      {
        loader: 'style-loader'
      },
      {
        loader: 'css-loader',
        options: { url: false }
      },
      {
        loader: 'sass-loader'
      }
    ]
  })
)

mkykadir pushed a commit to bosagora/talos that referenced this issue Jun 16, 2022
We were using node-gyp v3.8.0, which has a bug preventing it to be used with Python3
However, we build on Alpine Linux, which requires Python3.

As the bug was showing up while building node-sass,
the later was also updated to a compatible version.
It also helps as the node-sass version was ancient and did not
work with all recent node.js versions.

However, as `react-scripts` depended on `sass-loader` v8,
and `sass-loader` depends on `node-sass` v4.x.x, we also had to bump `react-scripts`.
The first version to support `sass-loader` v11 was v4.0.2 and v4.0.3 is the latest
version as of the time of this commit.

This then led to facebook/create-react-app#9937
which is worked around by simply moving the assets.
@bdrazen
Copy link

bdrazen commented Jul 9, 2022

Even after setting url: false for css-loader through react-app-rewired, it's still stripping the leading slash during build for me. (Post on stackoverflow) Any ideas?

@abrahamadamu
Copy link

what is the recommendation here? The following worked for me but is there a better way?

background-image: url("~/public/example.svg");

This seems the best solution so far

@Hew007
Copy link

Hew007 commented Jul 16, 2022

Expect for css-loader, I setting root: xxx for resolve-url-loader yet.
loader: require.resolve('resolve-url-loader'), options: { sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment, // root: paths.appSrc, ....... },

@LDT2016
Copy link

LDT2016 commented Apr 20, 2023

Describe the bug

When trying to import a image using the url method in a css/sass file the path no longer resolves to include the public directory using the prefix /

Did you try recovering your dependencies?

Yes

Which terms did you search for in User Guide?

Environment

  current version of create-react-app: 4.0.0
  running from /Users/jfay/.npm/_npx/12069/lib/node_modules/create-react-app

  System:
    OS: macOS 10.15.7
    CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
  Binaries:
    Node: 12.18.3 - /usr/local/bin/node
    Yarn: 1.21.1 - /usr/local/bin/yarn
    npm: 6.14.6 - /usr/local/bin/npm
  Browsers:
    Chrome: 86.0.4240.75
    Edge: Not Found
    Firefox: 80.0
    Safari: 14.0
  npmPackages:
    react: ^17.0.1 => 17.0.1 
    react-dom: ^17.0.1 => 17.0.1 
    react-scripts: ^4.0.0 => 4.0.0 
  npmGlobalPackages:
    create-react-app: Not Found

Steps to reproduce

  1. Start with a generic cra w/ react-scripts@4.0.0
  2. Open App.css
  3. Set the background to use an image resolved to the public url
.App {
  text-align: center;
  background-image: url("/logo192.png");
}

Expected behavior

Prior to upgrading to react-scripts@latest version 3.4.3 resolved images referenced in css files to include the public directory.

Actual behavior

Screen Shot 2020-10-28 at 12 33 07 PM

great! I got the same isuse, it disturbed me in one whole day, even i can't sleep all night, perfert, thank you.

I upgraded react to 18, while upgrading react-script to 5,
then do react eject, then it got build exception - i use scss import some png resource from public folder,
"Module not found: Error: Can't resolve '../../pict/main.png' in '....\ClientApp\src\resource\css'"

do the change in webpack.config.js
image

@olignyf
Copy link

olignyf commented Jul 26, 2023

What's the easiest way to override this line without having each individual developer edit the node_modules after each fresh checkout ? Can react-scripts add a new simple option to be read from a top-level script?
myapp\node_modules\react-scripts\config\webpack.config.js
options: cssOptions,
=>
options: { ...cssOptions, url: false },

@olignyf
Copy link

olignyf commented Jul 26, 2023

@atlanteh this issue would be important to fix in my opinion. In our case we leverage the different behavior of the public assets of not being renamed with random string to do file replacement afterward in the build. We have different flavor of products that use the same yarn build result for different hardware platforms and we afterward stage them differently by (among other things) replacing some images in the public folder based on the product theme. It would be nice not to have to use craco just to workaround this issue. Thanks!

@atlanteh
Copy link
Contributor

@olignyf This is not my decision to make as I'm just another user here like you, plus unfortunately CRA is no longer maintained, so if you want you can just fork it and fix it however you like or move to other alternatives :)

@YuAnWu0000
Copy link

Hi all,
I'm using react-app-rewired to extend webpack.config. Here is my solution:

// config-overrides.js
const path = require('path')
module.exports = function override(config) {
  const targetRegex = /\.css$/
  const targetPackage = /css-loader/
  // to make url() in css worked
  config.module.rules
    .find((r) => r.oneOf)
    .oneOf.find((r) => r.test.toString() === targetRegex.toString())
    .use.find((o) => o.loader && targetPackage.test(o.loader)).options.url =
    false
  return config
}

Hope you guys find it helpful!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests