Beacon.Router (Beacon v0.5.1)
View SourceControls pages routing and provides helpers to mount sites in your application router and generate links to pages.
defmodule MyAppWeb.Router do
use Phoenix.Router
use Beacon.Router
scope "/", MyAppWeb do
pipe_through :browser
beacon_site "/blog", site: :blog
end
endHelpers
A ~p sigil is provided to generate links to pages taking the scope and site prefix into account.
Using that sigil in a template in the :blog site defined above would result in the following links:
~p"/contact" => "/blog/contact"
~p"/posts/#{@post}" => "/blog/posts/my-post"In this example post is a Beacon.Content.Page that implements the Phoenix.Param protocol to resolve the page path.
Path
The full path of the site is calculated resolving the scope prefix plus the site prefix.
The simplest scenario is mounting a site at the root of your application:
scope "/", MyAppWeb do
pipe_through :browser
beacon_site "/", site: :my_site
endIn this case the site :my_site will be available at https://yourapp.com/
By mixing prefixes you have the flexibility to mount sites in different paths,
for example both declarations below will mount the site at https://yourapp.com/blog:
scope "/blog", MyAppWeb do
pipe_through :browser
beacon_site "/", site: :blog
end
scope "/", MyAppWeb do
pipe_through :browser
beacon_site "/blog", site: :blog
endThere's no difference between the two approaches, but that is important to group and organize your routes and sites, for example a scope might be served through a different pipeline:
scope "/marketing", MyAppWeb do
pipe_through :browser_analytics
beacon_site "/super-campaign", site: :marketing_super_campaign
beacon_site "/", site: :marketing
endNote in the last example that /super-campaign is defined before / and there's an important reason for that: router precedence.
Route Precedence
Beacon pages are defined dynamically so it doesn't know which pages are available when the router is compiled,
which means that any route after the prefix may match a published page. For example /contact may be a valid
page published under the mounted beacon_site "/, site: :marketing site.
Essentially it mounts a catch-all route like /* so if we had inverted the routes below we would end with:
/*
/super-campaignThe second route would never match since the first one would match all requests.
As a rule of thumb, put all specific routes first.
Summary
Functions
Mounts a site at prefix in your host application's router.
Functions
Mounts a site at prefix in your host application's router.
This will automatically serve sitemap.xml from the prefix path defined for this site,
and also robots.txt and sitemap_index.xml in the top-level host.
Options
:site(required)Beacon.Types.Site.t/0- register your site with a unique name. Note that the name has to match the one used in your site configuration. See the module doc andBeacon.Configfor more info.
Live Session options:
You can also override the following live_session options:
:session(optional) - an optional extra session map or MFA tuple to merge into Beacon'slive_session. Useful to authenticate the session using 3rd-party libs like AshAuthentication. Defaults to%{}.:root_layout- override the default root layout for the site. Defaults to{Beacon.Web.Layouts, :runtime}. SeeBeacon.Web.Layoutsfor more info.:on_mount(optional) - an optional list ofon_mounthooks to merge into Beacon'slive_session. This will allow for authenticated routes, among other uses. Defaults to[].
Examples
Initialize assigns for all pages in a site:
beacon_site "/", site: :my_site, on_mount: MyAppWeb.InitAssigns
defmodule MyAppWeb.InitAssigns do
import Phoenix.Component
def on_mount(:default, _params, session, socket) do
{:cont, assign(socket, :logo_url, "https://mycdn.com/logo.webp")}
end
endIntegrate a Beacon site with Ash:
beacon_site "/", [site: :my_site] ++ AshAuthentication.Phoenix.LiveSession.opts(on_mount: [{MyAppWeb.LiveUserAuth, :live_user_required}])