loading css url() files in a specific folder with webpack

fermmm picture fermmm · Dec 1, 2017 · Viewed 8.1k times · Source

I'm using a node library that has a css file inside, that css file loads an image like this

background-image: url("image.png");

The file "image.png" is being requested at http://localhost:9000/ (the root) is dirty to have images all over the root of the project.

Also I have another problem, I don't know why the image file of the module is not being copied to the build folder automatically, only works if I copy the image file manually to the build folder. Playing with Webpack config parameters I got working the feature to copy the images to root, but it puts random names to them and I do not want them in root.

I want all the images loaded to be copied to a "img" subfolder inside the build folder with thier original file names, and to be requested there, so the root is not dirty with all the files there.

This is my webpack config file:

var webpack               = require('webpack');
var WebpackNotifierPlugin = require('webpack-notifier');

"use strict";
module.exports = {
    entry:   "./source/typescript/Main.ts",
    output: {
        filename: "./js/bundle.js"
    },
    devtool: "inline-source-map",
    devServer: {
        contentBase: ".",
        host: "localhost",
        port: 9000,
        open: true
    },
    module: {
        rules: [
            {
                test:/\.(s*)css$/,
                use: [
                    {
                        loader: "style-loader"
                    },
                    {
                        loader: "css-loader",
                        options: {
                            url: false
                        }
                    },
                    {
                        loader: "sass-loader"
                    }
                ]
            },
            {
                test: /\.tsx?$/,
                use: 'ts-loader',
                exclude: /node_modules/
            },
            {
                enforce: 'pre',
                test: /\.js$/,
                loader: "source-map-loader"
            },
            {
                test: /\.(png|jpg|gif|svg|eot|ttf|otf|woff|woff2|json|xml|ico)$/,
                use: [{loader: 'file-loader'}]
            },
            {
                test: /\.(csv|tsv)$/,
                use: [{ loader: 'csv-loader' }]
            },
            {
                test: /\.exec\.js$/,
                use: [{ loader: 'script-loader' }]
            },
            {
                test: require.resolve('jquery'),
                use:
                [
                    {
                        loader: 'expose-loader',
                        options: 'jQuery'
                    },
                    {
                        loader: 'expose-loader',
                        options: '$'
                    }
                ]
            }

        ]
    },
    resolve: {
        extensions: [ '.tsx', '.ts', '.js' ]
    },
    plugins: [
        new WebpackNotifierPlugin({excludeWarnings: true}),
        //new webpack.optimize.UglifyJsPlugin({compress: {warnings: false}}) // Uncoment to minify bundle
    ]
};

Answer

fermmm picture fermmm · Dec 1, 2017

I solved the problems:

"outputPath" and "name" parameters can be used to tell webpack to copy all the image files to a specific folder in the build folder and with a specific name rule. So I solved the problems like this:

1) The solution to the files copied in the root with random file names: I changed the webpack configuration file to tell webpack that any image loaded should be copied to the build folder inside a img sub-folder with their original name. This is done in the file-loader options using the "outputPath" and "name" parameters.

2) The solution to the images files not being copied to the build folders: Removed "url: false" in the css-loader, so now the paths are managed by css-loader. (The default behavior). I originally set that option because I didn't understand how css-loader resolves urls so I disabled that feature because it was throwing some errors. Now I realised that css url() paths are relative to the root of the project starting with /, for example: url("/img/my-image.png"); That prevented webpack to copy the image files to the build folder.

Now everything works, my final webpack configuration of loaders is this:

    module: {
        rules: [
            {
                test: /\.(png|jpg|gif|svg|ico)$/,
                loader: 'file-loader',
                query:{
                    outputPath: './img/',
                    name: '[name].[ext]?[hash]'
                }
            },
            {
                test: /\.(eot|ttf|otf|woff|woff2|json|xml)$/,
                loader: 'file-loader',
                query:{
                    outputPath: './fonts/',
                    name: '[name].[ext]?[hash]'
                }
            },
            {
                test: /\.(json|xml)$/,
                loader: 'file-loader',
                query:{
                    outputPath: './data/',
                    name: '[name].[ext]?[hash]'
                }
            },
            {
                test: /\.(s*)css$/,
                use: [{ loader: "style-loader" }, { loader: "css-loader" }, { loader: "sass-loader" }]
            },
            {
                test: /\.tsx?$/,
                use: 'ts-loader',
                exclude: /node_modules/
            },
            {
                enforce: 'pre',
                test: /\.js$/,
                loader: "source-map-loader"
            },
            {
                test: /\.(csv|tsv)$/,
                use: [{ loader: 'csv-loader' }]
            },
            {
                test: /\.exec\.js$/,
                use: [{ loader: 'script-loader' }]
            }           
        ]
    }