Description
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
-
npm ls react-scripts
(if you haven’t ejected): Ejected -
node -v
: v6.9.2 -
npm -v
: 4.2.0 -
Operating system: Windows 10
-
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;