Using Font Awesome with Webpack and ExtractTextPlugin - css

I'm having difficulties with webpack and fonts... This is my webpack (common) config:
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var helpers = require('./helpers');
module.exports = {
entry: {
'polyfills': './src/polyfills.ts',
'vendor': './src/vendor.ts',
'app': './src/main.ts'
},
resolve: {
extensions: ['.js', '.ts']
},
module: {
rules: [
{
test: /\.ts$/,
loaders: [
{
loader: 'awesome-typescript-loader',
options: { configFileName: helpers.root('src', 'tsconfig.json') }
},
'angular2-template-loader'
]
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)(\?.*)?$/,
loader: 'file-loader?name=assets/[name].[hash].[ext]'
},
{
test: /\.css$/,
exclude: helpers.root('src', 'app'),
loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: 'css-loader?sourceMap' })
},
{
test: /\.scss$/,
exclude: helpers.root('src', 'app'),
loader: ExtractTextPlugin.extract({ fallback: 'style-loader', loader: [{ loader: 'css-loader?sourceMap' }, {loader: 'sass-loader?debug'} ] })
},
{
test: /\.css$/,
include: helpers.root('src', 'app'),
loader: 'raw-loader'
}
]
},
plugins: [
new webpack.ContextReplacementPlugin(
// The (\\|\/) piece accounts for path separators in *nix and Windows
/angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
helpers.root('./src'), // location of your src
{} // a map of your routes
),
new webpack.optimize.CommonsChunkPlugin({
name: ['app', 'vendor', 'polyfills']
}),
new HtmlWebpackPlugin({
template: 'src/index.html',
xhtml: true,
minify: {
removeAttributeQuotes: false,
keepClosingSlash: true
},
filename: '../templates/index.html'
})
]
};
I'm referencing font awesome scss with
$fa-font-path: '~font-awesome-sass/assets/fonts/font-awesome/';
#import '~font-awesome-sass/assets/stylesheets/_font-awesome-sprockets.scss';
#import '~font-awesome-sass/assets/stylesheets/_font-awesome.scss';
And the css seems correct but only fontawesome-webfont.svg is emitted, no woff, no eot...
When I try to look at the generated page with webpack-dev-server, I see "squares" instead of Font Awesome icons.
What am I doing wrong?

I resolved the problem installing font-awesome (instead of font-awesome-sass) and importing it with:
$fa-font-path: '~font-awesome/fonts/';
#import '~font-awesome/scss/font-awesome.scss';
I had the same problem with bootstrap-sass and glyphicons, and I resolved it changing the import from
//WARNING: Not working example
$icon-font-path: '~bootstrap-sass/assets/fonts/bootstrap/';
#import '~bootstrap-sass/assets/stylesheets/_bootstrap-sprockets.scss';
#import '~bootstrap-sass/assets/stylesheets/_bootstrap.scss';
to
$icon-font-path: '~bootstrap-sass/assets/fonts/bootstrap/';
#import '~bootstrap-sass/assets/stylesheets/_bootstrap.scss';

Related

React-filepond external CSS is not being applied. I suspect it's a webpack issue

This is beating my head in. I'm using react-filepond module in my react app, but the external CSS is not being applied. The module works but has no style. I suspect it's a loader issue in webpack but I'm still learning webpack and probably missed something. Thanks!
Here are the imports as per react-filepond:
import { FilePond } from 'react-filepond';
import 'filepond/dist/filepond.css'; // located in node_modules
Here's my webpack.config.js.
I'm using webpack 3.12.0
const path = require('path');
const autoprefixer = require('autoprefixer');
const htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
chunkFilename: '[id].js',
publicPath: '/'
},
resolve: {
extensions: ['.js', 'jsx', '.css']
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
options: {
presets: ['react']
},
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: true,
localIdentName: '[name]__[local]__[hash:base64:5]'
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
autoprefixer({
browsers: [
"> 1%",
"last 2 versions"
]
})
]
}
}
]
},
{
test: /\.(png|jpe?g|gif)$/,
loader: 'url-loader?limit=8000&name=images/[name].[ext]'
}
]
},
devServer: {
historyApiFallback: true
},
plugins: [
new htmlWebpackPlugin({
template: __dirname + '/src/index.html',
inject: 'body',
filename: 'index.html'
})
]
};
I found the solution for others wondering about this.
Issue: I am using CSS modules in react (note the line modules:true in the configuration of my css-loader in my webpack-config.js
The external react module I was trying to use does NOT use CSS modules.
Solution:
create a second rule for external CSS. Thus I have one for my CSS (as in the source above) and then I added this rule:
{
/* External CSS from node_modules */
test: /\.css$/,
include: /node_modules/,
loader: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
minimize: true,
},
}
]
},
Most importantly, I did NOT turn on CSS Modules
And then, in my other CSS rule, I added:
exclude: /node_modules/,

Rearrange style order in ccs bundle

After a migration from grunt, the styles are not working as intended with webpack. All the styles were concatenated in the gruntfile like this:
target: {
files: {
"all.css": [
"node_modules/bootstrap/dist/css/bootstrap.css",
"bower_components/toastr/toastr.css",
"bower_components/angular-ui-select/dist/select.css",
"node_modules/font-awesome/font-awesome.css",
"bower_components/angular-loading-bar/build/loading-bar.css",
"bower_components/angular-ui-tree/dist/angular-ui-tree.css",
"content/styles/awesome-bootstrap-checkbox.css",
"content/styles/tradesolution.css",
"content/styles/site.css",
"content/styles/ts.css",
"content/styles/nyKladd.css"
]
}
}
My current config in webpack:
var webpack = require('webpack');
var globby = require('globby');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var CleanWebpackPlugin = require('clean-webpack-plugin');
var AssetsPlugin = require('assets-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var DashboardPlugin = require('webpack-dashboard/plugin');
const ConcatPlugin = require('webpack-concat-plugin');
const extractCSS = new ExtractTextPlugin('[name].css');
const extractLESS = new ExtractTextPlugin('[name].css');
module.exports = {
entry: {
app: globby.sync(['./app/app.js','./app/app.run.js', './app/app.config.js', './app/**/*.js']),
Ztyles: globby.sync(['./content/styles/less/*.less']),
styles: globby.sync(['./content/styles/*.css']),
images: globby.sync(['./content/images/**/*.*']),
vendor: [
// removed to save space
],
},
output: {
filename: './scripts/[name].bundle.js',
path: path.join(__dirname, "public")
},
devServer: {
port: 1384,
contentBase: './public/'
},
// Enable sourcemaps for debugging webpack's output.
devtool: (() => {
if(NODE_ENV = "devlopment") return 'source-map'
else return 'cheap-module-eval-source-map'
}) (),
module: {
rules: [
{
test: /\.html$/,
loader: 'raw-loader',
exclude: [/node_modules/]
},
{
test: /\.css$/,
loader: extractCSS.extract(
{ fallback: 'style-loader', use: 'css-loader' }
),
//'style-loader', 'css-loader'
},
{ test: /\.less$/,
use: extractLESS.extract(
{fallback:'style-loader', use: ['css-loader','less-loader']}
)
//'style-loader', 'css-loader!less-loader'
},
{
test: /\.(ico)$/,
loader: "url-loader?name=./[name].[ext]",
include: path.resolve(__dirname, "content", "images")
},
{
test: /\.(jpg|jpeg|gif|png|PNG|tiff|svg)$/,
loader: 'file-loader?name=/[path]/[name].[ext]',
include: path.resolve(__dirname, "content", "images"),
},
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader?limit=10000&minetype=application/font-woff&name=./fonts/[name].[ext]' },
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file-loader?name=./fonts/[name].[ext]' },
{
test: require.resolve('adal-angular/lib/adal'),
loader: 'expose-loader?AuthenticationContext'
},
{
test: /\.js$/,
enforce: "pre",
loader: 'source-map-loader'
}
],
},
plugins: [
new webpack.DefinePlugin({
ADMIN_API_URL: JSON.stringify('http://localhost:41118/api/'),
API_URL: JSON.stringify('http://epdapi.tradesolution.no/'),
GLOBAL_ADMIN_URL: JSON.stringify('https://adminapi.tradesolution.no/')
}),
new HtmlWebpackPlugin({
template: './app/layout.html',
filename: 'index.html'
}),
extractCSS,
extractLESS,
new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: './scripts/vendor.bundle.js' }),
new ExtractTextPlugin({ filename: './[name].bundle.css' }),
new AssetsPlugin({
filename: 'webpack.assets.json',
path: './public',
prettyPrint: true
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
'window.$': 'jquery',
"window.AuthenticationContext": "AuthenticationContext",
_: 'underscore'
}),
new CopyWebpackPlugin([
{from: './app/**/*.html', to: './'}
]),
new DashboardPlugin()
],
externals: [
{ xmlhttprequest: '{XMLHttpRequest:XMLHttpRequest}' }
],
}
From this picture you can see that the default bootstrap styles are overriding the styles written for the nav-bar.
What i have done so far is to implement all the other css files into one less file, like this:
#import "../tradesolution.css";
#import "../site.css";
#import "../nykladd.css";
#import "for";
#import "kladd.less";
#import "~bootstrap/less/bootstrap";
#import "~bootstrap/less/alerts.less";
#import "~bootstrap/less/mixins/buttons.less";
#import "~font-awesome/less/font-awesome.less";
Then the less file is compiled to css and loaded in the Ztyles.css , but regardless of where I put the imports, my styles are still overridden. I have also tried changing the order of the webpack rules and the order of extractCSS and extractLESS in plugins
I dont think my intended solution is good practice, so any approach to solving this issue is very welcome.
After a while i stumbled over a new css framework postcss they have all kinds of plugins, and with this configuration I got it to work:
{
test: /\.css$/,
use: [
'style-loader',
{ loader: 'css-loader', options: { modules: true, importLoaders: 1 },
loader: 'postcss-loader',
},
]
},
{ test: /\.less$/,
use: extractLESS.extract(
{fallback:'style-loader', use: ['css-loader', 'less-loader']}
)
},
Here are some resources that helped:
https://github.com/postcss/postcss
https://webdesign.tutsplus.com/tutorials/using-postcss-together-with-sass-stylus-or-less--cms-24591
https://github.com/Crunch/postcss-less

