Repository: webpack-contrib/copy-webpack-plugin (js)

Issue:
Conflict with clean-webpack-plugin?
When I use `clean-webpack-plugin` with `copy-webpack-plugin`, I got `ERROR in [copy-webpack-plugin] unable to locate 'dist/manage.bundle.js' at '/Users/XXX/Workspace/project/dist/manage.bundle.js'`, but when I remove `clean-webpack-plugin`, it works fine, what the problem is?

```javascript
    plugins: [
        new CleanWebpackPlugin(['dist']),
        new UglifyJSPlugin({
            sourceMap: true
        }),
        new CopyWebpackPlugin([
            {
                from: 'dist/manage.bundle.js',
                to: '../public/js/'
            }
        ], { debug: 'info' })
    ],
```

Pull request description:
Fix persist assets between rebuilds
<!--
  HOLY CRAP a Pull Request. We ❤️ those!

  If you remove or skip this template, you'll make the 🐼 sad and the mighty god
  of Github will appear and pile-drive the close button from a great height
  while making animal noises.

  Please place an x (no spaces!) in all [ ] that apply
-->

This PR contains a:

- [x] **bugfix**
- [ ] new **feature**
- [x] **code refactor**
- [x] **test update** <!-- if bug or feature is checked, this should be too -->
- [ ] **typo fix**
- [ ] **metadata update**

### Motivation / Use-Case

fixes #360 and fixes #261

### Breaking Changes

Yes

### Additional Info

We should always have persist assets between rebuilds, the `force` option will be removed too

