Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e127298
feat(fs): Enhance API for incremental builds
RandomByte May 29, 2026
951206d
feat(project): Add SQLite-backed build cache storage
RandomByte May 29, 2026
f6da801
feat(project): Add hash-tree-based resource change tracking
RandomByte May 29, 2026
51ec9c3
feat(project): Add resource request graph and per-stage/task caches
RandomByte May 29, 2026
b8b3cf0
feat(project): Implement differential builds in ProjectBuilder/TaskRu…
RandomByte May 29, 2026
05f4ddb
feat(project): Add BuildServer for watch mode and incremental rebuilds
RandomByte May 29, 2026
b4f6890
feat(builder): Adapt build tasks for incremental builds
RandomByte May 29, 2026
77792a9
feat(server): Integrate BuildServer into dev server
RandomByte May 29, 2026
c0003a3
refactor: Support referencing legacy middlewares in UI5 CLI middlewar…
RandomByte May 29, 2026
325a549
feat(cli): Add --cache option for build and serve commands (#1368)
maxreichmann May 29, 2026
cbc1368
feat(logger): Add differential build logging support
RandomByte May 29, 2026
03ffb52
test(project): Add incremental build test suite
RandomByte May 29, 2026
e3c1715
deps: Update lockfile and e2e build test for incremental builds
RandomByte May 29, 2026
a7c6619
docs: Add Claude skills for incremental build and ui5-fs
RandomByte May 29, 2026
4314cdb
test(project): De-flake "Serve library" and document StageCache abort…
RandomByte May 29, 2026
0555fd6
refactor(project): Discard unflushed StageCache entries on aborted bu…
RandomByte May 29, 2026
b45f224
refactor(project): Add ui5DataDir option to graph.serve()
RandomByte May 29, 2026
1063b89
refactor(project): Recover from non-abort build errors instead of dea…
RandomByte May 29, 2026
5d031d3
refactor(server): Tolerate missing error callback on serve()
RandomByte May 29, 2026
ef60019
test: Isolate per-test build cache via ui5DataDir
RandomByte May 29, 2026
2405f98
test(project): Cover build server recovery after non-abort errors
RandomByte May 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .claude/skills/incremental-build/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: incremental-build
description: >
Work on the incremental (delta) build system in @ui5/project: build caching,
resource indexing, hash trees, stage caching, build server, file watching,
task execution caching, and delta builds.
when_to_use: >
TRIGGER when: the user asks about or wants to modify code related to incremental builds,
build caching, resource indexing, hash trees, stage caching, build server, file watching,
task execution caching, delta builds, resource tags in build context, or any component
listed in the Component Map in architecture.md.
DO NOT TRIGGER when: the user is working on unrelated CLI commands, general tooling,
or non-build features.
user-invocable: true
---

# Incremental Build Skill

You are working on the incremental (delta) build system in `@ui5/project`. Read `architecture.md` in this skill directory for the full architecture reference, including the component map, key flows, caching architecture, and data structures. Read `performance-investigation.md` for guidance on profiling builds, reading perf logs, and known performance peculiarities.

## Guidelines for Working on This Code

1. **Always read the source file before modifying it.** The Component Map in `architecture.md` tells you where each piece lives.
2. **Understand the cache flow direction.** Changes propagate: source change -> index update -> signature change -> cache miss -> task re-execution.
3. **Be careful with tag side effects.** `getTags()` is not a pure read -- it triggers lazy tag application. Avoid calling it in unexpected contexts.
4. **Respect abort signals.** Any long-running operation should check `signal?.throwIfAborted()` periodically.
5. **Test with incremental rebuilds.** A single build passing is not enough; the interesting bugs appear on the second and third builds after file changes.
6. **Watch for stale stage readers after abort.** If a build is aborted, stage writers may contain partial results that shadow source files.
7. **Signature stability matters.** Any change to how hashes are computed (e.g., adding new fields to hash input) invalidates all existing caches.
8. **SharedHashTree operations must go through TreeRegistry.** Never mutate a SharedHashTree directly; always schedule via the registry and flush.

## Known Constraints

- `StageCache` (in-memory) has no `clear()` method -- stage entries persist for the lifetime of the `ProjectBuildCache` instance
- `ProjectBuildContext` instances (including their caches) are reused across sequential builds of the same project within a session
- `resource.getTags()` has side effects: it triggers `#applyCachedResourceTags()` and creates `MonitoredResourceTagCollection` instances, which modify tag collection state. This means calling `getTags()` during hash tree operations (e.g., in `TreeRegistry.flush()`) can affect the stage pipeline state.
- `updateProjectIndices` uses `project.getReader()` (stage pipeline reader) to read resources. After an aborted build, stage writers may contain in-memory resources that shadow updated source content, causing stale reads.
- `getSourcePaths()` and `getVirtualPath()` are NOT consistent with `getSourceReader()` for all project types. Module has no `getVirtualPath()` (base class throws). ThemeLibrary's `getSourcePaths()` returns only `[src/]` and `getVirtualPath()` only maps `src/`, but `_getReader()` also includes `test/` when `_testPathExists`. Any optimization that replaces `sourceReader.byGlob()` with direct filesystem enumeration via `getSourcePaths()` + `getVirtualPath()` must handle these mismatches.
374 changes: 374 additions & 0 deletions .claude/skills/incremental-build/architecture.md

Large diffs are not rendered by default.

378 changes: 378 additions & 0 deletions .claude/skills/incremental-build/performance-investigation.md

Large diffs are not rendered by default.

67 changes: 67 additions & 0 deletions .claude/skills/ui5-fs/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
name: ui5-fs
description: >
Work on the @ui5/fs package: the virtual file system abstraction layer providing
Resource, Adapters (FileSystem, Memory), Reader Collections (ReaderCollection,
ReaderCollectionPrioritized, DuplexCollection, WriterCollection), specialized readers
(Filter, Link, Proxy), resource tagging, monitoring, and the resourceFactory API.
when_to_use: >
TRIGGER when: the user asks about or wants to modify code related to @ui5/fs,
the virtual file system, resources, adapters, reader collections, writer collections,
DuplexCollection, resourceFactory, ResourceTagCollection, MonitoredReader, fsInterface,
ResourceFacade, or any file within packages/fs/.
DO NOT TRIGGER when: the user is working on builder tasks/processors, CLI commands,
server middleware, or project graph resolution that does not touch the FS layer.
user-invocable: true
---

# @ui5/fs Skill

You are working on the `@ui5/fs` package — the virtual file system abstraction layer for UI5 CLI. Read `architecture.md` in this skill directory for the full architecture reference, including the class hierarchy, API surface, adapter internals, and collection patterns.

## Package Location

Source: `packages/fs/lib/`
Tests: `packages/fs/test/lib/`
Fixtures: `packages/fs/test/fixtures/`

## Guidelines for Working on This Code

1. **Always read the source file before modifying it.** The Component Map in `architecture.md` tells you where each piece lives.
2. **Understand the content type state machine.** Resources have internal content types (BUFFER, STREAM, FACTORY, DRAINED_STREAM, IN_TRANSFORMATION) with strict transitions. Never bypass `modifyStream()` for content transformations — it handles mutex locking and state management.
3. **Respect the mutex.** Resource content access is protected by `async-mutex`. Concurrent `getBuffer()` / `getString()` calls are safe, but `modifyStream()` acquires an exclusive lock. Never hold a reference to content across an `await` that could trigger a transformation.
4. **Virtual paths are POSIX-absolute.** All virtual paths must be absolute POSIX paths (start with `/`). Base paths must end with `/`. Adapters normalize patterns relative to their `virBasePath`.
5. **Content parameters are mutually exclusive.** When creating a Resource, only one of `buffer`, `string`, `stream`, `createStream`, or `createBuffer` can be provided. The `createBuffer`/`createStream` factories enable lazy loading.
6. **byGlob randomizes result order.** `AbstractReader.byGlob()` intentionally shuffles results to prevent consumers from relying on ordering. Do not assume or depend on glob result order.
7. **Clone semantics matter.** Resources are cloned on retrieval from adapters. `resource.clone()` creates an independent copy including content. When modifying resources from collections, understand whether you're working on the original or a clone.
8. **ResourceFacade is immutable.** `ResourceFacade.setPath()` throws. The facade wraps a resource with a different virtual path (used by Link reader). Use `getOriginalPath()` to get the underlying path.
9. **Tag format is strict.** Tags follow the pattern `"namespace:Name"` — namespace is lowercase alphanumeric, name is PascalCase. Tags are validated on set. Use `ResourceTagCollection` or `MonitoredResourceTagCollection` for tag operations.
10. **Test with both FileSystem and Memory adapters.** Behavior can differ between adapters (e.g., FileSystem uses `globby` while Memory uses `micromatch`; FileSystem has lazy content loading via factories, Memory clones on read).

## Known Constraints

- `Resource.getStream()` is deprecated — use `getStreamAsync()` or `getBuffer()` / `getString()` instead. The deprecation warning is only logged once per process.
- `Resource.getStatInfo()` is deprecated — use `getLastModified()`, `getSize()`, `getInode()` instead.
- FileSystem adapter's `write()` uses `fs.copyFile` for unmodified resources (optimization). It also detects same-source-same-target writes and skips them, but switches to buffer-based writes if the content was modified (to avoid stream read-during-write conflicts).
- Memory adapter auto-creates virtual directory entries in its hierarchy on `write()`.
- `WriterCollection` matches the **longest prefix** (greedy match) when routing writes to writers.
- `DuplexCollection` uses an internal `ReaderCollectionPrioritized` with the writer first, so written resources shadow the reader's resources.
- `fsInterface` provides a Node.js `fs`-compatible wrapper but only implements `readFile`, `stat`, and `readdir`. `mkdir` is a no-op.
- `Resource.getIntegrity()` computes SHA-256 via `ssri` — this triggers full content loading if not already loaded.
- Monitored readers/writers (`MonitoredReader`, `MonitoredReaderWriter`) prevent reads/writes after being sealed. They track all access patterns for build caching analysis.

## Running Tests

```bash
# All tests
npm run unit --workspace=@ui5/fs

# Single file
cd packages/fs && npx ava test/lib/Resource.js

# Verbose with logging
npm run unit-verbose --workspace=@ui5/fs

# Coverage
npm run coverage --workspace=@ui5/fs
```
Loading
Loading