Create-react-app: Loading files from css.

Created on 14 Feb 2017  路  21Comments  路  Source: facebook/create-react-app

Can you reproduce the problem with latest npm?

Yes.

Description

Font Awesome is installed with npm. I am importing the it from scss:
@import '~font-awesome/css/font-awesome.min.css';

In react-scripts 0.8.2 this was working without a problem. Fonts were loading correctly.
When I check the loaded css, I see that url() of font face replaced correctly with /static/media...

Note: this also happens when importing font with @font-face.

NOTE2: also images cannot bi loaded from scss files.

NOTE3: importing from css or scss files does not work. Files emitted on webpack but I cannot see them from chrome devtool. But importing from JS works.

Expected behavior

Fonts and images which is defined in css or scss should load from browser correctly.

Actual behavior

Fonts and images are not loading from browser on render. For normal fonts (not icon fonts) I imported from google and working fine. But when I try to import from css as local file, It is not loading on render. If I enter the url of the media to browser, I can reach it.

Any import or url() call does not get the files.

Environment

  1. npm ls react-scripts (if you haven鈥檛 ejected): Ejected
  2. node -v: v6.9.2
  3. npm -v: 4.2.0

  4. Operating system: Windows 10

  5. Browser and version: Chrome 56

Reproducible Demo

Freshly installed and ejected react-scripts:

package.json

{
  "name": "site",
  "version": "0.1.0",
  "private": true,
  "devDependencies": {
    "autoprefixer": "6.7.2",
    "babel-core": "6.22.1",
    "babel-eslint": "7.1.1",
    "babel-jest": "18.0.0",
    "babel-loader": "6.2.10",
    "babel-preset-react-app": "^2.1.0",
    "babel-runtime": "^6.20.0",
    "case-sensitive-paths-webpack-plugin": "1.1.4",
    "chalk": "1.1.3",
    "connect-history-api-fallback": "1.3.0",
    "cross-spawn": "4.0.2",
    "css-loader": "0.26.1",
    "detect-port": "1.0.1",
    "dotenv": "2.0.0",
    "eslint": "3.8.1",
    "eslint-config-react-app": "^0.5.1",
    "eslint-loader": "1.6.0",
    "eslint-plugin-flowtype": "2.21.0",
    "eslint-plugin-import": "2.0.1",
    "eslint-plugin-jsx-a11y": "2.2.3",
    "eslint-plugin-react": "6.4.1",
    "extract-text-webpack-plugin": "^2.0.0-rc.3",
    "file-loader": "0.10.0",
    "filesize": "3.3.0",
    "fs-extra": "0.30.0",
    "gzip-size": "3.0.0",
    "html-webpack-plugin": "^2.28.0",
    "http-proxy-middleware": "0.17.3",
    "jest": "18.1.0",
    "json-loader": "0.5.4",
    "jsx-control-statements": "^3.1.5",
    "node-sass": "^4.5.0",
    "object-assign": "4.1.1",
    "postcss-loader": "1.2.2",
    "promise": "7.1.1",
    "react-dev-utils": "^0.5.0",
    "react-hot-loader": "^3.0.0-beta.6",
    "recursive-readdir": "2.1.0",
    "redux-logger": "^2.8.1",
    "sass-loader": "^5.0.1",
    "strip-ansi": "3.0.1",
    "style-loader": "0.13.1",
    "url-loader": "0.5.7",
    "webpack": "^2.2.1",
    "webpack-dev-server": "^2.3.0",
    "webpack-manifest-plugin": "1.1.0",
    "whatwg-fetch": "2.0.2"
  },
  "dependencies": {
    "classnames": "^2.2.5",
    "font-awesome": "^4.7.0",
    "normalize-css": "^2.3.1",
    "react": "^15.4.2",
    "react-dom": "^15.4.2",
    "react-helmet": "^4.0.0",
    "react-redux": "^5.0.2",
    "react-router": "^3.0.2",
    "react-router-redux": "^4.0.8",
    "redux": "^3.6.0",
    "redux-thunk": "^2.2.0"
  },
  "scripts": {
    "start": "node scripts/start.js",
    "build": "node scripts/build.js",
    "test": "node scripts/test.js --env=jsdom"
  },
  "jest": {
    "collectCoverageFrom": [
      "src/**/*.{js,jsx}"
    ],
    "setupFiles": [
      "<rootDir>\\config\\polyfills.js"
    ],
    "testPathIgnorePatterns": [
      "<rootDir>[/\\\\](build|docs|node_modules|scripts)[/\\\\]"
    ],
    "testEnvironment": "node",
    "testURL": "http://localhost",
    "transform": {
      "^.+\\.(js|jsx)$": "<rootDir>/node_modules/babel-jest",
      "^.+\\.css$": "<rootDir>\\config\\jest\\cssTransform.js",
      "^(?!.*\\.(js|jsx|css|json)$)": "<rootDir>\\config\\jest\\fileTransform.js"
    },
    "transformIgnorePatterns": [
      "[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$"
    ],
    "moduleNameMapper": {
      "^react-native$": "react-native-web"
    }
  },
  "eslintConfig": {
    "extends": "react-app"
  }
}

