Phoenix 1.7-rc 發布
Chris McCord 在 2022 年 11 月 7 日張貼
Phoenix 1.7 的第一個候選版本已推出!Phoenix 1.7 包含許多期待已久的全新功能,例如經過驗證的路由、Tailwind 支援、LiveView 驗證產生器、統一的 HEEx 範本等等。這是具有少數棄用的相容性版本。大多數人只需變更幾個依賴項便可更新。
注意:對於 rc 期間,您需要從 Hex 明確安裝 phx.new
產生器來嘗試新的專案
mix archive.install hex phx_new 1.7.0-rc.0
經過驗證的路由
經過驗證的路由會用基於符號 (~p
) 的編譯時驗證方法取代路由輔助程式。
注意:經過驗證的路由使用新的 Elixir 1.14 編譯器功能。Phoenix 仍支援較舊的 Elixir 版本,但您需要更新才能享受新的編譯時驗證功能。
在實務上,這表示之前您使用自動產生的函式,例如
# router
get "/oauth/callbacks/:id", OAuthCallbackController, :new
# usage
MyRouter.Helpers.o_auth_callback_path(conn, :new, "github")
# => "/oauth/callbacks/github"
MyRouter.Helpers.o_auth_callback_url(conn, :new, "github")
# => "https://127.0.0.1:4000/oauth/callbacks/github"
現在您可以執行
# router
get "/oauth/callbacks/:id", OAuthCallbackController, :new
# usage
~p"/oauth/callbacks/github"
# => "/oauth/callbacks/github"
url(~p"/oauth/callbacks/github")
# => "https://127.0.0.1:4000/oauth/callbacks/github"
這有許多優點。不再需要猜測彈性處理的函式為何 - 是 Helpers.oauth_callback_path
還是 o_auth_callback_path
等。當 99% 的時間您知道應該使用哪個端點組態時,也不再需要在所有地方包含 %Plug.Conn{}
、 %Phoenix.Socket{}
或端點模組。
現在您在路由中撰寫的路由和使用 ~p
來呼叫的路由之間也有了 1:1 的對應。您只需撰寫,彷彿您在應用程式各處對字串進行硬編碼 - 但您不必面對硬編碼字串會帶來的維護問題。由於 ~p
會針對路由中的路由進行編譯時驗證,因此我們可以輕鬆享受易用性與維護性的優點。
例如,假設我們輸入一個路由
<.link href={~p"/userz/profile"}>Profile</.link>
編譯器會在編譯階段針對路由對應所有 ~p
,並讓您在找不到相符路由時了解狀況
warning: no route path for AppWeb.Router matches "/postz/#{post}"
lib/app_web/live/post_live.ex:100: AppWeb.PostLive.render/1
動態「命名參數」也只會像一般字串一樣進行內插,而不是隨意的函式引數
~p"/posts/#{post.id}"
此外,內插的 ~p
值會透過 Phoenix.Param
協定進行編碼。例如,應用程式中的 %Post{}
結構可以衍生 Phoenix.Param
協定,以產生基於標籤而非 ID 的路徑。這讓您可以在應用程式中使用 ~p"/posts/#{post}"
而不是 ~p"/posts/#{post.slug}"
。
經過驗證的路由也支援查詢字串,可以用傳統的查詢字串格式
~p"/posts?page=#{page}"
或用關鍵字清單或值對應
params = %{page: 1, direction: "asc"}
~p"/posts?#{params}"
與路徑片段類似,查詢字串參數會經過適當地 URL 編碼,並且可以內插至 ~p
字串中。
一旦你嘗試新功能,你將無法回到路由輔助程式。新的 phx.gen.html|live|json|auth
產生器使用已驗證的路由。
基於元件的 Tailwind 產生器
Phoenix 1.7 預設使用 TailwindCSS,系統上不依賴 nodejs。TailwindCSS 是我在 20 年網頁開發生涯中,發現用來設定介面樣式最好的方式。其以公用程式為先的方法,比我所使用過的任何 CSS 系統或框架更易於維護和提高生產力。其置於同一位置的方法也與 fucntion 元件和 LiveView 環境完全一致。
Tailwind 團隊也慷慨地設計了新的專案著陸頁、CRUD 頁面和新專案驗證系統頁面,為建構你的應用程式提供一流且完善的起點。
新的 phx.new
專案將包含一個 CoreComponents
模組,存放一組核心的 UI 元件,例如表格、模式對話方塊、表單和資料清單。一系列 Phoenix 產生器 (phx.gen.html|live|json|auth
) 利用核心元件。這樣有很多優點。
首先,你可以自訂核心 UI 元件,以滿足任何你有的需求、設計和喜好。如果你想使用 Bulma 或 Bootstrap 取代 Tailwind,沒問題!只要用 core_components.ex
中的函式定義取代你的框架/特定於 UI 的實作,然後產生器就可以繼續為新功能提供很棒的起點,無論你是初學者,或是建立客製化產品功能的經驗豐富專家。
實務上,產生器會給你利用核心元件的範本,如下所示
<.header>
New Post
<:subtitle>Use this form to manage post records in your database.</:subtitle>
</.header>
<.simple_form :let={f} for={@changeset} action={~p"/posts"}>
<.error :if={@changeset.action}>
Oops, something went wrong! Please check the errors below.
</.error>
<input field={{f, :title}} type="text" label="Title" />
<input field={{f, :views}} type="number" label="Views" />
<:actions>
<.button>Save Post</.button>
</:actions>
</.simple_form>
<.back navigate={~p"/posts"}>Back to posts></.back>
我們很喜歡 Tailwind 團隊為新應用程式所設計的內容,但我們也很期待看到社群釋出他們自己針對 core_components.ex
的 drop-in 替換,供不同的框架選擇使用。
統一控制器和 LiveViews 中的函式元件
HEEx 提供的函式元件,具備宣告式指定和槽,大幅改變了我們在 Phoenix 專案中寫入 HTML 的方式。函式元件提供 UI 建構積木,允許封裝功能,並在 Phoenix.View
中比先前的範本方法進行更好的延伸。你能更自然地寫入動態標記、可被呼叫者延伸的可重複使用 UI,以及編譯時功能,讓撰寫基於 HTML 的應用程式成為真正的首要體驗。
函式元件引入了撰寫 Phoenix 中的 HTML 應用程式的新方法,並具備了新的約定慣例。此外,使用者在應用程式中一直苦惱於如何將基於控制器的 Phoenix.View
功能與 Phoenix.LiveView
功能合併在一起。使用者發現自己會在基於控制器的範本中撰寫 render("table", user: user)
,而他們的 LiveViews 則使用新的 <.table rows={@users}>
功能。沒有好方法可以在應用程式中分享這兩種方法。
基於這些原因,Phoenix 團隊統一了 HTML 渲染方法,無論是來自控制器要求,或 LiveView。這種轉變讓我們得以重新審視約定慣例,並與 LiveView 將範本與應用程式程式碼配置在一起的方法保持一致。
新的應用程式(以及 phx 產生器),將 Phoenix.View
作為依賴項移除,轉而採用新的 Phoenix.Template
依賴項,其使用函式元件作為架構中所有渲染的基礎。
你的控制器仍舊看起來相同
defmodule AppWeb.UserController do
use MyAppWeb, :controller
def index(conn, _params) do
users = ...
render(conn, :index, users: users)
end
end
但是,控制器並未呼叫 AppWeb.UserView.render("index.html", assigns)
,我們將首先在檢視模組上尋找 index/1
函式元件,如果存在,則呼叫該元件進行渲染。此外,我們還重新命名了詞形變化檢視模組,以尋找 AppWeb.UserHTML
、AppWeb.UserJSON
等等,依據每種格式的檢視方法來渲染範本。這一切都以向後相容的方式完成,並且基於使用 Phoenix.Controller
的選項進行選用。
所有 HTML 渲染都基於函式元件,這些元件可以直接寫在模組中,或使用 Phoenix.Component
提供的新 embed_templates
巨集從外部檔案嵌入。你在新的應用程式中的 PageHTML
模組看起來像這樣
defmodule AppWeb.PageHTML do
use AppWeb, :html
embed_templates "page_html/*"
end
新的目錄結構看起來像這樣
lib/app_wb
├── controllers
│ ├── page_controller.ex
│ ├── page_html.ex
│ ├── error_html.ex
│ ├── error_json.ex
│ └── page_html
│ └── home.html.heex
├── live
│ ├── home_live.ex
├── components
│ ├── core_components.ex
│ ├── layouts.ex
│ └── layouts
│ ├── app.html.heex
│ └── root.html.heex
├── endpoint.ex
└── router.ex
你基於控制器的渲染或基於 LiveView 的渲染現在都共享相同的函式元件和佈局。無論是執行 phx.gen.html
、phx.gen.live
,還是 phx.gen.auth
,新產生的範本都會使用你的 components/core_components.ex
定義。
此外,我們已將檢視模組配置在他們的控制器檔案旁邊。這帶來與 LiveView 配置相同的好處 — 高度耦合的檔案集中在一起。無論是撰寫 LiveView 還是控制器功能,都必須同時修改的檔案現在都集中在一起。
這些變更都旨在改善撰寫基於 HTML 的應用程式的方法,但它們也簡化了其他格式的渲染,例如 JSON。例如,基於 JSON 的檢視模組遵循相同的約定慣例 — 在嘗試 render/2
之前,Phoenix 在渲染索引範本時將首先尋找 index/1
函式。這讓我們得以簡化一般的 JSON 渲染,並擺脫 Phoenix.View.render_one|render_many
等概念。
例如,這是一個由 phx.gen.json
所產生的 JSON 檢視
defmodule AppWeb.PostJSON do
alias AppWeb.Blog.Post
@doc """
Renders a list of posts.
"""
def index(%{posts: posts}) do
%{data: for(post <- posts, do: data(post))}
end
@doc """
Renders a single post.
"""
def show(%{post: post}) do
%{data: data(post)}
end
defp data(%Post{} = post) do
%{
id: post.id,
title: post.title
}
end
end
注意一下它全都僅是規範的 Elixir 函式,這本就應該是這樣的!
這些功能提供一個統一的渲染範例,提供一個新的且改善的方法撰寫 UI 給後續的應用程式,但它們與過往的實務有些差異。大多數大型、已建置的應用程式可能最適合持續依賴 Phoenix.View
。
替代網路伺服器支援
感謝 Mat Trudel 的努力,我們現在有基礎在 Plug 和 Phoenix 中提供頭等網路伺服器支援,允許其他網路伺服器比如 Bandit 可以交換進入 Phoenix 並享有所有功能,比如 WebSockets、Channels 和 LiveView。如果你對一個純 Elixir HTTP 伺服器有興趣或是在你自己的 Phoenix 項目中給它一個嘗試的話,持續關注 Bandit 這個專案吧!
一如往常地,逐步的升級指南 在那裡,帶領你既有的 1.6.x 應用程式升級到 1.7。
完整的修改記錄可以在 這裡 找到。
如果你有任何問題,可以在 elixir slack 或 論壇 上找到我們。
編碼愉快!
–Chris