diff --git a/src/FSCache.js b/src/FSCache.js index fdfd98166e1..8043b43e66f 100644 --- a/src/FSCache.js +++ b/src/FSCache.js @@ -4,6 +4,8 @@ const md5 = require('./utils/md5'); const objectHash = require('./utils/objectHash'); const pkg = require('../package.json'); const logger = require('./Logger'); +const glob = require('fast-glob'); +const isGlob = require('is-glob'); // These keys can affect the output, so if they differ, the cache should not match const OPTION_KEYS = ['publicURL', 'minify', 'hmr', 'target', 'scopeHoist']; @@ -30,16 +32,24 @@ class FSCache { return path.join(this.dir, hash + '.json'); } + async getLastModified(filename) { + if (isGlob(filename)) { + let files = await glob(filename, { + onlyFiles: true + }); + + return (await Promise.all( + files.map(file => fs.stat(file).then(({mtime}) => mtime.getTime())) + )).reduce((a, b) => Math.max(a, b), 0); + } + return (await fs.stat(filename)).mtime.getTime(); + } + async writeDepMtimes(data) { // Write mtimes for each dependent file that is already compiled into this asset for (let dep of data.dependencies) { if (dep.includedInParent) { - let depPath = dep.name; - if (depPath[depPath.length - 1] === '*') { - depPath = path.dirname(depPath); - } - let stats = await fs.stat(depPath); - dep.mtime = stats.mtime.getTime(); + dep.mtime = await this.getLastModified(dep.name); } } } @@ -60,8 +70,7 @@ class FSCache { // If any of them changed, invalidate. for (let dep of data.dependencies) { if (dep.includedInParent) { - let stats = await fs.stat(dep.name); - if (stats.mtime > dep.mtime) { + if ((await this.getLastModified(dep.name)) > dep.mtime) { return false; } } diff --git a/test/fs-cache.js b/test/fs-cache.js index 0f007b09a9e..ddf3fcffd8a 100644 --- a/test/fs-cache.js +++ b/test/fs-cache.js @@ -136,4 +136,31 @@ describe('FSCache', () => { }); }); }); + + it('should invalidate cache if a wildcard dependency changes', async () => { + const cache = new FSCache({cacheDir: cachePath}); + const wildcardPath = path.join(inputPath, 'wildcard'); + await fs.mkdirp(wildcardPath); + await ncp(__dirname + '/integration/fs', wildcardPath); + const filePath = path.join(wildcardPath, 'test.txt'); + + await cache.write(__filename, { + dependencies: [ + { + includedInParent: true, + name: path.join(wildcardPath, '*') + } + ] + }); + + let cached = await cache.read(__filename); + assert(cached !== null); + + // delay and update dependency + await sleep(1000); + await fs.writeFile(filePath, 'world'); + + cached = await cache.read(__filename); + assert.equal(cached, null); + }); });