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

Loading files from css. #1553

Closed
goztrk opened this issue Feb 14, 2017 · 21 comments
Closed

Loading files from css. #1553

goztrk opened this issue Feb 14, 2017 · 21 comments

Comments

@goztrk
Copy link

goztrk commented Feb 14, 2017

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’t 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;
@goztrk goztrk closed this as completed Feb 14, 2017
@gaearon
Copy link
Contributor

gaearon commented Feb 14, 2017

Have you figured it out?

@davesag
Copy link

davesag commented Feb 15, 2017

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.

@goztrk goztrk reopened this Feb 15, 2017
@goztrk
Copy link
Author

goztrk commented Feb 15, 2017

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.

@goztrk goztrk changed the title Font loading problem Loading URL from css. Feb 15, 2017
@goztrk goztrk changed the title Loading URL from css. Loading files from css. Feb 15, 2017
@gaearon
Copy link
Contributor

gaearon commented Feb 15, 2017

Can you reproduce this without ejecting?

@davesag
Copy link

davesag commented Feb 15, 2017

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.

@goztrk
Copy link
Author

goztrk commented Feb 15, 2017

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.

@gaearon
Copy link
Contributor

gaearon commented Feb 15, 2017

But this will not show us anything.

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

@DeltaCircuit
Copy link

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?

@gaearon
Copy link
Contributor

gaearon commented Feb 24, 2017

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

@DeltaCircuit
Copy link

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:
 root  
 |  -- my-app  
 |  -- semantic ui

I used Lerna 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

@alduro
Copy link

alduro commented Feb 25, 2017

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]'
      }

@gaearon
Copy link
Contributor

gaearon commented Feb 25, 2017

@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’t need to worry about long-term caching of assets.

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

@alduro
Copy link

alduro commented Feb 25, 2017

@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

@gaearon
Copy link
Contributor

gaearon commented Feb 25, 2017

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.

@gaearon
Copy link
Contributor

gaearon commented Feb 25, 2017

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.

@gaearon
Copy link
Contributor

gaearon commented Feb 25, 2017

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. 😉

@alduro
Copy link

alduro commented Feb 25, 2017

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

@gaearon
Copy link
Contributor

gaearon commented Feb 26, 2017

@alduro No worries! I’m glad you got it working 👍

I’m 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’re not really in the best position to answer it, and I suggest engaging with Webpack community for help. Unfortunately we can’t provide support for every possible Webpack configuration in this issue tracker.

The problem @giridharangm described further doesn’t 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’m happy to look at it but we’ll need a separate issue and a published project reproducing this.

@gaearon gaearon closed this as completed Feb 26, 2017
@DeltaCircuit
Copy link

@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.

@gaearon
Copy link
Contributor

gaearon commented Feb 26, 2017

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

@DeltaCircuit
Copy link

@gaearon Created a new issue for this here #1661

@lock lock bot locked and limited conversation to collaborators Jan 22, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants