How to specify multiple loaders in Webpack plugin? - css

My Webpack config contains the following loaders.
module: {
loaders: [
{ test: /\.js$/, loader: "babel", exclude: /node_modules/ },
{ test: /\.sass$/, loaders: ["style-loader", "css-loader", "sass-loader"], exclude: /node_modules/ }
]
},
Then, I wished to pull out the CSS to a separate file and I tried using the extract text webpack plugin, alternating my config like this.
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module: {
loaders: [
{ test: /\.js$/, loader: "babel", exclude: /node_modules/ },
// { test: /\.sass$/, loaders: ["style-loader", "css-loader", "sass-loader"], exclude: /node_modules/ }
{
test: /\.sass$/,
loader: ExtractTextPlugin.extract(
{
loaders: ["css-loader", "sass-loader"],
fallbackLoader: "style-loader"
}
),
exclude: /node_modules/
}
]
},
plugins: [new ExtractTextPlugin("global.css")],...
However, it fails with. Probably due me not specifying the loaders correctly. How can I specify multiple loaders (one for SASS and one for CSS)?
Module not found: Error: Cannot resolve module '[object Object]' in C:\Source\Poc\TestProj
# ./index.js 7:14-38
I've checked the file index.js but I can't see anything wrong there. It's literally empty export, as shown below. And the reference to 7:14-38 says nothing to me. There aren't that many lines in the file, even...
import CssGlobal from "./global.sass";
//document.write("Banana!");
export default {}

