This is mostly a prototype, meant to validate a few ideas to have something similar to https://storybook.js.org/ for Surface.
Add surface_catalogue to your list of dependencies in mix.exs:
def deps do
[
{:surface_catalogue, "~> 0.6.3", only: :dev}
]
endUpdate your router.ex configuration:
# lib/my_app_web/router.ex
use MyAppWeb, :router
import Surface.Catalogue.Router
...
if Mix.env() == :dev do
scope "/" do
pipe_through :browser
surface_catalogue "/catalogue"
end
endAdd a :catalogue entry in the :esbuild config in config.exs:
config :esbuild,
default: ...,
# Add a new entry for the catalogue
catalogue: [
args: ~w(../deps/surface_catalogue/assets/js/app.js --bundle --target=es2016 --minify --outdir=../priv/static/assets/catalogue),
cd: Path.expand("../assets", __DIR__),
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]Then update the endpoint configuration in config/dev.exs to add an esbuild watcher
for catalogue:
config :my_app, MyAppWeb.Endpoint,
...
watchers: [
esbuild: ...,
# Add an esbuild watcher for :catalogue
esbuild: {Esbuild, :install_and_run, [:catalogue, ~w(--sourcemap=inline --watch)]},
]That's all!
Run mix phx.server and access "/catalogue" to see the list of all available components in
your project.
If you want to access examples and playgrounds for components, edit your mix.exs file,
adding a new entry for elixirc_paths along with a catalogues function listing the
catalogues you want to be loaded:
...
def catalogues do
[
# Local catalogue
"priv/catalogue",
# Dependencies catalogues
"deps/surface/priv/catalogue",
"deps/surface_bulma/priv/catalogue",
# External catalogues
Path.expand("../my_components/priv/catalogue"),
"/Users/johndoe/workspace/other_components/priv/catalogue"
]
end
defp elixirc_paths(:dev), do: ["lib"] ++ catalogues()
...Then update the endpoint configuration in config/dev.exs to set up live reloading
for your catalogue:
config :my_app, MyAppWeb.Endpoint,
live_reload: [
patterns: [
~r"priv/catalogue/.*(ex)$",
...
]
]Note: Without the above configurations, the list of available components is still presented in the catalogue page. However, when selecting a component, only its documentation and API will be shown. No example/playground will be loaded nor tracked by Phoenix's live reloader.
If you're working on a suite of components that you want to share as a library, you
may need to provide additional information about the catalogue. This will be necessary
whenever your components require any css or js code that might not be available
on the host project.
To provide that additional information you must create a module implementing the
Surface.Catalogue behaviour in your priv/catalogue/ folder. Example:
defmodule MySuite.Catalogue do
use Surface.Catalogue
@impl true
def config() do
[
head_css: """
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.8.2/css/bulma.min.css" />
"""
]
end
endIn case you're working on a lib that doesn't initialize its own Phoenix endpoint, you
can use the built-in server provided by the surface_catalogue following these steps:
Add the required dependencies to your list of dependencies in mix.exs:
def deps do
[
{:plug_cowboy, "~> 2.0", only: :dev},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:jason, "~> 1.0", only: :dev}
]
endCreate a dev.exs script at the root of your project with the following content:
# iex -S mix dev
Logger.configure(level: :debug)
# Start the catalogue server
Surface.Catalogue.Server.start(
watchers: [
esbuild: {Esbuild, :install_and_run, [:catalogue, ~w(--sourcemap=inline --watch)]}
],
live_reload: [
patterns: [
~r"priv/static/.*(js|css)$",
~r"lib/my_lib_web/.*(ex)$"
],
notify: [
live_view: [
# Colocated sface and css can be reloaded without a hard refresh
~r"lib/my_lib_web/.*(sface|css)$"
]
]
]
)Surface Catalogue's assets need to be generated by your project to make it compatible with your Phoenix dependency versions.
Add the following content to your config/config.exs or config/dev.exs:
import Config
if Mix.env() == :dev do
config :surface_catalogue,
title: "My Lib Web",
config :esbuild,
...
catalogue: [
args:
~w(#{Mix.Project.deps_paths().surface_catalogue}/assets/js/app.js --bundle --target=es2016 --minify --outdir=priv/static/assets/catalogue),
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]
# Required at compile time
config :surface_catalogue, Surface.Catalogue.Server.Endpoint,
code_reloader: true,
debug_errors: true
endMake sure you set the patterns option according to your project.
To make things easier, add an alias run the script in your mix.exs:
def project do
[
...,
aliases: aliases()
]
end
...
defp aliases do
[
dev: "run --no-halt dev.exs",
...
]
endRun the server with:
mix devor using iex:
iex -S mix devYou can now access the catalogue at localhost:4000.
If you need, you can also start the server using a different port:
PORT=4444 iex -S mix devThe Surface.Catalogue.Server implementation was mostly extracted from the dev.exs script
from phoenix_live_dashboard.
All credits to the Phoenix Core Team.
Copyright (c) 2021, Marlus Saraiva.
Surface source code is licensed under the MIT License.