Get the most recent mtime of any Vite frontend source file. Uses os.scandir with directory-level pruning instead of rglob to avoid walking node_modules (2626 files, 420ms → 4ms). On Windows, DirEntry.stat() reuses FindFirstFile data (no extra syscall per file).
(template_dir: Path)
| 1616 | |
| 1617 | |
| 1618 | def _get_vite_source_mtime(template_dir: Path) -> float: |
| 1619 | """Get the most recent mtime of any Vite frontend source file. |
| 1620 | |
| 1621 | Uses os.scandir with directory-level pruning instead of rglob to avoid |
| 1622 | walking node_modules (2626 files, 420ms → 4ms). On Windows, DirEntry.stat() |
| 1623 | reuses FindFirstFile data (no extra syscall per file). |
| 1624 | """ |
| 1625 | max_mtime = 0.0 |
| 1626 | _EXTS = frozenset((".ts", ".js", ".html", ".css", ".json")) |
| 1627 | _SKIP = frozenset(("node_modules", "dist")) |
| 1628 | stack = [str(template_dir)] |
| 1629 | while stack: |
| 1630 | current = stack.pop() |
| 1631 | try: |
| 1632 | with os.scandir(current) as it: |
| 1633 | for entry in it: |
| 1634 | try: |
| 1635 | if entry.is_dir(follow_symlinks=False): |
| 1636 | if entry.name not in _SKIP: |
| 1637 | stack.append(entry.path) |
| 1638 | elif entry.is_file(follow_symlinks=False): |
| 1639 | _, ext = os.path.splitext(entry.name) |
| 1640 | if ext in _EXTS: |
| 1641 | mtime = entry.stat(follow_symlinks=False).st_mtime |
| 1642 | if mtime > max_mtime: |
| 1643 | max_mtime = mtime |
| 1644 | except OSError: |
| 1645 | pass |
| 1646 | except OSError: |
| 1647 | pass |
| 1648 | return max_mtime |
| 1649 | |
| 1650 | |
| 1651 | def copy_templates(output_dir: Path) -> None: |