Class: Ruact::ClientManifest
- Inherits:
-
Object
- Object
- Ruact::ClientManifest
- Defined in:
- lib/ruact/client_manifest.rb
Overview
Reads the react-client-manifest.json emitted by the Vite plugin and resolves component names to Flight ClientReferences.
Manifest format (one entry per “use client” export):
{
"LikeButton": {
"id": "/assets/LikeButton-abc123.js",
"chunks": ["/assets/LikeButton-abc123.js"],
"name": "LikeButton"
},
"posts/_like_button": {
"id": "/assets/posts/_like_button-abc123.js",
"chunks": ["/assets/posts/_like_button-abc123.js"],
"name": "default"
}
}
Class Method Summary collapse
-
.from_hash(data) ⇒ Object
Build from an already-parsed Hash (useful in tests).
-
.load(path) ⇒ Object
Load from a file path (JSON).
Instance Method Summary collapse
-
#include?(name) ⇒ Boolean
Returns true if
nameis a top-level key in the manifest data. -
#reference_for(name, controller_path: nil) ⇒ Object
Resolve a component name (e.g. “LikeButton”) → ClientReference.
-
#resolve(module_id, _export_name) ⇒ Object
Used by Flight::Serializer to produce I rows.
Class Method Details
.from_hash(data) ⇒ Object
Build from an already-parsed Hash (useful in tests).
76 77 78 79 80 |
# File 'lib/ruact/client_manifest.rb', line 76 def self.from_hash(data) manifest = new manifest.instance_variable_set(:@data, data) manifest end |
.load(path) ⇒ Object
Load from a file path (JSON). Pre-warms the reference cache and freezes the manifest so it cannot be mutated at runtime (AC#5). Pre-warming is required because Ruby’s freeze is shallow: instance variable assignment on a frozen object raises FrozenError, so @reference_cache must already be set before freeze.
67 68 69 70 71 72 73 |
# File 'lib/ruact/client_manifest.rb', line 67 def self.load(path) raw = File.read(path) data = JSON.parse(raw) manifest = from_hash(data) data.each_key { |name| manifest.reference_for(name) } manifest.freeze end |
Instance Method Details
#include?(name) ⇒ Boolean
Returns true if name is a top-level key in the manifest data. Used by the dual-path resolver to check co-located key existence before fallback.
34 35 36 |
# File 'lib/ruact/client_manifest.rb', line 34 def include?(name) entries_by_name.key?(name) end |
#reference_for(name, controller_path: nil) ⇒ Object
Resolve a component name (e.g. “LikeButton”) → ClientReference.
When controller_path is provided (e.g. “posts”), the resolver first looks for a co-located key (“posts/_like_button”). If found, it returns that reference; otherwise it falls back to the shared PascalCase key.
Returns the same object for repeated calls with the same resolved key (needed for dedup by object_id in Flight::Serializer). Raises if the resolved name is not found in the manifest.
47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/ruact/client_manifest.rb', line 47 def reference_for(name, controller_path: nil) @reference_cache ||= {} key = resolve_key(name, controller_path) @reference_cache[key] ||= begin entry = entries_by_name[key] unless entry raise ManifestError, "Component #{name.inspect} not found in manifest — " \ "Did you run the Vite build? Run 'npm run build' or start the Vite dev server." end Flight::ClientReference.new(module_id: entry["id"], export_name: name) end end |
#resolve(module_id, _export_name) ⇒ Object
Used by Flight::Serializer to produce I rows. Returns the metadata array the client expects: [id, name, chunks]
25 26 27 28 29 30 |
# File 'lib/ruact/client_manifest.rb', line 25 def resolve(module_id, _export_name) entry = by_module_id(module_id) raise "ClientManifest: no entry for module_id=#{module_id.inspect}" unless entry [entry["id"], entry["name"], entry["chunks"]] end |