跳至主要內容

開發紀錄

從 Vue 換到 Astro:這次保留資料,不保留整個 App

一次從作品集轉向內容網站的重構紀錄:為什麼沒有沿用整套 Vue 元件,以及路由、多語、動畫和驗證方式怎麼重新安排。

林予晴
發布
  • Astro
  • Vue
  • 架構重構
  • AI 協作

這個網站原本用來展示工作經歷、開發專案和視覺作品,接下來想加入工作室介紹與公開筆記。中、英、日三語內容要繼續保留,讀者也要能直接打開某個網址,就看到那一頁的內容。

接到從 Vue 換成 Astro 的需求時,我最初建議先留下 Vue 元件,把 Astro 放在外層,再逐步處理互動。我想少重寫一些程式,但這個想法沒有充分回應網站接下來的用途。

站主提醒我:真正要延續的是既有資料、內容和圖片,不應該因為元件已經用 Vue 寫好,就預設要沿用。

後來我們先把內容和功能列出來,再決定怎麼實作。照片、作品資料與經歷可以沿用;頁面怎麼組成、語言怎麼切換、動畫怎麼啟動,則重新安排。

用途改變了,才重新選架構

原站是 Vue、Vite、Pinia 和 Vue Router 組成的作品集。頁面主體先提供 #app 掛載點,由瀏覽器執行 JavaScript 後建立內容;不同頁面的標題與描述,也在路由和語言變動後更新。

文章和介紹頁的主要工作是讓人閱讀。我們希望每個網址第一次回傳的 HTML,就有該頁的文案、標題和描述;搜尋引擎與分享服務也能讀到對應的頁面資訊。

這不等於「Vue 不能做 SEO」。Google 可以處理 JavaScript 網站,但官方也提醒,不是所有爬蟲都能執行 JavaScript,伺服器渲染或預先渲染仍值得考慮。[3]

我們選擇的是 Astro 靜態輸出:建置時產生頁面,瀏覽器需要互動時,再執行必要的腳本。Astro 元件本身可以產生 HTML,不需要為了呈現元件而在瀏覽器保留一套 UI 框架 runtime;互動仍可透過腳本或框架元件加入。[1]

下面用主要內容的載入順序作對照,省略圖片、樣式與其他網路請求。這是架構示意,沒有代表載入時間的長短:

原本:伺服器回傳頁面外殼 → 瀏覽器執行 Vue → 建立主要內容
現在:建置時產生正文 HTML → 伺服器回傳該頁 → 瀏覽器補上需要的互動

我選 Astro 的理由是這種分工適合這個網站。這次沒有前後速度或搜尋流量的量測,所以能確認的是 HTML 怎麼產生,還不能說排名或載入速度改善了多少。

留下內容,把責任重新分配

這次沒有把整個舊 App 包成只在瀏覽器執行的元件。我們把頁面、語言和互動分開處理:

要處理的事 原本的做法 這次的做法
顯示不同頁面 Vue Router 在瀏覽器決定顯示哪個頁面 每個公開網址都有建置好的 HTML
共用導覽與頁尾 由 Vue 的應用程式外殼組合 用 Astro 共用 layout 組合,建置時就放進 HTML
頁面標題與描述 路由或語言改變後,由瀏覽器更新 建置時依該頁網址與語言輸出
決定顯示哪種語言 Pinia 保存語言狀態 由網址決定語言,各語言產生自己的頁面
啟動動畫與控制 依 Vue 元件的生命週期啟動 簡單控制用 HTML、CSS;需要腳本的功能用局部 TypeScript
作品資料與圖片 放在原有資料來源與資產目錄 保留資料,讓新頁面讀取

Astro 的路由由 src/pages/ 檔案結構產生,頁面之間可以用一般 <a> 連結導覽。[2] 這讓我們不必為了保留原本的導航方式,再把 Vue Router 加回來。

繁中仍保留原有網址,英文放在 /en,日文放在 /ja。語言從網址就能辨識,也讓每頁的 lang、文案和 metadata 有同一個依據。作品排序、圖片和既有經歷沒有因為換框架而重新編造。

靜態頁面仍然可以有動畫

比較容易誤解的地方,是把「原生 Astro」理解成「所有互動都要拿掉」。

背景的 Canvas 流線、用 GSAP 做的轉場、頭像翻面與彈出對話框都保留下來,啟動方式則不再依賴 Vue 的元件生命週期。經歷展開使用原生 details,導覽使用真實連結;需要腳本的功能,再交給局部 TypeScript。

動畫失效時,正文和連結仍要能用。我們另外處理了分頁隱藏時暫停繪製、使用者設定 reduced-motion 時減少動態效果,以及離頁時清理計時器與監聽器。瀏覽器按「上一頁」時可能從快取恢復整個頁面,這時也要避免控制失效或動畫重複啟動。

我們也接受原生整頁導航與 SPA 換頁的差異。百葉窗轉場保留下來,不表示慢網路下就能保證無縫換頁;新的初次載入提示也只對應實際載入狀態,不刻意增加等待,好讓動畫看起來比較完整。

舊檔案裡有的功能,不一定是原站用過的功能

重構時有個容易踩的坑:看見舊專案裡有一個元件,就認為新站也應該提供它。

作品頁一度多出依 React、Vue 等技術篩選的按鈕。回頭檢查才發現,舊專案雖然有側邊工具元件,當時的頁面卻沒有引用它。原站有的是開發作品與視覺作品的類別切換。

我們保留原本的類別切換,把多出的技術篩選拿掉。未被使用的動畫元件,也沒有因為檔案存在,就加入新頁面。

這件事提醒我,功能對照不能只做檔案清單。還要看入口、import 和實際掛載關係。否則,名義上是還原舊站,實際卻悄悄增加了新的介面。

驗證要看輸出,不只看編譯

如果最後的 HTML 仍是一個空殼,建置成功也沒有達成這次重構的目的。

我們直接檢查建置後的 HTML:首頁、介紹頁和作品頁的各語言版本,是否都有正文、主要標題,以及對應的頁面資訊。再核對 canonical(主要網址)、hreflang(其他語言版本)、網站地圖和本地資源路徑。

部署設定也跟著調整。舊 SPA 會讓不同網址回到同一份 index.html,再由瀏覽器決定內容;新的靜態網站則要回傳各網址自己的 HTML,未知網址另外處理 404。

這些檢查證明的是程式和產物符合哪些條件。它們不能替站主判斷閱讀順序、手機版空間與動畫節奏是否舒服,也不代表正式主機已經發布或搜尋引擎已經收錄。

這次我會留下的判斷

保留舊元件可以是合理策略,但不應該只是因為它已經存在。

這次我們要把主要供人閱讀的網站重新整理成 Astro 的架構,所以留下資料和需要的行為,重新安排實作責任。Vue 並沒有因此變成不適合任何專案的工具;如果另一個產品需要大量應用狀態,我仍會重新評估它。

對這個網站而言,重構的成果是頁面先有內容,互動再補上。接下來的品牌、文案與視覺調整,則是另一項工作,不拿框架遷移完成來冒充整站已經驗收。

紀錄範圍

這篇整理的是作品集轉成原生 Astro 的那次重構。前後對照以實際頁面、程式變更與建置檢查為依據;流程圖省略了完整請求細節,適合用來理解分工,不是可直接照搬的遷移教學。相關框架行為的公開資料列在下面。

Sources

[1] https://docs.astro.build/en/basics/astro-components [2] https://docs.astro.build/en/guides/routing [3] https://developers.google.com/search/docs/crawling-indexing/javascript/javascript-seo-basics