Webpack: CSS app/vendor code splitting

Despite many searches on the Web, I couldn't find a working example of a webpack config that allows CSS bundle splitting (app.css and vendor.css, like Ember.js does). No problem for JavaScript though. Currently I have Normalize.css as a NPM package that I would like to move to vendor.css, instead of app.css.
Here is my file :
var webpack = require('webpack');
var autoprefixer = require('autoprefixer');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: {
html: './app/index.html',
javascript: './app/app.js',
vendor: ['react', 'react-dom']
},
module: {
loaders: [
{ test: /\.html$/, loader: 'file?name=index.html' },
{ test: /\.scss$/, loader: ExtractTextPlugin.extract('style', 'css!sass!postcss') },
{ test: /\.js$/, exclude: /node_modules/, loaders: ['react-hot', 'babel?presets[]=es2015&presets[]=react'] },
{ test: require.resolve('react'), loader: 'expose?React' }
],
},
postcss: [ autoprefixer({ browsers: ['last 2 versions'] }) ],
plugins: [
new ExtractTextPlugin('app.css'),
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js')
],
output: {
path: './dist',
filename: 'app.js'
},
devServer: {
port: 8000
}
}
Thanks in advance !

How to get svg from MDL working with webpack

Using a checkbox component form Material Design Lite, i.e.
https://getmdl.io/components/index.html#toggles-section/checkbox
the tickmark.svg is not shown properly when I use
import '../../node_modules/material-design-lite/src/material-design-lite.scss';
for bundling with npm and webpack. Instead of:
I get:
In the browser I find the following path to tickmark.svg which is the svg that is 'missing':
When using either one of these two alternatives it works as it should:
1) import '../../node_modules/material-design-lite/.tmp/material-design-lite.css';
2) import '../../node_modules/material-design-lite/material.min.css';
To compare, when using 2 I get following in the browser:
My webpack.config.js:
var path = require('path');
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var Clean = require('clean-webpack-plugin');
var bootstrapPath = path.join(__dirname, 'node_modules/bootstrap/dist/css');
var sourcePath = path.join(__dirname, 'assets');
module.exports = {
devtool: 'eval-source-map',
context: __dirname,
entry: [
'./assets/js/index' // entry point of our app. .assets/js/index.js should require other js modules and dependencies it needs
],
output: {
path: path.resolve('./assets/bundles/'),
filename: '[name]-[hash].js',
}
,
node: {
console: true,
fs: 'empty'
}
,
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}),
new BundleTracker({filename: './webpack-stats.json'}),
new webpack.BannerPlugin('Pqbq Banner!!!! todo'),
new HtmlWebpackPlugin({
template: __dirname + '/assets/index.tmpl.html'
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new Clean(['assets/bundles'])
],
module: {
preloaders: [
{
test: /\.js/,
loader: 'eslint'
}
],
loaders: [
{
test: /\.js[x]?$/,
loader: 'babel',
exclude: /(node_modules|bower-components)/,
query: {
presets: ['es2015', 'stage-0']
}
},
{
test: /\.json$/,
loader: 'json-loader'
},
{
test: /\.js$/,
include: path.resolve(__dirname, 'node_modules/mapbox-gl/js/render/shaders.js'),
loader: 'transform/cacheable?brfs'
},
{
test: /\.js$/,
include: path.resolve(__dirname, 'node_modules/webworkify/index.js'),
loader: 'worker'
},
// {
// test: /\.css$/,
// loader: 'style!css?modules!postcss'
// },
{
test: /\.scss$/,
loaders: ['style', 'css?sourceMap', 'sass?sourceMap']
},
// {test: /\.(woff2?|svg)$/, loader: 'url?limit=10000'},
// {test: /\.(ttf|eot)$/, loader: 'file'},
{test: /\.css$/, loader: 'style-loader!css-loader'},
{test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'},
{test: /\.(woff|woff2)$/, loader: 'url?prefix=font/&limit=5000'},
{test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/octet-stream'},
// {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml'},
{test: /\.svg$/, loader: 'url?limit=8192!svgo'},
]
}
,
postcss: [
require('autoprefixer')
],
resolve: {
modulesDirectories: ['node_modules', 'bower_components', bootstrapPath, sourcePath],
extensions: ['', '.js', '.jsx', '.css'],
alias: {
webworkify: 'webworkify-webpack',
'$': 'jquery',
'jQuery': 'jquery'
}
}
,
devServer: {
contentBase: './assets',
colors: true,
historyApiFallback: true,
inline: true,
hot: true
}
};
To fix this I had to override the $image_path variable by creating my own material.scss file. I grabbed this file:
https://github.com/google/material-design-lite/blob/master/src/material-design-lite.scss
and then added:
#import "./variables";
at the top.
In that file I added this line:
$image_path: '~material-design-lite/dist/images/' !default;

Webpack style-loader modules are overriding installed component css

I am using the react-super-select component in a react/redux project that I'm working on.
That project currently uses webpack and style-loader to load my styling:
const path = require('path');
const webpack = require('webpack');
const poststylus = require('poststylus');
module.exports = {
entry: [
'webpack-hot-middleware/client',
'./src/client/index',
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/',
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['babel'],
exclude: /node_modules/,
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url-loader?limit=10000&mimetype=application/font-woff',
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader',
},
{
test: /\.styl$/,
loader: 'style-loader!css-loader?modules!stylus-loader',
}],
},
stylus: {
use: [
poststylus([ 'autoprefixer', 'rucksack-css' ]),
],
},
};
I am finding that this use of style-loader seems to be overriding the styling provided with react-super-select.
Is there a way to configure webpack so that it does not override the style for this component?
Ok, I figured out how to do this -- I created a wrapper component that loaded the css explicitly:
import React, { PropTypes, Component } from 'react';
import ReactSuperSelect from 'react-super-select';
import 'react-super-select/lib/react-super-select.css';
export default class Dropdown extends Component {
render() {
const { options, onChange, ...preferences } = this.props;
return (
<ReactSuperSelect placeholder={preferences.placeholder}
dataSource={options}
onChange={onChange}
searchable={preferences.searchable} />
);
}
}
Dropdown.propTypes = {
options: PropTypes.array.isRequired,
onChange: PropTypes.func.isRequired,
preferences: PropTypes.object.isRequired,
};
and then I added a line to load css in my webpack config:
module: {
loaders: [{
test: /\.js$/,
loaders: ['babel'],
exclude: /node_modules/,
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url?limit=10000&mimetype=application/font-woff',
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file',
},
{
test: /\.styl$/,
loader: 'style!css?modules!stylus',
},
{
test: /\.css$/,
loader: 'style!css',
}],
},

Resources