config/webpack.config.dev.js

var autoprefixer = require('autoprefixer');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
var getClientEnvironment = require('./env');
var paths = require('./paths');

var publicPath = '/';
var publicUrl = '';
var env = getClientEnvironment(publicUrl);

var postCssConfig = {
  loader: 'postcss-loader',
  options: {
    ident: 'postcss', // https://webpack.js.org/guides/migrating/#complex-options
    plugins: function () {
      return [
        autoprefixer({
          browsers: [
            '>1%',
            'last 4 versions',
            'Firefox ESR',
            'not ie < 9', // React doesn't support IE8 anyway
          ]
        })
      ]
    }
  }
};

module.exports = {
  devtool: 'cheap-module-source-map',
  entry: [
    require.resolve('react-dev-utils/webpackHotDevClient'),
    require.resolve('./polyfills'),
    paths.appIndexJs
  ],
  output: {
    path: paths.appBuild,
    pathinfo: true,
    filename: 'static/js/bundle.js',
    publicPath: publicPath
  },
  resolve: {
    modules: [paths.appSrc, 'node_modules'].concat(paths.nodePaths),
    extensions: ['.js', '.json', '.jsx'],
    alias: {
      'react-native': 'react-native-web'
    }
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        enforce: 'pre',
        use: [{
          loader: 'eslint-loader'
        }],
        include: paths.appSrc
      },
      {
        exclude: [
          /\.html$/,
          /\.(js|jsx)$/,
          /\.css$/,
          /\.(sass|scss)$/,
          /\.json$/,
          /\.svg$/
        ],
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: 'static/media/[name].[hash:8].[ext]'
        }
      },
      {
        test: /\.(js|jsx)$/,
        include: paths.appSrc,
        loader: 'babel-loader',
        options: {
          cacheDirectory: true
        }
      },
      {
        test: /\.css$/,
        exclude: /\.module\.css$/,
        use: [
          'style-loader', {
            loader: 'css-loader',
            options: {
              sourceMap: true,
              importLoaders: 1
            }
          },
          postCssConfig
        ]
      },
      // Sass loader
      {
        test: /\.(sass|scss)$/,
        exclude: /\.module\.(sass|scss)$/,
        use: [
          'style-loader', {
            loader: 'css-loader',
            options: {
              sourceMap: true,
              importLoaders: 2
            }
          },
          postCssConfig, {
            loader: 'sass-loader',
            options: {
              sourceMap: true
            }
          }
        ]
      },
      // Css module loader
      {
        test: /\.module\.css$/,
        use: [
          'style-loader', {
            loader: 'css-loader',
            options: {
              modules: true,
              camelCase: true,
              sourceMap: true,
              importLoaders: 1,
              localIdentName: '[name]__[local]___[hash:base64:5]'
            }
          },
          postCssConfig
        ]
      },
      // Sass module loader
      {
        test: /\.module\.(sass|scss)$/,
        use: [
          'style-loader', {
            loader: 'css-loader',
            options: {
              modules: true,
              camelCase: true,
              sourceMap: true,
              importLoaders: 2,
              localIdentName: '[name]__[local]___[hash:base64:5]'
            }
          },
          postCssConfig, {
            loader: 'sass-loader',
            options: {
              sourceMap: true
            }
          }
        ]
      },
      {
        test: /\.svg$/,
        loader: 'file-loader',
        options: {
          name: 'static/media/[name].[hash:8].[ext]'
        }
      }
    ]
  },
  plugins: [
    new InterpolateHtmlPlugin(env.raw),
    new HtmlWebpackPlugin({
      inject: true,
      template: paths.appHtml,
    }),
    new webpack.DefinePlugin(env.stringified),
    new webpack.HotModuleReplacementPlugin(),
    new CaseSensitivePathsPlugin(),
    new WatchMissingNodeModulesPlugin(paths.appNodeModules)
  ],
  node: {
    fs: 'empty',
    net: 'empty',
    tls: 'empty'
  },
  performance: {
    hints: false
  }
};

