@@ -37,8 +37,58 @@ class CopyPlugin {
3737 this . options = options . options || { } ;
3838 }
3939
40+ static async createSnapshot ( compilation , startTime , dependency ) {
41+ if ( ! compilation . fileSystemInfo ) {
42+ return ;
43+ }
44+
45+ // eslint-disable-next-line consistent-return
46+ return new Promise ( ( resolve , reject ) => {
47+ compilation . fileSystemInfo . createSnapshot (
48+ startTime ,
49+ [ dependency ] ,
50+ // eslint-disable-next-line no-undefined
51+ undefined ,
52+ // eslint-disable-next-line no-undefined
53+ undefined ,
54+ null ,
55+ ( error , snapshot ) => {
56+ if ( error ) {
57+ reject ( error ) ;
58+
59+ return ;
60+ }
61+
62+ resolve ( snapshot ) ;
63+ }
64+ ) ;
65+ } ) ;
66+ }
67+
68+ static async checkSnapshotValid ( compilation , snapshot ) {
69+ if ( ! compilation . fileSystemInfo ) {
70+ return ;
71+ }
72+
73+ // eslint-disable-next-line consistent-return
74+ return new Promise ( ( resolve , reject ) => {
75+ compilation . fileSystemInfo . checkSnapshotValid (
76+ snapshot ,
77+ ( error , isValid ) => {
78+ if ( error ) {
79+ reject ( error ) ;
80+
81+ return ;
82+ }
83+
84+ resolve ( isValid ) ;
85+ }
86+ ) ;
87+ } ) ;
88+ }
89+
4090 // eslint-disable-next-line class-methods-use-this
41- async runPattern ( compiler , compilation , logger , inputPattern ) {
91+ static async runPattern ( compiler , compilation , logger , cache , inputPattern ) {
4292 const pattern =
4393 typeof inputPattern === 'string'
4494 ? { from : inputPattern }
@@ -49,7 +99,6 @@ class CopyPlugin {
4999 pattern . to = path . normalize (
50100 typeof pattern . to !== 'undefined' ? pattern . to : ''
51101 ) ;
52-
53102 pattern . context = path . normalize (
54103 typeof pattern . context !== 'undefined'
55104 ? ! path . isAbsolute ( pattern . context )
@@ -266,64 +315,109 @@ class CopyPlugin {
266315 compilation . fileDependencies . add ( file . absoluteFrom ) ;
267316 }
268317
269- logger . debug ( `reading " ${ file . absoluteFrom } " to write to assets` ) ;
318+ let source ;
270319
271- let data ;
320+ if ( cache ) {
321+ const cacheEntry = await cache . getPromise ( file . relativeFrom , null ) ;
272322
273- try {
274- data = await readFile ( inputFileSystem , file . absoluteFrom ) ;
275- } catch ( error ) {
276- compilation . errors . push ( error ) ;
323+ if ( cacheEntry ) {
324+ const isValidSnapshot = await CopyPlugin . checkSnapshotValid (
325+ compilation ,
326+ cacheEntry . snapshot
327+ ) ;
277328
278- return ;
329+ if ( isValidSnapshot ) {
330+ ( { source } = cacheEntry ) ;
331+ }
332+ }
279333 }
280334
281- if ( pattern . transform ) {
282- logger . log ( `transforming content for "${ file . absoluteFrom } "` ) ;
283-
284- if ( pattern . cacheTransform ) {
285- const cacheDirectory = pattern . cacheTransform . directory
286- ? pattern . cacheTransform . directory
287- : typeof pattern . cacheTransform === 'string'
288- ? pattern . cacheTransform
289- : findCacheDir ( { name : 'copy-webpack-plugin' } ) || os . tmpdir ( ) ;
290- let defaultCacheKeys = {
291- version,
292- transform : pattern . transform ,
293- contentHash : crypto . createHash ( 'md4' ) . update ( data ) . digest ( 'hex' ) ,
294- } ;
295-
296- if ( typeof pattern . cacheTransform . keys === 'function' ) {
297- defaultCacheKeys = await pattern . cacheTransform . keys (
298- defaultCacheKeys ,
299- file . absoluteFrom
300- ) ;
301- } else {
302- defaultCacheKeys = {
303- ...defaultCacheKeys ,
304- ...pattern . cacheTransform . keys ,
335+ if ( ! source ) {
336+ let startTime ;
337+
338+ if ( cache ) {
339+ startTime = Date . now ( ) ;
340+ }
341+
342+ logger . debug ( `reading "${ file . absoluteFrom } " to write to assets` ) ;
343+
344+ let data ;
345+
346+ try {
347+ data = await readFile ( inputFileSystem , file . absoluteFrom ) ;
348+ } catch ( error ) {
349+ compilation . errors . push ( error ) ;
350+
351+ return ;
352+ }
353+
354+ if ( pattern . transform ) {
355+ logger . log ( `transforming content for "${ file . absoluteFrom } "` ) ;
356+
357+ if ( pattern . cacheTransform ) {
358+ const cacheDirectory = pattern . cacheTransform . directory
359+ ? pattern . cacheTransform . directory
360+ : typeof pattern . cacheTransform === 'string'
361+ ? pattern . cacheTransform
362+ : findCacheDir ( { name : 'copy-webpack-plugin' } ) || os . tmpdir ( ) ;
363+ let defaultCacheKeys = {
364+ version,
365+ transform : pattern . transform ,
366+ contentHash : crypto
367+ . createHash ( 'md4' )
368+ . update ( data )
369+ . digest ( 'hex' ) ,
305370 } ;
306- }
307371
308- const cacheKeys = serialize ( defaultCacheKeys ) ;
372+ if ( typeof pattern . cacheTransform . keys === 'function' ) {
373+ defaultCacheKeys = await pattern . cacheTransform . keys (
374+ defaultCacheKeys ,
375+ file . absoluteFrom
376+ ) ;
377+ } else {
378+ defaultCacheKeys = {
379+ ...defaultCacheKeys ,
380+ ...pattern . cacheTransform . keys ,
381+ } ;
382+ }
309383
310- try {
311- const result = await cacache . get ( cacheDirectory , cacheKeys ) ;
384+ const cacheKeys = serialize ( defaultCacheKeys ) ;
312385
313- logger . debug (
314- `getting cached transformation for "${ file . absoluteFrom } "`
315- ) ;
386+ try {
387+ const result = await cacache . get ( cacheDirectory , cacheKeys ) ;
316388
317- ( { data } = result ) ;
318- } catch ( _ignoreError ) {
319- data = await pattern . transform ( data , file . absoluteFrom ) ;
389+ logger . debug (
390+ `getting cached transformation for " ${ file . absoluteFrom } "`
391+ ) ;
320392
321- logger . debug ( `caching transformation for "${ file . absoluteFrom } "` ) ;
393+ ( { data } = result ) ;
394+ } catch ( _ignoreError ) {
395+ data = await pattern . transform ( data , file . absoluteFrom ) ;
396+
397+ logger . debug (
398+ `caching transformation for "${ file . absoluteFrom } "`
399+ ) ;
322400
323- await cacache . put ( cacheDirectory , cacheKeys , data ) ;
401+ await cacache . put ( cacheDirectory , cacheKeys , data ) ;
402+ }
403+ } else {
404+ data = await pattern . transform ( data , file . absoluteFrom ) ;
324405 }
325- } else {
326- data = await pattern . transform ( data , file . absoluteFrom ) ;
406+ }
407+
408+ source = new RawSource ( data ) ;
409+
410+ if ( cache ) {
411+ const snapshot = await CopyPlugin . createSnapshot (
412+ compilation ,
413+ startTime ,
414+ file . relativeFrom
415+ ) ;
416+
417+ await cache . storePromise ( file . relativeFrom , null , {
418+ source,
419+ snapshot,
420+ } ) ;
327421 }
328422 }
329423
@@ -349,7 +443,7 @@ class CopyPlugin {
349443 { resourcePath : file . absoluteFrom } ,
350444 file . webpackTo ,
351445 {
352- content : data ,
446+ content : source . source ( ) ,
353447 context : pattern . context ,
354448 }
355449 ) ;
@@ -374,7 +468,7 @@ class CopyPlugin {
374468 }
375469
376470 // eslint-disable-next-line no-param-reassign
377- file . data = data ;
471+ file . source = source ;
378472 // eslint-disable-next-line no-param-reassign
379473 file . targetPath = normalizePath ( file . webpackTo ) ;
380474 // eslint-disable-next-line no-param-reassign
@@ -392,6 +486,10 @@ class CopyPlugin {
392486
393487 compiler . hooks . thisCompilation . tap ( pluginName , ( compilation ) => {
394488 const logger = compilation . getLogger ( 'copy-webpack-plugin' ) ;
489+ const cache = compilation . getCache
490+ ? compilation . getCache ( 'CopyWebpackPlugin' )
491+ : // eslint-disable-next-line no-undefined
492+ undefined ;
395493
396494 compilation . hooks . additionalAssets . tapAsync (
397495 'copy-webpack-plugin' ,
@@ -404,7 +502,13 @@ class CopyPlugin {
404502 assets = await Promise . all (
405503 this . patterns . map ( ( item ) =>
406504 limit ( async ( ) =>
407- this . runPattern ( compiler , compilation , logger , item )
505+ CopyPlugin . runPattern (
506+ compiler ,
507+ compilation ,
508+ logger ,
509+ cache ,
510+ item
511+ )
408512 )
409513 )
410514 ) ;
@@ -426,12 +530,10 @@ class CopyPlugin {
426530 absoluteFrom,
427531 targetPath,
428532 webpackTo,
429- data ,
533+ source ,
430534 force,
431535 } = asset ;
432536
433- const source = new RawSource ( data ) ;
434-
435537 // For old version webpack 4
436538 /* istanbul ignore if */
437539 if ( typeof compilation . emitAsset !== 'function' ) {
0 commit comments