PhoenixMountable.Assets behaviour (PhoenixMountable v0.2.1)

Copy Markdown View Source

How a mountable library's CSS and JavaScript reach the browser.

A library picks a strategy with the :assets option of use PhoenixMountable:

use PhoenixMountable,
  otp_app: :my_lib,
  macro: :my_lib,
  assets: {PhoenixMountable.Assets.Embedded, css: "priv/static/app.css", js: "priv/static/app.js"}

Strategies shipped with PhoenixMountable:

A strategy is any module implementing this behaviour, so a library can bring its own.

Entries

Each strategy describes the files a page needs as entries: a name, a URL and a kind (:css, :js or :module). PhoenixMountable.Layout renders them as tags with the request's CSP nonces and phx-track-static, and url/2 returns one entry's URL.

Stale assets

After a deploy, a browser can keep running the previous bundle. When a library LiveView connects, PhoenixMountable asks the strategy whether any of the URLs the page tracks (phx-track-static) belongs to a previous build, and reloads the page if so. Phoenix's own static_changed?/1 cannot see this because it only knows the host's static manifest.

Summary

Types

An asset of a page.

A route a strategy adds under the mount path.

Callbacks

The entries of the strategy for a mount.

Validates the strategy options and computes its state.

Code to inject into the definition module, such as embedded file contents.

Routes to add under the mount path.

Whether any of the tracked URLs was produced by a previous build.

Functions

The asset entries of a mount, in order.

Whether the page that tracks tracked URLs runs assets of a previous build.

The URL of the asset entry name.

Types

entry()

@type entry() :: %{name: atom(), url: String.t(), kind: :css | :js | :module}

An asset of a page.

route()

@type route() :: %{
  :verb => atom(),
  :path => String.t(),
  :plug => module(),
  :plug_opts => term(),
  optional(:opts) => keyword()
}

A route a strategy adds under the mount path.

Callbacks

entries(state, t, path_fun)

@callback entries(
  state :: term(),
  PhoenixMountable.Mount.t(),
  path_fun :: (String.t() -> String.t())
) :: [
  entry()
]

The entries of the strategy for a mount.

path_fun turns a path relative to the mount into a full path, honouring the endpoint's script name and the mount's :asset_host.

init(opts, context)

@callback init(opts :: keyword(), context :: %{module: module(), otp_app: atom()}) ::
  term()

Validates the strategy options and computes its state.

Runs at compile time in the definition module. context has the definition :module and the library's :otp_app. The state is stored in every mount, so keep it small: file contents belong in inject/2.

inject(state, definition)

(optional)
@callback inject(state :: term(), definition :: module()) :: Macro.t()

Code to inject into the definition module, such as embedded file contents.

routes(state, definition)

@callback routes(state :: term(), definition :: module()) :: [route()]

Routes to add under the mount path.

stale?(state, t, tracked)

@callback stale?(state :: term(), PhoenixMountable.Mount.t(), tracked :: [String.t()]) ::
  boolean()

Whether any of the tracked URLs was produced by a previous build.

Functions

entries(mount)

@spec entries(PhoenixMountable.Mount.t()) :: [entry()]

The asset entries of a mount, in order.

stale?(mount, tracked)

@spec stale?(PhoenixMountable.Mount.t(), [String.t()]) :: boolean()

Whether the page that tracks tracked URLs runs assets of a previous build.

url(mount, name)

@spec url(PhoenixMountable.Mount.t(), atom()) :: String.t()

The URL of the asset entry name.

<script src={PhoenixMountable.Assets.url(@mount, :js)} defer></script>