WebPack how to put all css files into one css file

Fred picture Fred · Nov 1, 2016 · Viewed 14k times · Source

I am fairly new to WebPack, and I want to be able to take a directory of CSS files (.app/styles/[css files...]) and output them into one CSS file (dist/styles.css).

Currently, all the JavaScript files is compiled into one single "index_bundle.js" file, which is perfect, but I want to achieve the same for my CSS files.

After a lot of "Googling", I found that the ExtractTextPlugin for WebPack should be able to help with this, but this only works for one CSS file that is added to the "entry" property (eg: entry: {style: "./app/styles/style.css"}) which is then added to the html's head as a link tag, which is fine, but I want all my css files to go into one styles.css file and then use that in the html's head as a link.

My current WebPack config looks like this:

var HtmlWebpackPlugin = require('html-webpack-plugin');
var HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
    template: __dirname + '/app/index.html',
    filename: 'index.html',
    inject: 'body'
});

var ExtractTextPlugin = require('extract-text-webpack-plugin');
var ExtractTextPluginConfig = new ExtractTextPlugin(
    "styles.css", 
    {
        allChunks: false
    }
);

module.exports = {
    entry: {
        index: "./app/index.js"//,
        //styles: "./app/styles/style1.css" // I don't want one file, I want to use a directory eg: "./app/styles/"
    },
    output: {
        path: __dirname + '/dist',
        filename: 'index_bundle.js'
    },
    module: {
        loaders: [
            {
                test: /\.js$/, 
                exclude: /node_modules/, 
                loader: 'babel-loader'
            },
            { 
                test: /\.css$/, 
                loader: ExtractTextPlugin.extract("style-loader", "css-loader")
            }
        ]
    },
    plugins: [
        HtmlWebpackPluginConfig,
        ExtractTextPluginConfig
    ]
}

Can someone please point me in the right direction? Even if it is another plugin or a different approach. Any help will be greatly appreciated!

EDIT: My new WebPack config looks like this:

var HtmlWebpackPlugin = require('html-webpack-plugin');
var HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
    template: __dirname + '/app/index.html',
    filename: 'index.html',
    inject: 'body'
});

var ExtractTextPlugin = require('extract-text-webpack-plugin');
var ExtractTextPluginConfig = new ExtractTextPlugin(
    "index_bundle.css"
);

module.exports = {
    entry: [
        './app/index.js',
        './app/index.css'
    ],
    output: {
        path: __dirname + '/dist',
        filename: 'index_bundle.js'
    },
    module: {
        preloaders: [
            {
                test: /\.css/,
                exclude: /styles/, 
                loader: 'import-glob-loader'
            }
        ],
        loaders: [
            {
                test: /\.js$/, 
                exclude: /node_modules/, 
                loader: 'babel-loader'
            },
            { 
                test: /styles\.css$/, 
                loader: ExtractTextPlugin.extract("style-loader", "css-loader")
            },
            { 
                test: /\.json$/, 
                loader: 'json' 
            }
        ]
    },
    devServer: {
        historyApiFallback: true
    },
    plugins: [
        HtmlWebpackPluginConfig,
        ExtractTextPluginConfig
    ]
}

Answer

Fred picture Fred · Nov 1, 2016

Ok, so it seems to have been a camel-case problem.

With the help of Davin Tryon, I was able to resolve my issue - thanks!

If you look at: https://www.npmjs.com/package/import-glob-loader they have the following:

preloaders: [{
    test: /\.scss/,
    loader: 'import-glob-loader'
}]

It should be:

preLoaders: [{
    test: /\.scss/,
    loader: 'import-glob-loader'
}]

So in the end, my whole webpack.config.json looks like this:

var HtmlWebpackPlugin = require('html-webpack-plugin');
var HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
    template: __dirname + '/app/index.html',
    filename: 'index.html',
    inject: 'body'
});

var ExtractTextPlugin = require('extract-text-webpack-plugin');
var ExtractTextPluginConfig = new ExtractTextPlugin(
    "index_bundle.css"
);

module.exports = {
    entry: [
        './app/index.js',
        './app/index.css'
    ],
    output: {
        path: __dirname + '/dist',
        filename: 'index_bundle.js'
    },
    module: {
        preLoaders: [
            {
                test: /\.css$/,
                exclude: /styles/, 
                loader: 'import-glob-loader'
            }
        ],
        loaders: [
            {
                test: /\.js$/, 
                exclude: /node_modules/, 
                loader: 'babel-loader'
            },
            { 
                test: /\.css$/, 
                loader: ExtractTextPlugin.extract("style-loader", "css-loader")
            },
            { 
                test: /\.json$/, 
                loader: 'json' 
            }
        ]
    },
    devServer: {
        historyApiFallback: true
    },
    plugins: [
        HtmlWebpackPluginConfig,
        ExtractTextPluginConfig
    ]
}

And my index.css file looks like this:

@import './styles/**/*';

This is working for me and I get a single css output file "index_bundle.css". The style and scripts also automatically gets injected into the html template.

index.html before injection:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Admin - Login</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css"/>
    </head>
    <body>
        <div id="app"></div>
    </body>
</html>

index.html after injection in /dist folder:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Admin - Login</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css"/>
    <link href="index_bundle.css" rel="stylesheet"></head>
    <body>
        <div id="app"></div>
    <script type="text/javascript" src="index_bundle.js"></script></body>
</html>