johnagan / clean-webpack-plugin

A webpack plugin to remove your build folder(s) before building
MIT License
1.96k stars 136 forks source link

Unexpected removal of `background-image` files #159

Open aaaatpdev opened 4 years ago

aaaatpdev commented 4 years ago

Steps to reproduce

  1. cd /path/to/project

  2. npm init -y

  3. npm install -D webpack webpack-cli style-loader css-loader mini-css-extract-plugin file-loader clean-webpack-plugin

  4. Code to reproduce

package.json scripts:

    "build": "webpack --mode production",
    "dev": "webpack --mode development --watch",

webpack.config.js:

const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

var config = {
  entry: {
    main: './src/main.js',
  },
  output: {
    path: path.resolve(__dirname, 'public'),
    filename: 'build/app.js',
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          MiniCssExtractPlugin.loader,
          'css-loader',
        ],
      },
      {
        test: /\.(png|jpe?g|gif|svg)$/,
        loader: 'file-loader',
        options: {
          outputPath: 'build/images',
          name: '[name].[hash:7].[ext]',
        },
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'build/app.css',
    }),
    new CleanWebpackPlugin({
      cleanOnceBeforeBuildPatterns: [ 'build/**/*', ],
    }),
  ],
}

module.exports = config

src/assets/images/bg.png: any dummy image (e.g. https://dummyimage.com/600x400/000/fff).

src/css/app.css:

.whatever {
  background-image: url('../assets/images/bg.png');
}

src/main.js:

import './css/app.css'
  1. npm run dev

  2. Save src/css/app.css

Observed behavior

bg.png unexpectedly disappears (from public/build/images).

kaligrafy commented 4 years ago

Same problem here, all images are deleted and never recreated. It happens only in watch mode. As soon as a file is modified, the plugin does refresh css and js, but erases images.

chrisblossom commented 4 years ago

You either need to set cleanStaleWebpackAssets: false or add negative patterns to cleanAfterEveryBuildPatterns: ['!*.png'].

aaaatpdev commented 4 years ago

@chrisblossom, those are possible workarounds. Is there any problem to keep background-image files alive?

chrisblossom commented 4 years ago

@aaaatpdev Please clarify what you are asking. Are you asking if it is an issue to keep stale assets on disk? If so, that is completely up to you.

marekdedic commented 4 years ago

I'm experiencing this issue as well:

When I do a regular "production" build, All my files get copied over correctly. However, on "watch" builds, the files get copied over on the initial build, but on any change, all the files copied over by copy-webbpack-plugin get deleted (and are not copied over again).

Probably related to webpack-contrib/copy-webpack-plugin#385, webpack-contrib/copy-webpack-plugin#261 and statianzo/webpack-livereload-plugin#53

aaaatpdev commented 4 years ago

@chrisblossom, i mean that the described behavior is unexpected (background-image files aren't stale assets) and should be fixed. Or maybe i'm missing something?

jvandesande commented 4 years ago

I have the same issue with fonts that are extracted via the minicss-extract-plugin.

mya-ake commented 4 years ago

I have the same issue. I think that it can be avoided if the ignore pattern can be set.

I was able to work around it by setting cleanAfterEveryBuildPatterns.

Amaimersion commented 4 years ago

You can use remove-files-webpack-plugin for this.

If i'm get it right: in watch mode need to delete all except files which in public/build/images folder. Here is solution with that plugin.

Config:

plugins: [
  new RemovePlugin({
    // in watch mode (only in "watch" mode, not "normal" mode!) 
    // remove all files, folders and subfolders from `./public` except 
    // `./public/build/images` folder (and files which included in that folder).
    watch: {
      root: './public',
      test: [
        {
          folder: '.',
          method: () => true,
          recursive: true
        }
      ],
      exclude: [
        './build/images'
      ]
    }
  })
]

Note: i'm the creator of this plugin, so, it's a bit of an advertisement.

Xerrion commented 4 years ago

I have the same issue. ~I think that it can be avoided if the ignore pattern can be set.~

I was able to work around it by setting cleanAfterEveryBuildPatterns.

@mya-ake Could you clarify your workaround?

stock-dd commented 3 years ago

You can use remove-files-webpack-plugin for this.

If i'm get it right: in watch mode need to delete all except files which in public/build/images folder. Here is solution with that plugin.

Config:

plugins: [
  new RemovePlugin({
    // in watch mode (only in "watch" mode, not "normal" mode!) 
    // remove all files, folders and subfolders from `./public` except 
    // `./public/build/images` folder (and files which included in that folder).
    watch: {
      root: './public',
      test: [
        {
          folder: '.',
          method: () => true,
          recursive: true
        }
      ],
      exclude: [
        './build/images'
      ]
    }
  })
]

Note: i'm the creator of this plugin, so, it's a bit of an advertisement.

I tried to use your plugin, but bump into the same problem. I.e. adding a folder to the exclude array still insists on removing the folder's contents. Props for the efforts though.

Edit: I managed to get desired result still by restructuring my build folder a bit and setting recursive to false.

luke-denton-aligent commented 3 years ago

I think I've been having the same issue, although mine was with sw.js. Running this plugin would continually remove the sw.js file from the build folder.

Stepping through the plugin, my file was being removed as part of handleInitial, and using the cleanOnceBeforeBuildPatterns of ['**/*'] (which is the default value if this property isn't provided in the config object).

For my scenario, I've just set cleanOnceBeforeBuildPatterns to [] in my config object, and now my sw.js file isn't being deleted.

SamanthaAdrichem commented 3 years ago

I've also got this issue, it either doesn't clean anything anymore or it randomly cleans everything that the copy plugin provided (for example the .htaccess to rewrite to index.html) and it's random. It suddenly decides to do so.

We've got the following config which means it shouldn't do it. But still sometimes randomly it decides to clean all the files provided by the copy plugin

        new CleanWebpackPlugin({
            cleanAfterEveryBuildPatterns: [],
            cleanStaleWebpackAssets: false,
            verbose: true,
            dry: false,
        }),

we're on version 3.0.0. Webpack 4, upgrading to 5 to see if that helps

marekdedic commented 3 years ago

Honestly, my solution was to go to gulp for this kind of stuff and use gulp-webpack. In my (albeit limited) experience, webpack as a "task runner" just isn't that great. So for these kinds of tasks (copying config files etc.) I use gulp and when I want a bundler, I call webpack with gulp-webpack.

Ofc, this is just a personal preference, ymmv...

Kukkimonsuta commented 3 years ago

I can confirm @luke-denton-aligent findings where cleanOnceBeforeBuildPatterns sometimes (typically after some errors occurred in previous builds and were now fixed) removes (almost?) everything at weird times (after whole bunch of successful rebuilds in watch mode). I'm having trouble isolating the issue and can't invest more time into it right now, however cleanOnceBeforeBuildPatterns: [] did fix it in our case.