facebook / create-react-app

Set up a modern web app by running one command.
https://create-react-app.dev
MIT License
102.57k stars 26.8k forks source link

public directory css url #9937

Open keonik opened 3 years ago

keonik commented 3 years ago

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
atlanteh commented 3 years ago

@zpetukhov you do realize that this was not intentional, right? I had a specific issue, I created a pr which was backed up by tests, approved by CRA team and it was merged. There was no tests regarding images resolution from public folder.

Honestly I didn't realize there were other issues with more people, but as you can see from the comments there, they all reached sort of what I had in mind:

The webpack issue seems very much related, but it seems to be used only in css-loader@5.2.6. react-scripts uses 4.3.0. I do see that next release (CRA@5), CRA updates webpack to version 5 with all relevant dependencies updated as well. I created an empty project and updated to react-scripts@5.0.0-next.31, then I created this css class:

and added this div to App: <div class="MyLogo" /> and it seems to be working, so next CRA release we should be able to start using webpackIgnore to reference files in css directly from public folder

zhuhang-jasper commented 3 years ago

@maciejgaciarz's fix worked for me until I built for prod because the leading backslash of my URLs was being removed. To resolve this, I further configured craco to remove resolve-url-loader and add it back without the newly-introduced root option.

craco.config.js

const { loaderByName, addAfterLoader, removeLoaders } = require("@craco/craco");

module.exports = {
  reactScriptsVersion: "react-scripts",
  style: {
    css: {
      loaderOptions: () => {
        return { url: false };
      },
    },
  },
  webpack: {
    configure: (webpackConfig, { env }) => {
      const isEnvDevelopment = env === "development";
      const isEnvProduction = env === "production";
      const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false";
      removeLoaders(webpackConfig, loaderByName("resolve-url-loader"));

      const resolveUrlLoader = {
        loader: require.resolve("resolve-url-loader"),
        options: {
          sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
        },
      };

      addAfterLoader(
        webpackConfig,
        loaderByName("postcss-loader"),
        resolveUrlLoader
      );

      return webpackConfig;
    },
  },
};

Thanks for this. I faced the same exact issue in PROD environment. And doing this in craco solves it!

vpokrityuk commented 3 years ago

Same issue 😬 After a lot of googling ended up here, which explains it

Kraedt commented 3 years ago

This sucks. Gotta love it when all of the docs online tell you how to import from the public folder, but as it turns out, nah just move everything into the src folder and it works fine!

makis-spy commented 3 years ago

A year later and still wrestling to get the public folder to work. New record. Old code importing url("/img") before 4 works but any new code automagically gets turned into url("../img") magic is great just not when trying to run a software company :)

caijf commented 3 years ago

I used craco and solved it this way, set the publicPath of webpack-dev-server

module.exports = {
  // ...

  devServer: (devServerConfig) => {
    // webpack-dev-server v3
    devServerConfig.publicPath = '/';
    return devServerConfig;
  }
}
SzymonGalazka commented 2 years ago

As seen in different thread, it is possible to have this working again with craco, by putting the following in .cracorc:

reactScriptsVersion: 'react-scripts',
  style: {
    css: {
      // CRA 4 escape hatch to serve static files from /public
      loaderOptions: () => {
        return { url: false };
      },
    },
  }
petro-shkuratenyuk commented 2 years ago

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

Morkowski commented 2 years ago

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 commented 2 years ago

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[bot] commented 2 years ago

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.

cfecherolle commented 2 years ago

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

cherouvim commented 2 years ago

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 commented 2 years ago

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

Hew007 commented 2 years ago

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 commented 2 years ago

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

background-image: url("~/public/example.svg");
Hew007 commented 2 years ago

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 commented 2 years ago

@Hew007 ooi where are you adding this?

Hew007 commented 2 years ago

@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'
      }
    ]
  })
)
bdrazen commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

@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 commented 1 year ago

@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 commented 2 months ago

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!