index.js (this is where I import the style file which contains font-awesome import.)

// import { AppContainer } from 'react-hot-loader';
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { Router, browserHistory } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import routes from 'routes';
import configureStore from 'store/configureStore';
import 'index.scss';

const store = configureStore();
const history = syncHistoryWithStore(browserHistory, store);

const rootEl = document.getElementById('react-root');

render(
  <Provider store={store}>
    <Router history={history} routes={routes} />
  </Provider>,
  rootEl
);

index.scss

@import '~normalize-css/normalize.css';
@import url('https://fonts.googleapis.com/css?family=Lato:400,400i,700,700i|Quattrocento:400,700&subset=latin-ext');
@import '~font-awesome/css/font-awesome.min.css';
@import 'assets/styles/grid';
@import 'assets/styles/variables';

...

In some component:

import React, { Component } from 'react';
import cx from 'classnames';
import s from './style.module.scss';

class Navigation extends Component {
  render() {
    return (
      <section className={s.navigation}>
        <ul>
          <NavLink to="/about-me" text="About Me" icon="user" />
          <NavLink to="/projects" text="Projects" icon="briefcase" />
          <NavLink to="/blog" text="Blog" icon="pencil" />
          <NavLink to="/contact" text="Contact" icon="plane" />
        </ul>
      </section>
    );
  }
}

function NavLink(props) {
  return (
    <li className={s.navLink}>
      <a href={props.to}>
        <div className={s.icon}>
          <i className={cx('fa', `fa-${props.icon}`)} />
        </div>
        <div className={s.text}>{props.text}</div>
      </a>
    </li>
  );
}

export default Navigation;
underlying tools

All 21 comments

Have you figured it out?

I've encountered an analagous issue with Bootstrap's Glyphicons. See http://stackoverflow.com/questions/42228340/fonts-not-loading-after-upgrade-from-webpack-1-to-webpack-2

I'll study your example above as it's more advanced than my own webpack.config code and I am always keen to learn, but I'm wondering why you've closed this.

Actually I could not find a solution. After 6 hours of work, I could not reach any result. I have not found a complete solution on the internet. I closed the issue thinking "Maybe I'm doing something wrong and I will look like an idiot."

Here is what I did:

I usually eject app to add additional loaders and resolve src folder as root.

First, I closed the quiet mode from scripts/start.js to see what is going on. On the chunk list, I can see the images correctly loading. But when I look to devtool sources panel on Chrome, it shows only js folder lives in static folder. (it is skipping static folder like it has only js folder in it. I can provide screenshot if you want). Also there is no 404 error on the console.

I tried many loader options. When I can not reach a result, I try to import one of the images from within JS. When I import it in this way, the image is loaded properly.

Interestingly, when I enter the URL of image which is loaded from css, to browser, the image is loading properly.

So I gave up on trying after many hours. I still do not know what I did wrong. I can upload code to git if you want.

Can you reproduce this without ejecting?

In my case if I just build a production version with pretty much the same config and serve it up directly the fonts load fine. It _seems_ to be webpack-dev-server that's the issue. I'm sitting in a taxi now but can happily put together a minimal example that demonstrates the problem tomorrow.

