為什麼文字系統這麼困難,我花十年繞了不少路,才發現文字與程式關係的本質。
一、開始:只想要一個最爛的網站
大約十年前,我的需求單純到近乎天真:我只想要一個地方紀錄我的筆記。
最早,我像大多數人一樣,試過各大部落格平台。Google Blogger 用過,Medium 也寫過一陣子。它們方便,一鍵發佈,但問題很快就浮現:我被平台綁架了。
當我想搬家時,發現內容搬不走,格式亂成一團,SEO 要從頭來過。我受夠了這種「租房子」的感覺,我想要自己的土地,自己的房子。於是我決定一切自己來。
那時候的我,甚至覺得資料庫是多餘的。我在 GitHub 上建了個 repo,把路由邏輯直接映射到檔案系統結構。 home/README.md 是首頁,about/README.md 是關於我,tech/linux/README.md 是技術文章。
每個目錄一個檔案,這就是我的網站。純粹,直接,醜陋但實用。當時我覺得自己很聰明:沒有後端,沒有 Render Loop,就是最原始的 HTTP 檔案傳輸。
但很快地,這種「原始」變成了一種折磨。沒有共用的導覽列,我每寫一篇新文章,就要手動複製貼上 HTML header;沒有樣式管理,整個網站看起來像是 1990 年代的佈告欄。
於是我踏入了 Jekyll 的世界。
Jekyll 讓我第一次體驗到「樣板(Template)」的威力。套上一個 Theme,網站瞬間像樣了。但隨著我對內容的要求變高,痛苦也隨之而來。
我想在文章裡加入互動圖表,或者一個動態的程式碼展示區。在 Jekyll 的邏輯裡,這是一場災難。
我必須在 _includes/ 資料夾裡建立 chart.html,裡面塞滿了 <script> 標籤和 Liquid 邏輯。然後在 Markdown 裡,我得用一種奇怪的語法去呼叫它。
我的專案結構變成了義大利麵:
- Markdown 負責內容,但混雜了 Liquid 標籤。
- HTML 負責結構,但混雜了 JavaScript 邏輯。
- JS 負責互動,但必須依賴 Liquid 注入變數。
每當我要修改一個圖表的顏色,我得同時打開 Markdown 檔、HTML layout 檔和 CSS 檔,在三個視窗間切換,腦袋裡的 Stack 不斷溢出。
我開始逃避。我試過 Hugo(太快但更難改),試過 Gatsby(React 生態系太重,光是設定 Webpack 和 GraphQL 就花掉我寫作的力氣)。
直到我遇見了 Web Components 和 Svelte。
這是我第一次感受到「關注點分離」的真正力量。我不再需要 Jekyll 去處理複雜的邏輯。
嘗試了 Lit 寫 wc,覺得 Lit 是極其反人類的寫法,差點放棄之餘意外發現 Svelte 也能 compile as wc。
我用 Svelte 寫好一個乾淨的 <my-chart> 元件,編譯成標準的 Web Component。 在 Markdown 裡,我只需要寫: <my-chart data="[1,2,3]"></my-chart>
Jekyll 瞬間退化成一個只負責 content 的空殼路由,而 Svelte 接管了所有互動。那一刻,世界清靜了。Markdown 負責說故事,Component 負責變魔術,兩者互不干擾。
跟 AI 聊天後發現,這就是現代的 Islands Architecture 設計理念,而 Astro 正是這個概念的極致。
二、寫書:排版的無底洞
在折騰部落格的同時,我也曾經試圖寫書。
研究所時期,為了寫論文,我被迫使用 LaTeX。那是一種強大但也極其痛苦的體驗。 我們實驗室有一個代代相傳的 Git repo,裡面是學長姐們留下來的 thesis.tex,充滿了沒人敢動的神祕巨集。 而這個模板,也是來自各學校之間 fork 多次改良的參天大樹。
更痛苦的是,LaTeX 的錯誤訊息如同天書。 一個 misplaced \noalign 或者是漏掉一個 },可以讓我 Debug 兩小時。編譯器噴出的 Log 只有幾行是有用的,其他都是雜訊。
我常常盯著螢幕發呆:我真的在寫書嗎?還是其實在學這該死的排版系統?
後來我想,既然 Markdown 這麼好用,能不能直接用 Markdown 寫書?
我嘗試用 Pandoc 直接轉 PDF。結果慘不忍睹——頁面斷在不該斷的地方,圖片位置亂跑,字型不一致,甚至連基本的段落間距都無法讓人滿意。
「那直接寫 HTML 呢?」我想。HTML 控制力最強,只要瀏覽器能顯示,我就能輸出。
於是我開始手寫 HTML 書稿。但寫了幾頁後,我發現自己陷入了另一種地獄:我不斷在調整 <div> 的 margin 和 padding,為了讓標題好看一點而寫了一堆 CSS class。
我又回到了排版地獄,只是從 LaTeX 換成了 CSS。
經過無數次失敗,我最終發現了一條沒人告訴過我的捷徑:HTML 是萬能的中間層。
我不該去手寫 HTML,也不該去學 LaTeX。 正確的路徑是:
- 專注寫 Markdown(純粹的資料)。
- 用 Svelte/Template 把 Markdown 渲染成 HTML(自動化的樣式)。
- 用瀏覽器 (Chromium) 的 Print 功能輸出 PDF(最強的渲染引擎)。
這條 Pipeline 成了我後來的黃金標準。我不再跟排版對抗,我把排版交給 CSS,把渲染交給瀏覽器,而我,只負責寫字。
三、遊戲與劇本:結構化的敘事工程
解決了排版,我的野心膨脹到了遊戲設計。我曾熱衷於鑽研遊戲機制,也順帶深入學習了劇本創作的概念。
這帶來了一個全新的挑戰:知識庫管理。
為了建構一個完整的世界觀、塑造立體的人物(Characters)以及編排錯綜複雜的劇情線,我需要大量的資料。
起初,我使用 Obsidian。它的雙向連結(Bi-directional linking)非常適合處理這種網狀的知識結構。但很快地,因為我是開發者,我希望能更無縫地整合進我的開發環境,於是我轉用了 VS Code 的插件 Foam。
但這些都還是在「本地端」打轉。當我想要分享、檢索,甚至讓 AI 幫我檢查邏輯時,本地檔案就變成了孤島。
最終,我把這些知識庫全部遷移回了 Jekyll,架在網路上。
為什麼?因為URL 是最棒的索引。
架在網路上不僅方便我自己隨時搜尋,更重要的是容易讓 AI 閱讀。當我需要 AI 幫我分析某個角色的動機時,我只需要把該角色的 URL 丟給它,它就能理解整個上下文。
這段經歷還讓我學會了另一件事:劇本不只是文字,更是資料結構。
在學習好萊塢經典的「救貓咪(Save the Cat)」編劇節奏表(Beat Sheet)時,我意識到,一個標準的商業劇本,其實是有著嚴格 Schema 的。
- 開場畫面 (Opening Image)
- 主題陳述 (Theme Stated)
- 觸發事件 (Catalyst)
- …
這不就是 key-value pair 嗎?
於是我不再用 Markdown 寫劇本大綱,我開始用 YAML。
我定義好 YAML 資料,然後寫好對應的 HTML Template。
不僅是 Beat Sheet,包括複雜的人物設計表(Character Sheet),甚至是給投資人看的「一頁式提案(One-page Pitch)」,最終都套用了這套邏輯:YAML 定義內容,Liquid/HTML 定義結構,CSS 定義美學。
我不需要排版,我只需要「填表」。這讓我可以專注在創意的核心邏輯,而不是文檔的格式。
最終做了yml apply to html template的邏輯,也學會了本能用template html思考。
四、可視化編輯器的試煉 (LangGraph GUI)
處理完結構化的文字資料,我又給自己找了個麻煩:我想做一個 AI 工作流的可視化編輯器(類似 ComfyUI 或 n8n)。
這是一個高複雜度的 GUI 系統。使用者需要拖拉節點(Nodes)、連接線條(Edges),來構建邏輯。
這段經歷簡直是「技術選型」的血淚史:
-
PyQt 的泥沼 我一開始覺得這是 Desktop App,當然用 Python + PyQt。 但我很快發現,狀態管理是個惡夢。當我拖曳一個節點時,我需要手動計算座標,手動重繪線條,還要處理 Undo/Redo 的 Stack。UI 程式碼和業務邏輯緊緊耦合在記憶體裡,稍微改動一個功能,整個 App 就崩潰。
-
ReactFlow 的重渲染地獄 轉戰 Web 後,我用了 React。React 很強,但 Hook 機制在處理這種高頻互動圖形時,讓我吃盡苦頭。 為了同步節點拖曳的狀態,我必須小心翼翼地處理
useEffect的依賴陣列。 SetState -> Re-render -> Diff -> Patch DOM。 這條路徑太長了。當圖上有 100 個節點時,React 的效能開始卡頓,我寫了大量的useMemo和useCallback只是為了讓它跑順一點。 -
SvelteFlow 的救贖 最後我遷移到了 Svelte 5。 在 Svelte 5 裡,狀態管理變得異常簡單。
$state就是變數,改了它,介面就自己動了。沒有 Virtual DOM 的 Diff 消耗,拖曳變得絲般順滑。
在這個過程中,我悟出了一個道理:一個複雜的 GUI 系統,本質上只是一個 JSON 資料結構的「執行引擎」。
前端看到的那些花俏連線,底層其實就是一張 DAG(有向無環圖)。我的工作不是「畫圖」,而是「管理數據流」。 當我把資料結構(Schema)定義清楚(比如用 JSON 描述節點關係),介面只是隨之而來的副作用。
五、App 開發:平台的迷思
為了讓我的軟體能跑在更多地方,我也嘗試過開發 Mobile App。
從原生的 Kotlin (Android) 到跨平台的 Dart (Flutter),我每一種都試過。 寫 Kotlin 時,我被 Fragment 的生命週期搞得暈頭轉向。 寫 Flutter 時,我雖然享受它的熱重載,但我心裡總有個聲音在問:「為什麼我要為了一個簡單的 List View,去學一套全新的 Widget 語言?」
這讓我很焦慮:難道我要為 Web 寫一套 Svelte,為手機寫一套 Flutter,為桌面寫一套 Qt?
直到我回頭看我的 Web 專案。現在的 Web 技術已經進步到難以置信的地步。 配合 Capacitor 這樣的工具,我可以用同一套 Svelte 代碼,打包成 iOS、Android 和 Desktop App。
我不需要學三種語言。Web 是終極的容器。與其在不同平台間流浪,不如把 Web 技術練到極致。
六、收斂:萬法歸一
經過這十年的折騰,從寫最爛的 README.md 網站,到被 LaTeX 折磨,到結構化劇本的 YAML,到刻畫複雜的 GUI,再到跨平台 App。
我一度以為我在做完全不同的事情,學完全不同的技術。 「我是不是學太雜了?」我常這樣問自己。
但當我靜下心來回顧,我驚訝地發現,這些經歷最後竟然收斂成同一個形狀。
無論是寫部落格、寫書、設計劇本,還是做複雜的軟體系統,本質上我都在解決同一個問題:「如何讓結構化的資訊,高效地流動並呈現給人類。」
看看這些模式是多麼相似:
- 部落格:Markdown (資料) -> Svelte/WC (邏輯) -> HTML (呈現)
- 書籍:Markdown (資料) -> CSS (邏輯) -> PDF (呈現)
- 劇本/設定集:YAML (資料) -> Liquid Template (邏輯) -> HTML (呈現)
- GUI 系統:JSON (資料) -> SvelteFlow (呈現) -> Python (執行邏輯)
- 跨平台 App:Web Bundle (資料與邏輯) -> Capacitor (容器) -> Native App (呈現)
我繞了一大圈,終於把工具箱裡的雜物都丟光了。
我不再糾結要用什麼框架,因為我知道「分離」才是關鍵。 資料層歸資料(Markdown/JSON/YAML),邏輯層歸邏輯(Svelte/Python),展示層歸展示(HTML/CSS)。
為什麼文字系統這麼困難? 因為我們總是試圖把內容、邏輯和樣式混在一起解決。
LaTeX 錯在把排版邏輯混進內容裡;Jekyll 錯在把 JS 邏輯混進 HTML 裡;React 錯在把 State 邏輯混進 UI 渲染裡。
當你把這三者乾淨地切開,你會發現,不管是寫一篇文章,還是開發一個企業級系統,其實都是同一件事。
那些我曾經以為是彎路的「鏟土」過程,最終讓我看清了程式與文字關係的本質。這把磨了十年的瑞士刀,現在終於鋒利了。