{% extends "base.html" %} {% from "_parts.html" import defs, lesson, prose %} {% from "ui/layout.html" import page_header, stack %} {# 這一頁是給「要不要用」的決定,不是給「怎麼用」的任務。 站上其他每一頁都預設你已經選了 fjkit。這一頁沒有,而這是讀者最先需要的: 其他做法的代價,以及這個做法的代價。兩節,不多。範圍與反目標是 CHARTER.md 第 2.1 與 2.4 節的事,不在這裡重述。 這一頁受兩條規則約束。 一:不指名任何競品。比較產品的頁面會因為別人發版而過期,而且會把讀者引去爭論 別人的取捨,而不是做自己的決定。三種做法,用它們本身是什麼來命名。 二:這裡列的每一項代價都是真的,而且以代價的語氣寫。一個沒有人能據以行動的 「什麼時候不要用」,只是換了謙虛語氣的行銷。 行文規則:一句話講一件事,結論放前面。 #} {% set sections = [ {"id": "ways", "num": "01", "title": "三種做法"}, {"id": "costs", "num": "02", "title": "這個做法的代價"}, ] %} {% block content %} {% call stack(8) %} {% set intro %} 其他做法的代價,以及這個做法的代價。在你決定形狀之前讀,不是之後。 {% endset %} {{ page_header("為什麼選 fjkit,以及什麼時候不要", intro) }} {# ============================================================== 01 #} {% set w01 %}三種做法,以及各自的代價。{% endset %} {% call lesson("ways", "01", "幫 FastAPI app 做介面的三種做法", w01) %} {% call prose() %}
這三種都沒有錯。差別在代價是什麼,以及代價什麼時候才出現。
{% endcall %} {{ defs("① 模板加上自己的 CSS", [ ("你要寫的", "Jinja,外加一份你自己擁有的 stylesheet——手刻的,或是一套你自己編譯的 utility 框架"), ("代價", "一套你本來沒打算做的設計系統。間距、狀態、focus ring、深色模式與無障礙全是你的,而且會隨著 app 變大而腐化,因為某一頁偏離其他頁時,不會有任何東西失敗"), ("什麼時候適合", "頁面只有幾頁,或者你要的外觀沒有現成東西給得起"), ]) }} {{ defs("② 前端自己渲染", [ ("你要寫的", "一個元件化的前端應用,與 API 分開供應、分開部署"), ("代價", "多一套建置、多一種語言、多一個要部署的東西。你的資料會被塑形兩次——一次給 API、一次給畫面——而原本由伺服器回答的載入中、錯誤與空狀態,變成你要自己拿著"), ("什麼時候適合", "真的有客戶端狀態:編輯器、畫布、即時文件,任何在兩次請求之間還要繼續運作的東西"), ]) }} {{ defs("③ 伺服器渲染的元件套件——也就是這一個", [ ("你要寫的", "回傳 model 的 handler,以及呼叫 macro 的模板。瀏覽器拿到的是 HTML"), ("代價", "見第 02 節"), ("什麼時候適合", "後台、內部工具、內容網站、admin——在你已經有的 API 上做一個真正的介面,以「頁」為單位,而伺服器本來就什麼都知道"), ]) }} {% endcall %} {# ============================================================== 02 #} {% set w02 %}三件你要放棄的事。每一件都是第 01 節某樣東西的價錢。{% endset %} {% call lesson("costs", "02", "這個做法的代價", w02) %} {# 前兩項裡有,所以用 `{% set %}` 區塊而不是純字串:區塊產生 Markup,
純字串會被跳脫。第三項沒有標記,維持字串。
#}
{% set c_css %}class 詞彙表是封閉的,fjkit check 會讓任何在它之外的東西 build 失敗。這正是「不用 build」買來的:stylesheet 能在你還不存在時就編譯好,只因為你的模板能要求什麼是事先知道的。當一個版面看起來需要某個 utility,答案是一個 macro 參數——也就是一次上游修改,而不是一次本地修改{% endset %}
{% set c_missing %}gate 會擋下那個 class,而它指出來的東西必須先做出來,那一頁才出得去。fjkit eject 把 macro 複製進你的倉庫當逃生門——而你接手的那份檔案從此收不到上游修正,所以文件不主推它{% endset %}
{{ defs("這筆交易", [
("你不能自由寫 CSS", c_css),
("kit 還沒寫的元件會卡住你", c_missing),
("外觀一開始是別人的", "出貨八個風格包,改一個 token 就能把整站重新上色,但這仍然是一套你採用的設計系統,不是你撰寫的"),
]) }}
{% call prose() %}
前兩項是同一筆交易的兩端,而那就是這筆交易:窄到可以預先編譯的詞彙表,
也就窄到會用完。
{% endcall %}
{% endcall %}
{% endcall %}
{% endblock %}