Klenodexample

Docs

Module Graph And Imports

Klenod collects modules into a graph first, then evaluates Ruby code only when an entry or import value needs it.

Collection Versus Evaluation

Collection reads source, resolves imports, transforms modules, records dependencies, emits assets, stores metadata, and creates a ModuleRecord. Evaluation instantiates a Klenod::Runtime::Mod, runs transformed Ruby source, and exposes exports.

context.entry(...) and context.collect(...) collect without evaluating. entry.exports, entry.call(...), context.exports(...), and context.evaluate(...) evaluate on demand.

Build mode depends on this split: it can serialize collected records without running app top-level code. Production bundles preserve lazy evaluation, but the runtime can explicitly preload entrypoints or all modules.

Module Identifiers

Module ids are canonical URI-like identifiers internally.

import("./Card")
import("/components/Card")
import("virtual:router")
import("gem://klenod-ui/components/Card")

App source files use the hostless app: scheme internally, such as app:/components/Card.haml. Virtual modules use virtual:/..., and plugin-owned module trees can use hostful schemes such as gem://gem-name/path.

Relative imports resolve from the importer. Leading slash imports resolve from the current scheme root, so app modules resolve them from the configured source directory. Use app:/... when code in another scheme needs to import from the app.

Extensionless imports use the resolvers default extension order. Ruby files are preferred before Haml files, and CSS imports should be explicit.

Eager, Lazy, And Glob Imports

import("...") creates an eager dependency. lazy_import("...") records a dependency but loads the value only when called.

Details = lazy_import("./details")

def self.render_details
  Details.call::Default.new.render
end

import_glob("...") returns a deterministic hash of matched imports. It is eager by default and can be made lazy with eager: false. Query strings are applied to every matched dependency.

Images = import_glob("./gallery/*.{jpg,png}?width=320&format=webp")
Pages = import_glob("./routes/*.rb", eager: false)

Eager import cycles are errors. Use lazy_import for deferred or cyclic branches.