Patch:
diff --git a/README.md b/README.md
index 212ac7a..bb359e1 100644
--- a/README.md
+++ b/README.md
@@ -499,11 +499,10 @@ module.exports = {
 
 ### Options
 
-|                Name                 |    Type     |          Default           | Description                                                                                                                                       |
-| :---------------------------------: | :---------: | :------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------ |
-|         [`ignore`](#ignore)         |  `{Array}`  |            `[]`            | Array of globs to ignore (applied to `from`)                                                                                                      |
-|        [`context`](#context)        | `{String}`  | `compiler.options.context` | A path that determines how to interpret the `from` path, shared for all patterns                                                                  |
-| [`copyUnmodified`](#copyunmodified) | `{Boolean}` |          `false`           | Copies files, regardless of modification when using watch or `webpack-dev-server`. All files are copied on first build, regardless of this option |
+|         Name          |    Type    |          Default           | Description                                                                      |
+| :-------------------: | :--------: | :------------------------: | :------------------------------------------------------------------------------- |
+|  [`ignore`](#ignore)  | `{Array}`  |            `[]`            | Array of globs to ignore (applied to `from`)                                     |
+| [`context`](#context) | `{String}` | `compiler.options.context` | A path that determines how to interpret the `from` path, shared for all patterns |
 
 #### `ignore`
 
@@ -529,20 +528,6 @@ module.exports = {
 };
 ```
 
-#### `copyUnmodified`
-
-Copies files, regardless of modification when using watch or `webpack-dev-server`. All files are copied on first build, regardless of this option.
-
-> ℹ️ By default, we only copy **modified** files during a `webpack --watch` or `webpack-dev-server` build. Setting this option to `true` will copy all files.
-
-**webpack.config.js**
-
-```js
-module.exports = {
-  plugins: [new CopyPlugin([...patterns], { copyUnmodified: true })],
-};
-```
-
 ## Contributing
 
 Please take a moment to read our contributing guidelines if you haven't yet done so.
diff --git a/src/index.js b/src/index.js
index 4e976ff..6c1396d 100644
--- a/src/index.js
+++ b/src/index.js
@@ -22,7 +22,6 @@ class CopyPlugin {
   apply(compiler) {
     const fileDependencies = new Set();
     const contextDependencies = new Set();
-    const written = {};
 
     let context;
 
@@ -44,14 +43,12 @@ class CopyPlugin {
       const globalRef = {
         logger,
         compilation,
-        written,
         fileDependencies,
         contextDependencies,
         context,
         inputFileSystem: compiler.inputFileSystem,
         output: compiler.options.output.path,
         ignore: this.options.ignore || [],
-        copyUnmodified: this.options.copyUnmodified,
         concurrency: this.options.concurrency,
       };
 
diff --git a/src/options.json b/src/options.json
index 0a00044..fe7582f 100644
--- a/src/options.json
+++ b/src/options.json
@@ -101,12 +101,6 @@
         },
         "ignore": {
           "type": "array"
-        },
-        "logLevel": {
-          "type": "string"
-        },
-        "copyUnmodified": {
-          "type": "boolean"
         }
       }
     }
diff --git a/src/postProcessPattern.js b/src/postProcessPattern.js
index cf62bcc..bc95494 100644
--- a/src/postProcessPattern.js
+++ b/src/postProcessPattern.js
@@ -15,14 +15,7 @@ import { stat, readFile } from './utils/promisify';
 /* eslint-disable no-param-reassign */
 
 export default function postProcessPattern(globalRef, pattern, file) {
-  const {
-    logger,
-    compilation,
-    fileDependencies,
-    written,
-    inputFileSystem,
-    copyUnmodified,
-  } = globalRef;
+  const { logger, compilation, fileDependencies, inputFileSystem } = globalRef;
 
   logger.debug(`getting stats for '${file.absoluteFrom}' to write to assets`);
 
@@ -148,30 +141,7 @@ export default function postProcessPattern(globalRef, pattern, file) {
         return content;
       })
       .then((content) => {
-        const hash = loaderUtils.getHashDigest(content);
         const targetPath = normalizePath(file.webpackTo);
-        const targetAbsolutePath = normalizePath(file.absoluteFrom);
-
-        if (
-          !copyUnmodified &&
-          written[targetPath] &&
-          written[targetPath][targetAbsolutePath] &&
-          written[targetPath][targetAbsolutePath] === hash
-        ) {
-          logger.log(
-            `skipping '${file.webpackTo}', because content hasn't changed`
-          );
-
-          return;
-        }
-
-        logger.debug(`adding '${file.webpackTo}' for tracking content changes`);
-
-        if (!written[targetPath]) {
-          written[targetPath] = {};
-        }
-
-        written[targetPath][targetAbsolutePath] = hash;
 
         if (compilation.assets[targetPath] && !file.force) {
           logger.log(`skipping '${file.webpackTo}', because it already exists`);


Test patch:
diff --git a/test/CopyPlugin.test.js b/test/CopyPlugin.test.js
index 1725a31..9acb361 100644
--- a/test/CopyPlugin.test.js
+++ b/test/CopyPlugin.test.js
@@ -385,9 +385,9 @@ describe('apply function', () => {
         .catch(done);
     });
 
-    it('only include files that have changed', (done) => {
+    it('should include files that have changed when `from` is a file', (done) => {
       runChange({
-        expectedAssetKeys: ['tempfile1.txt'],
+        expectedAssetKeys: ['tempfile1.txt', 'tempfile2.txt'],
         newFileLoc1: path.join(FIXTURES_DIR, 'watch', 'tempfile1.txt'),
         newFileLoc2: path.join(FIXTURES_DIR, 'watch', 'tempfile2.txt'),
         patterns: [
@@ -403,9 +403,9 @@ describe('apply function', () => {
         .catch(done);
     });
 
-    it('only include files that have changed', (done) => {
+    it('should include all files when `from` is a directory', (done) => {
       runChange({
-        expectedAssetKeys: ['tempfile1.txt'],
+        expectedAssetKeys: ['.gitkeep', 'tempfile1.txt', 'tempfile2.txt'],
         newFileLoc1: path.join(
           FIXTURES_DIR,
           'watch',
@@ -428,37 +428,9 @@ describe('apply function', () => {
         .catch(done);
     });
 
-    it('include all files if copyUnmodified is true', (done) => {
+    it('should include all files when `from` is a glob', (done) => {
       runChange({
-        expectedAssetKeys: ['tempfile1.txt', 'tempfile2.txt', '.gitkeep'],
-        newFileLoc1: path.join(
-          FIXTURES_DIR,
-          'watch',
-          'directory',
-          'tempfile1.txt'
-        ),
-        newFileLoc2: path.join(
-          FIXTURES_DIR,
-          'watch',
-          'directory',
-          'tempfile2.txt'
-        ),
-        options: {
-          copyUnmodified: true,
-        },
-        patterns: [
-          {
-            from: 'directory',
-          },
-        ],
-      })
-        .then(done)
-        .catch(done);
-    });
-
-    it('copy only changed files', (done) => {
-      runChange({
-        expectedAssetKeys: ['dest1/tempfile1.txt'],
+        expectedAssetKeys: ['dest1/tempfile1.txt', 'dest1/tempfile2.txt'],
         newFileLoc1: path.join(
           FIXTURES_DIR,
           'watch',
@@ -483,9 +455,14 @@ describe('apply function', () => {
         .catch(done);
     });
 
-    it('copy only changed files (multiple patterns)', (done) => {
+    it('should include all files when multiple patterns used', (done) => {
       runChange({
-        expectedAssetKeys: ['dest1/tempfile1.txt', 'dest2/tempfile1.txt'],
+        expectedAssetKeys: [
+          'dest1/tempfile1.txt',
+          'dest1/tempfile2.txt',
+          'dest2/tempfile1.txt',
+          'dest2/tempfile2.txt',
+        ],
         newFileLoc1: path.join(
           FIXTURES_DIR,
           'watch',
@@ -515,11 +492,12 @@ describe('apply function', () => {
         .catch(done);
     });
 
-    it('copy only changed files (multiple patterns with difference context)', (done) => {
+    it('should include all files when multiple patterns with difference contexts', (done) => {
       runChange({
         expectedAssetKeys: [
           'dest1/tempfile1.txt',
           'dest2/directory/tempfile1.txt',
+          'dest2/tempfile2.txt',
         ],
         newFileLoc1: path.join(
           FIXTURES_DIR,
@@ -543,60 +521,5 @@ describe('apply function', () => {
         .then(done)
         .catch(done);
     });
-
-    it('copy only changed files (multiple patterns with difference context 1)', (done) => {
-      runChange({
-        expectedAssetKeys: [
-          'dest1/directory/tempfile1.txt',
-          'dest2/tempfile1.txt',
-        ],
-        newFileLoc1: path.join(
-          FIXTURES_DIR,
-          'watch',
-          'directory',
-          'tempfile1.txt'
-        ),
-        newFileLoc2: path.join(FIXTURES_DIR, 'watch', 'tempfile2.txt'),
-        patterns: [
-          {
-            from: '**/*.txt',
-            to: 'dest1',
-          },
-          {
-            context: 'directory',
-            from: '**/*.txt',
-            to: 'dest2',
-          },
-        ],
-      })
-        .then(done)
-        .catch(done);
-    });
-
-    it('copy only changed files (multiple patterns with difference context 2)', (done) => {
-      runChange({
-        expectedAssetKeys: ['dest1/tempfile1.txt'],
-        newFileLoc1: path.join(FIXTURES_DIR, 'watch', 'tempfile1.txt'),
-        newFileLoc2: path.join(
-          FIXTURES_DIR,
-          'watch',
-          'directory',
-          'tempfile2.txt'
-        ),
-        patterns: [
-          {
-            from: '**/*.txt',
-            to: 'dest1',
-          },
-          {
-            context: 'directory',
-            from: '**/*.txt',
-            to: 'dest2',
-          },
-        ],
-      })
-        .then(done)
-        .catch(done);
-    });
   });
 });