5.2 KiB
Arcology Web Elixir Application
Setting up the ArcologyWeb
module
Much of this is boilerplate which I include here only to understand and take apart how Phoenix operates. There's not a whole lot hiding "under the hood" compared to, say, Ruby on Rails, which I really appreciate, to be honest.
So starting with the moduledoc:
The entrypoint for defining your web interface, such
as controllers, components, channels, and so on.
This can be used in your application as:
use ArcologyWeb, :controller
use ArcologyWeb, :html
The definitions below will be executed for every controller,
component, etc, so keep them short and clean, focused
on imports, uses and aliases.
Do NOT define functions inside the quoted expressions
below. Instead, define additional modules and import
those modules here.
This is pretty straightforward, right? Our controllers and views can include a bunch of standard behavior (auth, logging, rate limiting, etc) by invoking those use
statements. There are a bunch of functions defined below which will be exposed in that fashion using this "magic" __using__
macro:
@doc """
When used, dispatch to the appropriate controller/view/etc.
"""
defmacro __using__(which) when is_atom(which) do
apply(__MODULE__, which, [])
end
Some of the helpers include some extra helpers shared among them by "unquoting" a function which returns "quoted" import
and alias
statements – this is the sort of indirection which makes sense in my Lisp brain, but it can be really off-putting to people who aren't exposed to this sort of pattern. The basic idea here is to provide those statements in the function which is "used in" rather than in the private helpers where they would be executed were they not quoted.
These functions import functionality for HTML rendering, compile-time Verified Route generation, and translations:
defp html_helpers do
quote do
# HTML escaping functionality
import Phoenix.HTML
# Core UI components and translation
import ArcologyWeb.CoreComponents
import ArcologyWeb.Gettext
# Shortcut for generating JS commands
alias Phoenix.LiveView.JS
# Routes generation with the ~p sigil
unquote(verified_routes())
end
end
def verified_routes do
quote do
use Phoenix.VerifiedRoutes,
endpoint: ArcologyWeb.Endpoint,
router: ArcologyWeb.Router,
statics: ArcologyWeb.static_paths()
end
end
Use'ing :router
in roam:ArcologyWeb.Router lets me customize the behavior of the router by introducing Plugs; I'll be adding a Plug to attempt to load Arcology pages rather than using a "greedy" route which I used in (for example) the FastAPI Arcology Domain Router.
def router do
quote do
use Phoenix.Router, helpers: false
# Import common connection and controller functions to use in pipelines
import Plug.Conn
import Phoenix.Controller
import Phoenix.LiveView.Router
end
end
Routing, controlling, viewing, etc, can all be skipped for static_paths
, these are files that can just be served out of the filesystem where the application is built and bundled:
def static_paths, do: ~w(assets fonts images favicon.ico robots.txt)
The :controller
helper sets up rendering rules, provides access to translations
def controller do
quote do
use Phoenix.Controller,
formats: [:html, :json],
layouts: [html: ArcologyWeb.Layouts]
import Plug.Conn
import ArcologyWeb.Gettext
unquote(verified_routes())
end
end
The :live_view
, :live_component
, and :html
helpers set up HTML rendering and dynamic LiveView components using the quoted helpers described above.
def live_view do
quote do
use Phoenix.LiveView,
layout: {ArcologyWeb.Layouts, :app}
unquote(html_helpers())
end
end
def live_component do
quote do
use Phoenix.LiveComponent
unquote(html_helpers())
end
end
def html do
quote do
use Phoenix.Component
# Import convenience functions from controllers
import Phoenix.Controller,
only: [get_csrf_token: 0, view_module: 1, view_template: 1]
# Include general helpers for rendering HTML
unquote(html_helpers())
end
end
The :channel
helper will provide Phoenix.Channel
helpers to PubSub channels, if I decide to use them.
def channel do
quote do
use Phoenix.Channel
end
end
defmodule ArcologyWeb do
@moduledoc """
<<ArcologyWeb.moduledoc>>
"""
<<helpers>>
<<quoted_helpers>>
<<ArcologyWeb.__using__>>
end