Builds the components a page or a layout is about to draw, several at once, before it draws them.
A component that is not precompiled is built by the first render that names it
(MishkaCmsCore.Runtime.LiveViewHelpers.component/1), and a render meets its components one
after another, a child only once its parent is drawn. So the first visitor of a cold page waited
for every one of them in a row. Compiling is CPU-bound, and the node has more than one core.
A page module and a layout module built by MishkaCmsCore.Runtime.Compilers.LiveViewCompiler and
MishkaCmsCore.Runtime.Compilers.LayoutCompiler call prefetch/2 at the top of their render/1.
A built page does nothing
The module carries the components its own template names in a tag that says which copy it draws,
as module names. When every one of them is loaded — or its last compile failed, or it is another
site's — prefetch/2 answers :ok having read nothing but the loaded-code table: no file, no
database, no message.
A cold one
When one is not, the module's own template is walked from what it keeps
(MishkaCmsCore.Runtime.Compilers.CssClosure.reached_components/2, :references), through the
component templates the boot writes, to every component it reaches, each in the copy the render
draws. Those not loaded, not known to fail, and global or of the site this process renders for
are built through MishkaCmsCore.Runtime.LiveViewHelpers.ensure_component_loaded/2 — the path
the render takes, so the registry, the worker and MishkaCmsCore.Runtime.Handlers.CompileGate
are the same ones, nothing is compiled twice, and a render or another request asking for one of
them meanwhile waits for that compile. render/1 goes on once they are all done.
Its share of the node
One render builds at most slots/0 at once: config :mishka_cms_core, :component_prefetch_share
of the gate's limit, rounded down and at least one — half when unset. The rest of the gate stays
for every other request and site. 0 or false turns this off, and a render builds its
components one after another, as it did.
What it never does
It takes no lock but a gate slot per compile, and reads no row itself: each compile reads its own
in its worker, as a render's would. A component that does not compile fails as it does in a
render — its failure is kept in MishkaCmsCore.Runtime.States.CompileFailureState, and the render
draws the box it always draws in its place. A compile that crashes ends its task, not the page.
Events
runtime:compile:before_page_prefetch— before anything is built, with%{module: module, site: site_name, site_id: site_id, components: [%{name: name, site: site}]},sitethe site's name for a component of its own and"Global"for a global one. A plugin answers the map with othercomponentsto build more or fewer; only those not built yet, of the site rendered for or global, are built.runtime:compile:after_page_prefetch— once they are built, with%{module: module, site: site_name, site_id: site_id, built: [component], failed: [%{name: name, site: site, reason: reason}]}.
Telemetry
[:mishka_cms, :runtime, :component_prefetch, :start | :stop | :exception]— a span around a cold page's walk and build, with%{module: module, site: site_name, site_id: site_id}, and on:stopasked,built,failedandslotstoo. A built page emits nothing.
Summary
Types
A component, and the site a <.component> tag names to draw it.
Functions
Builds what owner is about to draw, unless every component in named is already built.
How many components one render builds at once: :component_prefetch_share of
MishkaCmsCore.Runtime.Handlers.CompileGate.limit/0, at least one, and 0 when it is off.
Types
Functions
Builds what owner is about to draw, unless every component in named is already built.
owner is a page or layout module; named is the components its template names, as
{module, site}, which the compiler writes into the call. Always :ok.
@spec slots() :: non_neg_integer()
How many components one render builds at once: :component_prefetch_share of
MishkaCmsCore.Runtime.Handlers.CompileGate.limit/0, at least one, and 0 when it is off.