ブログ、ドキュメント、その他の静的ページを Phoenix アプリに追加します。このライブラリはルーターにシームレスに統合され、フロントマターによるマークダウンのレンダリング、構文の強調表示、コンパイル時のキャッシュなどのサポートが組み込まれています。
def deps do
[
{ :phoenix_pages , "~> 0.1" }
]
end
Phoenix アプリケーションにインストールする推奨方法は、これをlib/myapp_web.ex
のrouter
関数に追加し、 myapp
アプリケーションの名前に置き換えることです。
def router do
quote do
use Phoenix.Router , helpers: false
use PhoenixPages , otp_app: :myapp
# ...
end
end
これで、 pages/4
マクロを使用して新しいルートを追加できます。
scope "/" , MyAppWeb do
pipe_through :browser
get "/" , PageController , :home
pages "/:page" , PageController , :show , from: "priv/pages/**/*.md"
end
これにより、 priv/pages
からすべてのマークダウン ファイルが読み取られ、それぞれに対して新しい GET ルートが作成されます。 :page
セグメントは、ベース ディレクトリを基準としたパスとファイル名 (拡張子なし) に置き換えられます (「パスの定義」を参照)。
:show
ハンドラーをlib/myapp_web/controllers/page_controller.ex
に追加する必要もあります。
defmodule MyAppWeb.PageController do
use MyAppWeb , :controller
# ...
def show ( conn , _params ) do
render ( conn , "show.html" )
end
end
最後に、 lib/myapp_web/controllers/page_html/show.html.heex
にテンプレートを追加します。ページのレンダリングされたマークダウンは、 inner_content
割り当てで利用可能になります。
< main >
<%= @inner_content % >
</ main >
それでおしまい!次に、 priv/pages/hello.md
にファイルを作成し、 /hello
にアクセスしてみます。
他の Phoenix Router マクロと同様に、 mix format
pages
マクロに括弧を追加しないようにするには、 :phoenix_pages
.formatter.exs
に追加します。
[
import_deps: [ :ecto , :ecto_sql , :phoenix , :phoenix_pages ]
]
Frontmatter では、YAML 形式を使用して、ページ固有の変数をマークダウン ファイルの先頭に含めることができます。フロントマター変数 (オプション) を設定する場合、それらはファイルの最初のものであり、三点鎖線の間に設定する必要があります。
---
title : Hello World
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.
各ページでどのフロントマター値が予期されるかを指定するには、 attrs
オプションを設定します。
pages "/:page" , PageController , :show ,
from: "priv/pages/**/*.md" ,
attrs: [ :title , author: nil ]
アトム値は必須とみなされ、ページのいずれかにない場合はコンパイル エラーがスローされます。 Key-Value はリストの最後に来る必要があり、デフォルト値を定義することによってオプションとみなされます。属性リストで定義されていないフロントマター値は、警告なしに破棄されます。
有効な属性値は割り当てで使用できます。
< main >
< h1 > <%= @title % > </ h1 >
< h2 :if = {@author} > <%= @author % > </ h2 >
<%= @inner_content % >
</ main >
Phoenix Pages は、構文の強調表示に Makeup プロジェクトを使用します。有効にするには、特定の言語のレクサーをプロジェクトの依存関係に追加します。 Phoenix Pages は、それ以上の設定を行わなくても、新しい依存関係を取得し、コード ブロックの強調表示を開始します。デフォルトではレクサーは含まれません。
`{:makeup_c, "~> 0.0"}`
`{:makeup_diff, "~> 0.0"}`
`{:makeup_elixir, "~> 0.0"}`
`{:makeup_erlang, "~> 0.0"}`
`{:makeup_graphql, "~> 0.0"}`
`{:makeup_eex, "~> 0.0"}`
`{:makeup_html, "~> 0.0"}`
`{:makeup_js, "~> 0.0"}`
`{:makeup_json, "~> 0.0"}`
`{:makeup_rust, "~> 0.0"}`
`{:makeup_sql, "~> 0.0"}`
選択した言語がサポートされていない場合は、コミュニティに貢献するために新しい Makeup レクサーを作成することを検討してください。それ以外の場合は、 render_options
でcode_class_prefix: "language-"
およびsyntax_highlighting: false
を設定することで、highlight.js などの JS ベースの構文ハイライターを使用できます。
次に、以下にリストされているテーマを CSS バンドルにインポートします。これを行う詳細は CSS 設定に大きく依存しますが、いくつかの例を以下に示します。ほとんどの場合、 phoenix_pages/css/monokai.css
(または選択したテーマ) をバンドルにインポートし、 deps
ベンダー ディレクトリとして含まれていることを確認する必要があります。
ESBuild インストーラーを使用して、 env
オプションをconfig/config.exs
に追加します。
config :esbuild ,
version: "0.17.18" ,
default: [
cd: Path . expand ( "../assets" , __DIR__ ) ,
env: % { "NODE_PATH" => Path . expand ( "../deps" , __DIR__ ) } ,
args: ~w ( --bundle --outdir=../priv/static/assets js/app.js )
]
次に、 app.js
で次のようにします。
import "phoenix_pages/css/monokai.css" ;
Sass インストーラーを使用して、 --load-path
フラグをconfig/config.exs
に追加します。
config :dart_sass ,
version: "1.62.0" ,
default: [
cd: Path . expand ( "../assets" , __DIR__ ) ,
args: ~w ( --load-path=../deps css/app.scss ../priv/static/assets/app.css )
]
次に、 app.scss
で次のようにします。
@import " phoenix_pages/css/monokai " ;
ここで説明されているようにpostcss-import
プラグインをインストールし、以下をassets/postcss.config.js
に追加します。
module . exports = {
plugins : {
"postcss-import" : { }
}
}
次に、 app.css
で次のようにします。
@import "../../deps/phoenix_pages/css/monokai" ;
他のすべてのページへのリンクを含むインデックス ページを作成するには、通常の GET ルートを作成し、ルーターでget_pages/1
およびget_pages!/1
と一緒にid
オプションを使用します。
get "/blog" , BlogController , :index
pages "/blog/:page" , BlogController , :show ,
id: :blog ,
from: "priv/blog/**/*.md" ,
attrs: [ :title , :author , :date ]
defmodule MyAppWeb.BlogController do
use MyAppWeb , :controller
def index ( conn , _params ) do
pages = MyAppWeb.Router . get_pages! ( :blog )
conn
|> assign ( :pages , pages )
|> render ( "index.html" )
end
def show ( conn , _params ) do
render ( conn , "show.html" )
end
end
<.link :for={page < - @pages} navigate = {page.path} >
<%= page.assigns.title % >
</.link>
すべてのページ ファイルはコンパイル中に読み取られてキャッシュされるため、 get_pages
関数は実際にはファイル システムから何も読み取らないため、非常にパフォーマンスが高くなります。
get_pages
関数から返されたページは、ファイル名によってソートされます。ページをロードするたびにコントローラー内でではなく、コンパイル中に別の順序を指定したい場合は、 sort
オプションを使用します。
pages "/blog/:page" , BlogController , :show ,
id: :blog ,
from: "priv/blog/**/*.md" ,
attrs: [ :title , :author , :date ] ,
sort: { :date , :desc }
フロントマターの任意の属性値を並べ替え値として定義できます。
ページのパスを定義する場合、コンパイル中に生成されたページごとに:page
セグメントが**
と*
から派生した値に置き換えられます。これは、実行時にコントローラー関数のparams
属性に解析される通常のルートのセグメントとは異なります。
たとえば、次のファイル構造があるとします。
┌── priv/
│ ┌── pages/
│ │ ┌── foo.md
│ │ ├── bar/
│ │ │ ┌── baz.md
ルーターでpages "/:page", from: "priv/pages/**/*.md"
get "/foo"
とget "/bar/baz"
の 2 つのルートが作成されます。 /blog/:page
など、パス内の別の場所に:page
セグメントを配置することもでき、 get "/blog/foo"
およびget "/blog/bar/baz"
を作成すると期待どおりに機能します。
複雑なシナリオの場合は、 :page
セグメントの代わりにキャプチャ グループ変数を使用するオプションがあります。
上記と同じファイル構造があるが、 baz
パスを/bar
下にネストしたくないとします。 :page
代わりに$2
を使用して、 pages "/$2", from: "priv/pages/**/*.md"
を定義できます。これにより、 get "/foo"
とget "/bar"
の 2 つのルートが作成されます。
キャプチャ グループ変数には、 $1
から順に**
および*
チャンクの値が含まれます。 **
すべてのファイルと 0 個以上のディレクトリおよびサブディレクトリに一致し、 *
ファイル名の末尾、次のドット、または次のスラッシュまでの任意の数の文字に一致することに注意してください。
ワイルドカード パターンの詳細については、Path.wildcard/2 を参照してください。
カスタマイズ可能なマークダウン オプションに加えて、マークダウン レンダリングはデフォルトで IAL 属性もサポートします。つまり、構文{:attr}
を使用して、任意のブロックレベル要素に HTML 属性を追加できます。
たとえば、 <h1 class="foobar">Header</h1>
のレンダリング出力を作成するには、次のようにします。
# Header{:.foobar}
属性は次のいずれかになります。
{:#id}
で ID を定義します{:.className}
クラス名を定義します{:name=value}
、 {:name="value"}
、または{:name='value'}
で他の属性を定義します複数の属性を定義するには、 {:#id name=value}
のようにスペースで区切ります。
mix phx.server
実行中にページを追加、削除、または変更すると、それらはキャッシュ内で自動的に置き換えられるため、有効にするために再起動する必要はありません。ページが変更されたときにライブリロードするには、 config/dev.exs
のエンドポイント構成のパターン リストに追加します。
config :myapp , MyAppWeb.Endpoint ,
live_reload: [
patterns: [
# ...
~r " priv/pages/.*(md)$ " ,
# ...
]
]