Tambahkan blog, dokumentasi, dan halaman statis lainnya ke aplikasi Phoenix. Pustaka ini terintegrasi dengan mulus ke dalam router Anda dan dilengkapi dengan dukungan bawaan untuk merender penurunan harga dengan frontmatter, penyorotan sintaksis, cache waktu kompilasi, dan banyak lagi.
def deps do
[
{ :phoenix_pages , "~> 0.1" }
]
end
Cara yang disarankan untuk menginstal ke dalam aplikasi Phoenix Anda adalah dengan menambahkan ini ke fungsi router
Anda di lib/myapp_web.ex
, ganti myapp
dengan nama aplikasi Anda:
def router do
quote do
use Phoenix.Router , helpers: false
use PhoenixPages , otp_app: :myapp
# ...
end
end
Sekarang Anda dapat menambahkan rute baru menggunakan makro pages/4
:
scope "/" , MyAppWeb do
pipe_through :browser
get "/" , PageController , :home
pages "/:page" , PageController , :show , from: "priv/pages/**/*.md"
end
Ini akan membaca semua file penurunan harga dari priv/pages
dan membuat rute GET baru untuk masing-masing file. Segmen :page
akan diganti dengan path dan nama file (tanpa ekstensi) yang berhubungan dengan direktori dasar (lihat Mendefinisikan Paths).
Anda juga harus menambahkan :show
handler ke 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
Terakhir, tambahkan template di lib/myapp_web/controllers/page_html/show.html.heex
. Penurunan harga halaman yang diberikan akan tersedia di penetapan inner_content
:
< main >
<%= @inner_content % >
</ main >
Itu saja! Sekarang coba buat file di priv/pages/hello.md
dan kunjungi /hello
.
Untuk mencegah mix format
menambahkan tanda kurung ke makro pages
yang mirip dengan makro Phoenix Router lainnya, tambahkan :phoenix_pages
ke .formatter.exs
:
[
import_deps: [ :ecto , :ecto_sql , :phoenix , :phoenix_pages ]
]
Frontmatter memungkinkan variabel khusus halaman untuk disertakan di bagian atas file penurunan harga menggunakan format YAML. Jika Anda menyetel variabel frontmatter (yang bersifat opsional), variabel tersebut harus berada di urutan pertama dalam file dan harus disetel di antara garis putus-putus tiga kali:
---
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.
Untuk menentukan nilai frontmatter mana yang diharapkan di setiap halaman, atur opsi attrs
:
pages "/:page" , PageController , :show ,
from: "priv/pages/**/*.md" ,
attrs: [ :title , author: nil ]
Nilai atom akan dianggap diperlukan, dan kesalahan kompilasi akan terjadi jika hilang dari halaman mana pun. Nilai kunci harus berada di urutan terakhir dalam daftar, dan akan dianggap opsional dengan menentukan nilai default. Nilai frontmatter apa pun yang tidak ditentukan dalam daftar atribut akan dibuang secara diam-diam.
Nilai atribut yang valid akan tersedia di penetapan:
< main >
< h1 > <%= @title % > </ h1 >
< h2 :if = {@author} > <%= @author % > </ h2 >
<%= @inner_content % >
</ main >
Phoenix Pages menggunakan proyek Makeup untuk penyorotan sintaksis. Untuk mengaktifkannya, tambahkan lexer untuk bahasa spesifik Anda ke dependensi proyek. Phoenix Pages akan mengambil ketergantungan baru dan mulai menyorot blok kode Anda tanpa konfigurasi lebih lanjut. Tidak ada lexer yang disertakan secara default.
`{: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"}`
Jika bahasa pilihan Anda tidak didukung, pertimbangkan untuk menulis lexer Rias baru untuk berkontribusi pada komunitas. Jika tidak, Anda dapat menggunakan penyorot sintaksis berbasis JS seperti highlight.js dengan mengatur code_class_prefix: "language-"
dan syntax_highlighting: false
di render_options
.
Selanjutnya, impor tema yang tercantum di bawah ini ke dalam bundel CSS Anda. Hal spesifik dalam melakukan hal ini sangat bergantung pada konfigurasi CSS Anda, namun beberapa contoh disertakan di bawah. Dalam kebanyakan kasus, Anda perlu mengimpor phoenix_pages/css/monokai.css
(atau tema apa pun yang Anda pilih) ke dalam bundel Anda dan memastikan deps
disertakan sebagai direktori vendor.
Menggunakan penginstal ESBuild, tambahkan opsi env
ke 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 )
]
Kemudian di app.js
:
import "phoenix_pages/css/monokai.css" ;
Dengan menggunakan penginstal Sass, tambahkan flag --load-path
ke 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 )
]
Kemudian di app.scss
:
@import " phoenix_pages/css/monokai " ;
Instal plugin postcss-import
seperti yang dijelaskan di sini dan tambahkan yang berikut ke assets/postcss.config.js
:
module . exports = {
plugins : {
"postcss-import" : { }
}
}
Kemudian di app.css
:
@import "../../deps/phoenix_pages/css/monokai" ;
Untuk membuat halaman indeks dengan link ke semua halaman lainnya, buat rute GET normal dan gunakan opsi id
bersama get_pages/1
dan get_pages!/1
di router Anda:
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>
Semua file halaman dibaca dan di-cache selama kompilasi, sehingga fungsi get_pages
tidak akan benar-benar membaca apa pun dari sistem file—membuatnya berkinerja sangat baik.
Halaman yang dikembalikan dari fungsi get_pages
akan diurutkan berdasarkan nama file. Jika Anda ingin menentukan urutan yang berbeda selama kompilasi daripada di pengontrol pada setiap pemuatan halaman, gunakan opsi sort
:
pages "/blog/:page" , BlogController , :show ,
id: :blog ,
from: "priv/blog/**/*.md" ,
attrs: [ :title , :author , :date ] ,
sort: { :date , :desc }
Nilai atribut apa pun dari frontmatter dapat didefinisikan sebagai nilai pengurutan.
Saat menentukan jalur halaman, segmen :page
akan diganti untuk setiap halaman yang dihasilkan selama kompilasi dengan nilai yang berasal dari **
dan *
. Ini berbeda dengan segmen di rute biasa, yang diuraikan selama runtime ke dalam atribut params
dari fungsi pengontrol.
Misalnya, Anda memiliki struktur file berikut:
┌── priv/
│ ┌── pages/
│ │ ┌── foo.md
│ │ ├── bar/
│ │ │ ┌── baz.md
Mendefinisikan pages "/:page", from: "priv/pages/**/*.md"
di router Anda akan membuat dua rute: get "/foo"
dan get "/bar/baz"
. Anda bahkan dapat meletakkan segmen :page
di tempat lain di jalur, seperti /blog/:page
, dan ini akan berfungsi seperti yang diharapkan dengan membuat get "/blog/foo"
dan get "/blog/bar/baz"
.
Untuk skenario yang kompleks, Anda memiliki opsi untuk menggunakan variabel grup tangkapan, bukan segmen :page
.
Katakanlah Anda memiliki struktur file yang sama seperti di atas, tetapi tidak ingin jalur baz
disarangkan di bawah /bar
. Anda dapat menentukan pages "/$2", from: "priv/pages/**/*.md"
, menggunakan $2
alih-alih :page
. Ini akan membuat dua rute: get "/foo"
dan get "/bar"
.
Variabel grup tangkapan akan berisi nilai potongan **
dan *
secara berurutan, mulai dari $1
. Ingatlah bahwa **
akan mencocokkan semua file dan nol atau lebih direktori dan subdirektori, dan *
akan mencocokkan sejumlah karakter hingga akhir nama file, titik berikutnya, atau garis miring berikutnya.
Untuk informasi selengkapnya tentang pola wildcard, lihat Path.wildcard/2.
Selain opsi penurunan harga yang dapat disesuaikan, rendering penurunan harga juga mendukung atribut IAL secara default. Artinya Anda dapat menambahkan atribut HTML ke elemen tingkat blok apa pun menggunakan sintaksis {:attr}
.
Misalnya, untuk membuat keluaran yang dirender dari <h1 class="foobar">Header</h1>
:
# Header{:.foobar}
Atribut dapat berupa salah satu dari berikut ini:
{:#id}
untuk menentukan ID{:.className}
untuk mendefinisikan nama kelas{:name=value}
, {:name="value"}
, atau {:name='value'}
untuk mendefinisikan atribut lainnya Untuk menentukan beberapa atribut, pisahkan dengan spasi: {:#id name=value}
.
Jika Anda menambah, menghapus, atau mengubah halaman saat menjalankan mix phx.server
, halaman tersebut akan otomatis diganti di cache dan Anda tidak perlu memulai ulang agar halaman tersebut dapat diterapkan. Untuk memuat ulang langsung ketika halaman berubah, tambahkan ke daftar pola konfigurasi Endpoint di config/dev.exs
:
config :myapp , MyAppWeb.Endpoint ,
live_reload: [
patterns: [
# ...
~r " priv/pages/.*(md)$ " ,
# ...
]
]