No I get urls are loaded correctly from css when I do not eject the app.
But this will not show us anything. If there was a problem with unejected app, there will be so many people asking same question.

Now I will eject the app and enable css-loader module.

But this will not show us anything.

It helps me determine how critical the issue is. If it happens before ejecting, it鈥檚 a blocker. If it happens after, it鈥檚 a problem in how you configure it. We try to help but we aren鈥檛 Webpack experts either so you might want to file this directly with WDS or Webpack.

I'm not sure whether relates to this issue, but I've got a similar problem.
I've set up a Semantic-UI as a module, and tried to import the CSS from that module. All I'm getting is missing loader errors like url, file etc. That Semantic CSS does have @import and url() calls.
But if I run a npm i in the node_modules\react-scripts\ then it'll work without any issues. Possible side-effect of removing bundledDependencies?

If you can reproduce this in a project without ejecting, please provide this project and exact instructions to reproduce.

Yes. This issue can be reproduced without ejecting. What I did was:

  • Did a fresh installation of create-react-app my-app
  • Installed semantic-ui as a separate standalone local module.
    So the folder structure would look like this:
 |  -- my-app  
 |  -- semantic ui
 ```
 I used [Lerna](https://lernajs.io/) to organize these local modules.
 The `package.json` of semantic-ui package look like this:  
 ```
 {
  "name": "@gm/semantic-ui",
  "version": "2.2.4",
  "description": "",
  "main": "dist/semantic.css",
  "scripts": {
    "build": "gulp build",
    "clean": "gulp clean"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "semantic-ui": "^2.2.4"
  },
  "devDependencies": {
    "gulp": "^3.9.1"
  }
}

And the App.js of the newly created react app look like this:

import React, { Component } from 'react'
import '@gm/semantic-ui'
import { Grid } from 'semantic-ui-react'
class App extends Component {
  render() {
    return (
      <Grid>
        <Grid.Row>
          <Grid.Column>
            <h1>Hello World!</h1>
          </Grid.Column>
        </Grid.Row>
      </Grid>
    )
  }
}

export default App

I tried to move one of my projects to create-react-app structure and I couldn't make this work. Even if I eject the project, I haven't found a way to load fonts or images from within SCSS files. I tried using file or url loaders with no luck and it was really frustrating.
fonts and images directories are under src/

@import './node_modules/bootstrap-sass/assets/stylesheets/_bootstrap.scss'; <-- it loads correctly
@font-face {
    font-family: 'MontserratMedium';
    src: url('fonts/MontserratMedium.eot'); <--- it doesn't load
    src: url('fonts/MontserratMedium.eot') format('embedded-opentype'),
        url('fonts/MontserratMedium.woff2') format('woff2'),
        url('fonts/MontserratMedium.woff') format('woff'),
        url('fonts/MontserratMedium.ttf') format('truetype'),
        url('fonts/MontserratMedium.svg#MontserratMedium') format('svg');
    font-style: normal;
    font-weight: normal;
}

I added these loaders into webpack.config.dev.js. No luck.

     {
        test: /\.scss$/,
        include: paths.appSrc,
        loaders: ["style", "css", "resolve-url", "sass"]
      },
      {
        test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        loader: 'file?name=fonts/[name].[ext]'
      },
      { 
        test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, 
        loader: 'file?name=fonts/[name].[ext]' 
      },
      {
        // ASSET LOADER
        // Reference: https://github.com/webpack/file-loader
        test: /\.(png|jpg|jpeg|gif|svg|ico)$/,
        loader: 'url?name=images/[name].[ext]'
      }

@giridharangm

Please provide a full project. I don't understand what you are trying to do, or what problem you have, from your comment alone.

@alduro

As documented in the User Guide, you need to prepend any file URLs with ./ if you want them to end up in the Webpack bundle. So instead of fonts/MontserratMedium.eot you need to write ./fonts/MontserratMedium.eot:

Webpack finds all relative module references in CSS (they start with ./) and replaces them with the final paths from the compiled bundle. If you make a typo or accidentally delete an important file, you will see a compilation error, just like when you import a non-existent JavaScript module. The final filenames in the compiled bundle are generated by Webpack from content hashes. If the file content changes in the future, Webpack will give it a different name in production so you don鈥檛 need to worry about long-term caching of assets.

If it鈥檚 not clear enough, please send a pull request to improve the documentation.

@gaearon

Yes, I tried using ./ prefix originally but it did not work. I just added it and still not working. I'm attaching a screenshot showing errors.

screenshot 2017-02-25 12 44 33

You said fonts are in the src directory, but your styles are in a subfolder. So ./ is not the correct path. When I said to start it with ./ I meant that it needs to be a relative path, not that it must be literally ./fonts. You need to actually supply the correct path. In your case it is probably something like ../fonts/ or whatever it is depending on your structure.

So, to be clear, it works exactly like imports in JS. You need to supply a path relative from the folder where your CSS lives.

If you look at the error message you posted, it says which directory it is looking in, and which path it is trying to find. You can see that it doesn't match your folder location. Use that information to fix the path, and it will work. :wink:

@gaearon and you were right ! Sorry for my silly question. A matter of correct paths. Thanks for your time.

@alduro No worries! I鈥檓 glad you got it working 馃憤

I鈥檓 going to close this issue because the problem @gkhno reported seems to only affect configuration tweaked after ejecting. So this is not really a problem of CRA itself, but rather a Webpack usage question. We鈥檙e not really in the best position to answer it, and I suggest engaging with Webpack community for help. Unfortunately we can鈥檛 provide support for every possible Webpack configuration in this issue tracker.

The problem @giridharangm described further doesn鈥檛 seem related to the original issue to me. It looks more like a problem with Lerna setup and some assumptions Create React App might be making about paths. I鈥檓 happy to look at it but we鈥檒l need a separate issue and a published project reproducing this.

@gaearon may be you're right. I was wondering about lerna configuration too. My problem isn't about loading files using url(), but the loaders itself. This is the error I'm getting:

Failed to compile.

Error in ../semantic/dist/semantic.css
Module not found: 'url' in D:\work\open-source\cra-test\packages\semantic\dist

 @ ./~/css-loader?importLoaders=1!./~/postcss-loader!../semantic/dist/semantic.css 6:118615-118666

Error in ../semantic/dist/semantic.css
Module not found: 'url' in D:\work\open-source\cra-test\packages\semantic\dist

 @ ./~/css-loader?importLoaders=1!./~/postcss-loader!../semantic/dist/semantic.css 6:154380-154430 6:154453-154503

Error in ../semantic/dist/semantic.css
Module not found: 'url' in D:\work\open-source\cra-test\packages\semantic\dist

 @ ./~/css-loader?importLoaders=1!./~/postcss-loader!../semantic/dist/semantic.css 6:154553-154605

Error in ../semantic/dist/semantic.css
Module not found: 'url' in D:\work\open-source\cra-test\packages\semantic\dist

 @ ./~/css-loader?importLoaders=1!./~/postcss-loader!../semantic/dist/semantic.css 6:154636-154687

Error in ../semantic/dist/semantic.css
Module not found: 'url' in D:\work\open-source\cra-test\packages\semantic\dist

 @ ./~/css-loader?importLoaders=1!./~/postcss-loader!../semantic/dist/semantic.css 6:154717-154767

Error in ../semantic/dist/semantic.css
Module not found: 'file' in D:\work\open-source\cra-test\packages\semantic\dist

 @ ./~/css-loader?importLoaders=1!./~/postcss-loader!../semantic/dist/semantic.css 6:154801-154851

Sorry if I wasn't clear about the issue earlier. I've created a sample repo to reproduce. Please have a look.

Can you please create a new issue? It鈥檚 easier to keep track this way.

@gaearon Created a new issue for this here #1661

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dualcnhq picture dualcnhq  路  3Comments

alleroux picture alleroux  路  3Comments

xgqfrms-GitHub picture xgqfrms-GitHub  路  3Comments

adrice727 picture adrice727  路  3Comments

fson picture fson  路  3Comments