This syntax for ExtractTextPlugin.extract() only works in webpack2 and above, apparently (an object as argument). Check this issue.
In order to make it work with webpack1, the syntax is:
ExtractTextPlugin.extract([notExtractLoader], loader, [options])`
notExtractLoader (optional) the loader(s) that should be used when the css is not extracted (i.e. in an additional chunk when allChunks:
false)
loader the loader(s) that should be used for converting the resource to a css exporting module.
Source: https://github.com/webpack/extract-text-webpack-plugin/blob/webpack-1/README.md
So, a working config file would be:
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
/* ... */
module : {
loaders: [
{ test: /\.js$/, loader: "babel", exclude: /node_modules/ },
{
test: /\.sass$/,
exclude: /node_modules/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader!sass-loader")
/* using ExtractTextPlugin.extract(["css","sass"]) works too */
}
]
},
plugins: [
new ExtractTextPlugin("styles.css")
]
}
This will genereate a styles.css file.

Loaders are transformations that are applied on a resource file of your app. They are functions (running in node.js) that take the source of a resource file as the parameter and return the new source.
For example, you can use loaders to tell webpack to load CoffeeScript or JSX.
Nicely Explained here
http://ui-codeman.blogspot.in/2017/02/webpack.html?view=sidebar

Related

Webpack.config not running Sass-Loader before PostCSS-Loader

My config file currently has the following possibly relevant code:
{
// do not exclude `node_modules`
test: /\.css$/,
loader: ExtractTextPlugin.extract(
'style-loader',
'css',
{ publicPath: '../' }
)
},
{
test: /\.scss$/,
exclude: /node_modules/,
loader: ExtractTextPlugin.extract(
'style-loader',
['css-loader', 'postcss-loader', 'sass-loader'],
{ publicPath: '../' }
)
},
It's important that I run sass-loader first because PostCSS-loader (Autoprefixer) is unable to reach code within a #mixin that I have.
So far I've been unable to apply the relevant vendor prefix to the #mixin code being imported in. Everything works as expected if I move the #mixin code to where I #include it.
For Webpack 1 the extract function is expecting two parameters.
The first parameter will be applied when you're not extracting css to a file (fallback).
The second parameter is a list of loaders separated by an exclamation mark (!) , these loaders are applied from right to left.
ExtractTextPlugin.extract(
'style-loader',
'css-loader!postcss-loader!sass-loader'
);
For Webpack 2:
The ExtractTextPlugin is expecting a loader or an object.
ExtractTextPlugin.extract(options: loader | object)
Example:
{
test: /\.scss$/,
exclude: /node_modules/,
loader: ExtractTextPlugin.extract({
fallbackLoader: "style-loader",
loader: [
"css-loader",
"postcss-loader",
"sass-loader"
]
})
}
I've discovered the issue in my code. My entry-point files, where the scss files were being imported, were importing as such:
import styles from '!style-loader!css!sass!postcss-loader!./styles/styles.scss'
This was overwriting the configurations in my webpack.config files, so I simply changed all my import lines to have the correct loader order.

unable to generate CSS file sass-loader webpack

I am trying to use sass-loader to convert SCSS files to css(Required to have physical file). Styles are getting applied but unable to see generated .css files .
//webpack.config.js
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: './src/index.js',
output: {
path: __dirname + '/public',
filename: 'bundle.js'
},
devServer: {
contentBase: __dirname + '/public'
},
module: {
loaders: [
{test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'},
{test: /\.scss$/, loader: ExtractTextPlugin.extract('css-loader!sass-loader')}
]
},
plugins: [
new ExtractTextPlugin("style.css")
]
}
Full source code is available at github repo
I've seen the source code. I'm sure it's because of you're still using webpack version 1 syntax but what you installed was webpack v2. Webpack2 has a different syntax than the previous version.
Using webpack v2 your webpack.config.js will look like this:
module: {
rules: [ // from 'loaders' to 'rules'
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.sass$/,
exclude: /node_modules/,
loader: ExtractTextPlugin.extract({
fallbackLoader: 'style-loader',
loader: ['style-loader','sass-loader']
})
}
]
},
plugins: [
new ExtractTextPlugin('bundle.css') // what the output file (css) is going to be
]
Hope this helps.

Unable to extract CSS from scss with ExtractTextPlugin webpack

I have following configurations in my webpack.config.js and package.json respectively:
var extractSCSS = new ExtractTextPlugin({filename: '[name].css', disable: false, allChunks: true});
module: {
loaders: [
{
test: /\.jsx?$/,
include: SRC_DIR,
exclude: /(node_modules)/,
loader: 'babel-loader',
query: {
presets: ["react", "es2015", "stage-2"]
}
},
{
test: /\.scss$/i,
include: SRC_DIR,
exclude: /(node_modules)/,
loader: extractSCSS.extract(['css','sass'])
}
]
},
plugins: [
extractSCSS
]
and
"css-loader": "^0.26.1",
"extract-text-webpack-plugin": "^2.0.0-beta",
"style-loader": "^0.13.1",
"webpack": "^2.2.0",
But I am not able to generate the css files. Is there something I am missing here?
EDIT
I updated the files as below:
"css-loader": "^0.26.1",
"extract-text-webpack-plugin": "^2.0.0-beta.5",
"sass-loader": "^4.1.1",
"style-loader": "^0.13.1",
and
{
test: /\.css$/,
exclude: /(node_modules)/,
loader: ExtractTextPlugin.extract({
fallbackLoader: "style-loader",
loader: "css-loader",
publicPath: "/dist"
})
}
I have ExtractTextPlugin set up and it works, but it looks totally different from the configuration that you have. This is my configuration
module: {
rules: [
...
{
loader: ExtractTextPlugin.extract({
fallbackLoader: "style-loader",
loader: [
{
loader: "css-loader"
},
{
loader: "postcss-loader"
},
{
loader: "sass-loader"
}
]
}),
test: /\.s(a|c)ss$/
}
...
},
plugins: [
...
new ExtractTextPlugin({
allChunks: true,
filename: "style.[contenthash].css"
})
...
]
How it works is that the loaders get called from the back to the front. So first is the sass-loader, then the postcss-loader, etc. The fallbackLoader option is used when there is no CSS which can be extracted.
Last but not least, I want to add that I don't use ExtractTextPlugin in development, since it can result in longer build times.
Edit
I forgot to include the plugins part of my configuration. And just to clarify, the dots mean that there it is a piece of my configuration. All content relevant to the question is provided.
You have to install sass-loader
npm install --save-dev sass-loader
Note that with Webpack2 you should/have to update the configuration file :
It is not possible anymore to omit the -loader extension when referencing loaders (Automatic -loader)
module.loaders is now module.rules ( webpack 2 migration guide )
chaining loaders is only supported using the legacy option module.loaders
in V2 rule.use entry specifies a loader to be used. (rule.use)
Here is extracts of my working config :
const extractCss = new ExtractTextPlugin('app.bundle.css');
add this rules :
{
test: /\.scss$/,
loader: extractCss.extract([
{ loader: 'css-loader', query: { sourceMaps: true }},
{ loader: 'sass-loader', query: { sourceMaps: true }}
])
},
and the plugin :
plugins: [
extractCss,
Not sure if this will help, but for me moving over from Browserify I had some grief with this same issue.
I didn't realise in order for the ExtractTextPlugin to produce any css, I had to include the scss in the javascript somewhere (even though it's extracting to app.bundle.css or similar) otherwise it will silently produce no output.
application.js
require('../scss/container.scss')
or
import css from '../scss/container.scss'
will result in injected <style> tags in the header in development, and an extracted app.bundle.css file in production.

How to precompile scss to a single css file in webpack?

Using React with webpack.
Ran through some articles, but most of them suggest calling individual scss file for each component. But I would like to precompile all css into single file for entire application like we do using grunt/gulp.
You can use the webpack-text-extract-pluggin that is in charge of compiling all css files and bundling them in an index.css file.
Also note that you'll need to install sass-loader too in order to compile the scss.
In the webpack config:
var ExtractTextPlugin = require('extract-text-webpack-plugin');
config = {
...,
plugins: [
...,
new ExtractTextPlugin('index.css')
],
module: {
loaders: [
...
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style','css')
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style', 'css!sass')
}
]
}
}
In index.html:
<link rel="stylesheet" type="text/css" href="/index.css">
In any Javascript file that gets through webpack:
require("./styles/my-custom-file.scss");
You could take a look at the extract-text-webpack-plugin.
After requiring this in your webpack.config.js:
var ExtractTextPlugin = require("extract-text-webpack-plugin");
You can rewrite your sass loader to this:
module: {
loaders: [
{test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'},
{test: /\.scss$/, loader: ExtractTextPlugin.extract('style', 'css', 'sass')}
]
},
plugins: [
new ExtractTextPlugin('bundle.css')
]
For more options and usage check the link above.

Webpack and fonts: module parse failed

I'm trying to use FontAwesome in my app. I'm using webpack to do it's magic. My config is:
resolve: {
// you can now require('myfile') instead of require('myfile.cjsx')
extensions: ['', '.js', '.jsx', '.cjsx', '.coffee']
},
module: {
loaders: commonLoaders.concat([
{ test: /\.css$/, loader : 'style-loader!css-loader' },
{ test: /\.(ttf|eot|svg|woff(2))(\?[a-z0-9]+)?$/, loader : 'file-loader' },
{ test: /\.cjsx$/, loaders: ['react-hot', 'coffee', 'cjsx']},
{ test: /\.coffee$/, loader: 'coffee' },
{ test: /\.jsx$|\.js$/, loader: 'jsx-loader?harmony' },
])
}
I'm requesting FontAwesome CSS like that:
require "../../styles/font-awesome.min.css";
font-awesome.min.css contains this:
#font-face {
font-family: 'FontAwesome';
src: url('../fonts/fontawesome-webfont.woff') format('woff');
font-weight: normal;
font-style: normal;
}
And for some reason, WebPack tries to parse .woff file with style-loader and gives me error:
ERROR in ./src/fonts/fontawesome-webfont.woff
Module parse failed: /var/www/app/src/fonts/fontawesome-webfont.woff Line 1: Unexpected token ILLEGAL
You may need an appropriate loader to handle this file type.
(Source code omitted for this binary file)
# ./~/css-loader!./src/styles/font-awesome.min.css 2:73-117
I'm really lost right now. Any ideas?
Update:
I'm completely lost right now. I've decided to fool around with my config and put this line in loaders:
{ test: /\.eot$/, loader : 'file' },
And required this file:
require "../../fonts/fontawesome-webfont.eot";
Got error:
ERROR in ./src/fonts/fontawesome-webfont.eot
Module parse failed: /var/www/app/src/fonts/fontawesome-webfont.eot Line 2: Unexpected token ILLEGAL
You may need an appropriate loader to handle this file type.
(Source code omitted for this binary file)
However, when I tried to require my file like this:
require "file!../../fonts/fontawesome-webfont.eot";
Everything went smooth. Looks like webpack ignores my loaders?
it depends on the url used in css.
this error is releated to regex, try to change (\?[a-z0-9]+) to (\?v=[0-9]\.[0-9]\.[0-9]) or (\?[\s\S]+).
Example:
https://github.com/gowravshekar/font-awesome-webpack
module.exports = {
module: {
loaders: [
// the url-loader uses DataUrls.
// the file-loader emits files.
{ 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" }
]
}
};
https://github.com/shakacode/font-awesome-loader
module.exports = {
module: {
loaders: [
// the url-loader uses DataUrls.
// the file-loader emits files.
{
test: /\.woff2?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
// Limiting the size of the woff fonts breaks font-awesome ONLY for the extract text plugin
// loader: "url?limit=10000"
loader: "url"
},
{
test: /\.(ttf|eot|svg)(\?[\s\S]+)?$/,
loader: 'file'
},
]
}
};
The other day I add the font-awesome through the LESS source so basically
npm install --save less-loader
bower install --save components-font-awesome
Then I require font awesome like this
require('bower_components/components-font-awesome/less/font-awesome.less')
And finally in the webpack.config.js I add the loader modules
var path = require('path')
module.exports = {
...
, module: {
loaders: [
{test: /\.less$/, loader: "style!css!less"},
{test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-woff'},
{test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/octet-stream'},
{test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'},
{test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml'}
]
}
};
I know that it not the same with .css but I believe that its easy this way. Hope it helps.

Resources