# `MishkaCmsCore.Runtime.Compilers.Shared`
[🔗](https://github.com/mishka-group/mishka_cms_core/blob/v0.0.1/lib/mishka_cms_core/runtime/compilers/shared.ex#L5)

The pieces the four kind compilers (component, layout, page, error page) genuinely share.

## What is here, and what deliberately is not

`web_module/0` and `define_import/2` were byte-identical in all four and depend on nothing about
the module they live in, so they live here once. `component_prefetch/2` is what the page and the
layout compiler both write into their modules.

`make_env/0,1` looks like a fifth copy and is not one. Two things stop it moving:

  * It closes over `__ENV__`, which is **the defining module's** environment. Moving it would
    silently change which aliases and imports are in scope when a template is evaluated — the
    subtlest possible way to break rendering.
  * The four are not the same function. `LiveViewCompiler.make_env/1` *raises* when an import
    fails, because a page whose helpers are missing must not render half-broken;
    `ComponentCompiler` and `ErrorCompiler` take no arguments and hardcode their import list, and
    `LayoutCompiler` warns. Those differences are policy, not drift.

Collapsing them would be the kind of tidying that reads well in a diff and changes behaviour, so
each stays with its compiler.

# `component_prefetch`

```elixir
@spec component_prefetch(String.t() | nil, String.t() | nil) :: {Macro.t(), Macro.t()}
```

What a page or layout module needs to build its components before it draws them
(`MishkaCmsCore.Runtime.ComponentPrefetch`), from the template it is compiled from and the name of
the site it belongs to, `nil` for a global one.

The first element defines `__component_references__/0`, what the template names, kept for the
walk a cold render takes. The second is the call its `render/1` makes first, carrying the
components the template names in a tag that says which copy it draws, as module names.

# `define_import`

```elixir
@spec define_import(Macro.Env.t(), module()) ::
  {:ok, Macro.Env.t()} | {:error, term()}
```

Adds `module` to a macro environment's imports.

Takes the environment as an argument rather than capturing one, which is exactly why this half is
safe to share while `make_env` is not.

# `site_css_href`

```elixir
@spec site_css_href(String.t()) :: String.t() | nil
```

The content-addressed URL of a site's compiled stylesheet, or `nil` before its first compile.

Error pages used to inline the whole bundle in a `<style>` tag, which meant every 404 sent the
site's entire CSS over the wire uncached — 1.5 MB per missing image, per crawler, per broken link,
on the one response you least want to be expensive. The same bytes are already served at this URL
with a far-future cache header, and a visitor who reached a 404 by clicking a bad link on the site
has it in cache already.

`nil` means the site has never compiled; the caller should fall back to inlining, because an error
page with no styling at all is worse than a large one.

# `site_js_href`

```elixir
@spec site_js_href(String.t()) :: String.t() | nil
```

The content-addressed URL of a site's compiled JavaScript, or `nil` before its first compile.

See `site_css_href/1` — same reasoning, same fallback.

# `web_module`

```elixir
@spec web_module() :: module()
```

The host application's web module — what a compiled runtime module does `use` on.

Read through `Application.compile_env/3`, so changing the key recompiles this module and, through
it, every compiler that reads it.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
