Почему CopyWebpackPlugin работает не правильно?
В fileloader можно передать параметр outputPath, который принимает функцию, которая возвращает путь для файла. Вот так сделано у меня. url это имя файла с расширением, resourcePath абсолютный путь к обрабатываемому файлу, context это еще один параметр, который вы можете задать (а можете и не задавать), у меня images, по названию папки, куда я хочу складывать изображения. С помощью регулярного выражения проверяется resourcePath, если совпадает, то кидает файл в указанную папку. Если нет совпадений, то кидает в папку по-умолчанию, которая указана в последнем return. Попробуйте, возможно это то, что вы ищите.{
          test: /\.(png|jpe?g|gif|svg)$/,
          use: [
            {
              loader: 'file-loader',
              options: {
                name: '[name].[ext]',
                context: 'images',
                publicPath: (url, resourcePath, context) => {
                  if (/decoration/.test(resourcePath)) {
                    return `../${context}/decoration/${url}`;
                  }

                  return `${context}/${url}`;
                },
                outputPath: (url, resourcePath, context) => {
                  if (/decoration/.test(resourcePath)) {
                    return `${context}/decoration/${url}`;
                  }

                  return `${context}/${url}`;
                },
              },
            },
          ],
        },
Во-первых CopyWebpackPlugin работает правильно, он копирует что вам нужно
Во-вторых https://webpack.js.org/plugins/copy-webpack-plugin...
Если вы хотите чтоб ваш файл через file-loader был в img то измените генерируемое имяname: 'img/[name].[ext]'