0

In my webpack config, I want the file-loader plugin to drop all referenced images in the ./dist/images/ folder (including SVGs). At the same time, I would like the file-loader plugin to also drop all referenced font files (for font-awesome) in the ./dist/assets/webfonts/ folder (this, too, includes SVGs).

The problem I'm having is that standard SVG images are being copied to the ./dist/assets/webfonts/ AND ./dist/images/ folders and font SVGs from font-awesome are being copied to the ./dist/images/ AND ./dist/assets/webfonts/ folders.

But worse than that, all the SVGs in the ./dist/images/ don't contain SVG data, they contain this:

module.exports = __webpack_public_path__ + "./assets/webfonts/logo-text.svg";

This is my current module configuration for the file-loader plugin:

{ test: /.*\.(gif|png|jpe?g|svg)$/, loader: "file-loader", options: { name: "./images/[name]_[hash:7].[ext]" }, exclude:  __dirname +  "/../src/assets/" },
{ test: /.*\.(ttf|eot|woff|woff2|svg)$/, loader: "file-loader", options: { name: "./assets/webfonts/[name].[ext]" }, exclude:  __dirname + "/../src/images/" }

You'll notice that for each file-loader entry, I've already excluded the folder it isn't supposed to load files from but that doesn't seem to have worked.

Any ideas on how to fix this?

Walter
  • 664
  • 1
  • 6
  • 19

1 Answers1

1

I had the same issue.

1. Distinguish between SVG fonts and images

You can use the outputPath option of the file-loader to differentiate between fonts and images like this:

{
    test: /.*\.(gif|png|jpe?g|svg)$/,
    loader: "file-loader",
    options: {
        name: "[name].[ext]",
        outputPath: (url, resourcePath, context) => {
            const relativePath = path.relative(context, resourcePath);

            // ignore SVG file if its relative path contains "fonts" (in your case "assets")
            if (/\/fonts\//.test(relativePath)) {
                return;
            }

            return `images/${url}`;
        },
    },
},
{
    test: /.*\.(ttf|eot|woff|woff2|svg)$/,
    loader: "file-loader",
    options: {
        name: "[name].[ext]",
        outputPath: (url, resourcePath, context) => {
            const relativePath = path.relative(context, resourcePath);

            // ignore SVG file if its relative path contains "images"
            if (/\/images\//.test(relativePath)) {
                return;
            }

            return `fonts/${url}`;
        },
    },
},

...but there is still the other issue:

2. Broken SVG content

It seems that only the SVGs of the last section are working. If I first run the fonts and after that the images, only images are built correctly - and vice versa. A workaround would be to add a new section for all SVGs and remove them from the fonts- and images-section.

{
    test: /.*\.(gif|png|jpe?g)$/,
    loader: "file-loader",
    options: {
        name: "images/[name].[ext]",
    },
},
{
    test: /.*\.(ttf|eot|woff|woff2)$/,
    loader: "file-loader",
    options: {
        name: "fonts/[name].[ext]",
    },
},
{
    test: /\.svg$/,
    loader: "file-loader",
    options: {
        name: "[name].[ext]",
        outputPath: (url, resourcePath, context) => {
            const relativePath = path.relative(context, resourcePath);

            if (/\/images\//.test(relativePath)) {
                // return target for svg images
                return `images/${url}`;
            } else if (/\/fonts\//.test(relativePath)) {
                // return target for svg fonts
                return `fonts/${url}`;
            }

            return `other/${url}`;
        },
    },
},
yolona
  • 11
  • 2