跳到主要內容

FE Day 44 系列總結

FE Day 44 系列總結

執行需求:CPU 可跑。今天是「前端開發實戰:React 與 Next.js 全套」系列的第四十四天,也是貫穿專案「預約管理系統前端」的收尾日。今天做四件事:第一,把 44 天的路徑完整回顧一次,說清楚每個階段為什麼排在這個位置;第二,寫一支盤點腳本,用客觀數字回答「這個專案最後到底交付了什麼」;第三,跑一次完整的驗收流程(型別檢查、lint、單元測試、端對端與無障礙檢查、production 建置),並把結果寫成結案報告;第四,標記 v1.0.0 並列出已知限制。今天不引入任何新工具、不新增功能,全部沿用 Day 31–43 的共用設定,在 CPU 上就能完整跑完。

引言

學習系列最容易被跳過的就是最後一天。前面每一天都有明確的產出(一個元件、一支測試、一次部署),到了總結日反而變成「說感想」,讀者看過就忘。今天刻意反過來做:把總結變成一次可執行的驗收。因為「這個系列到底學到什麼」這個問題,不該用形容詞回答,而該用「跑得過的檢查、數得出來的檔案、說得出理由的決定」回答。

貫穿專案的「預約管理系統」是個小型服務業線上預約平台(情境涵蓋攝影棚、健身教練、諮詢工作室,所有資料都是虛構示範)。這個專案從 2026 年 3 月 17 日的導論開始,到今天剛好走完 44 篇:從 Node.js 22 與 pnpm 的環境配置、TypeScript 5.9 的型別系統、React 19.x 的元件與狀態、Vitest 3.x 與 Playwright 1.5x 的測試、Next.js 15 的 App Router 與 Server Components,一路做到 Day 31–43 的 11 個頁面、兩角色登入、三層錯誤處理、效能調校、部署與交接資料。今天的任務是把這些片段接成一條線。

今天的內容分四段:第一段把 Day 31–43 的共用設定做最後一次統整;第二段說明這 44 天的路徑設計邏輯,以及「後端工程師轉全端」真正的心態變化;第三段實作盤點腳本、結案報告產生器、發布前檢查與完整驗收 workflow,最後標記 v1.0.0;第四段講這個專案接下來最該補的三個地方。讀完之後你會拿到一份自己的結案報告範本,以及一套能在任何專案重複使用的驗收清單。

貫穿專案共用設定(Day 31–44 沿用)

這份設定從 Day 31 一路用到今天,是整個專案篇的基準,也是結案報告要記錄的核心事實:

  • 框架:Next.js 15(App Router、Server Components 預設)、React 19.x、TypeScript 5.9
  • 樣式:Tailwind CSS 4.x、CSS variables 設計 token、Day 32 的 components/ui/(Button、Input、Card、Badge、Dialog、Toast)
  • 路由:11 個頁面,公開 5(/、/services、/services/[id]、/login、/register)、客戶 2(/bookings、/bookings/new)、後台 4(/admin、/admin/bookings、/admin/services、/admin/services/[id]/slots)
  • 認證:JWT access token(12 小時)、refresh token(14 天,httpOnly cookie);Day 38 的 AuthProvider 共 5 個 action
  • 資料層:lib/api/ 統一出口,依 NEXT_PUBLIC_API_MODE 切換 mock 與 live,後端為 Web 系列 Day 35–44 的 FastAPI
  • 品質工具:Vitest 3.x、Playwright 1.5x、axe-core 4.x、ESLint 9 flat config
  • 維運:Vercel 三層環境變數、GitHub Actions CI、RUNBOOK 與七份交接資料
  • 版本:v1.0.0,日期 2026-04-15

這份設定刻意從頭到尾不變,只在既有結構上「加能力」。回顧起來,整個專案沒有任何一次回頭重寫架構、沒有換過狀態管理工具、沒有改過路由表;所有新增(登入、錯誤處理、效能、a11y、交接資料)都是疊在同一層地基上。這個「地基不動」的性質,本身就是專案設計成功與否最直接的證據。

原理解念:路徑設計與後端轉全端的心態變化

這 44 篇的順序不是隨意排的,背後有三條設計原則。第一條是「工具先於框架」:Day 1–16 先把 Node.js、pnpm、TypeScript、React、測試與專案結構講完,才在 Day 17 進入 Next.js。原因是 Next.js 的許多行為(Server Component 的邊界、快取的預設值、build 與 dev 的差異)要看得懂,前提是你已經知道底層的 React 怎麼運作。跳過底層直接學框架,會變成「只會照著官方文件貼程式碼」,一遇到例外就只能猜。

第二條是「品質與上線在框架之後、專案之前」:Day 25–30 才講效能、圖片、E2E、無障礙、部署與監控。這個位置是刻意的——品質工具需要「有東西可以量」才有意義。如果在 Day 5 就講 Lighthouse 分數,讀者量到的是一個沒有資料的空白頁;等到 11 個頁面都做完再量,每一個數字都對應一個具體的畫面與一段可以改的程式碼。第三條是「專案放在最後」:Day 31–44 用 14 天的篇幅把前面所有知識組裝成一個真的能交付的系統。只有走過這一輪,前面學到的每個名詞才會各自找到位置。

至於心態上的變化,最大的轉折是「從回傳值到使用者感受」。後端工程師習慣的品質判準是確定的:回應時間、錯誤率、資料一致性,這些都可以量、可以寫測試。前端的品質有一部分同樣可量(LCP 2.5 秒、INP 200 毫秒、CLS 0.1、a11y 零違規),但也有一大塊是後端很少處理的:使用者在等待時看到什麼、表單填錯時知不知道怎麼改、鍵盤使用者能不能完成預約、手機單手操作會不會誤觸。這些事情的共同點是「不影響功能,但決定使用者會不會繼續用」。Day 37 的錯誤處理與 Day 42 的總檢,本質上就是在補這一塊。

第二個轉折是「從單一服務到整體交付」。後端交付通常是一組端點與一份 API 規格;前端交付的是「一個使用者可以打開、可以完成任務、出事時有人知道怎麼處理」的完整體。所以專案篇的後半段(Day 41–43)幾乎都在處理「營運」:環境變數分三層、CI 守門、Runbook、交接資料。這些工作不會讓畫面變漂亮,卻決定了這個系統在沒人盯著的週末能不能活下來。

完整實作:盤點、結案報告、發布前檢查與 v1.0.0

第一步,先把六個階段的回顧寫成資料。這份資料同時是結案報告的目錄,也是「這個系列走過哪些路」的壓縮版。

// docs/LEARNING-PATH.mjs
// 44 天路徑的回顧資料:每個階段的主題、涵蓋篇章與交付物。
export const PHASES = [
  {
    name: '導論',
    days: 'Day 1-2',
    theme: '後端工程師的前端地圖、環境與工具鏈',
    deliverable: '可執行的 Node.js 22 與 pnpm 環境、ESLint 9 flat config',
  },
  {
    name: '基礎',
    days: 'Day 3-8',
    theme: 'TypeScript 型別系統、React 元件與 JSX、狀態與渲染、Tailwind',
    deliverable: '型別安全的元件寫法、可組合的樣式慣例',
  },
  {
    name: '核心',
    days: 'Day 9-14',
    theme: 'useEffect 的時機、自訂 Hook、狀態管理、表單、元件設計、資料取得',
    deliverable: '可重用的鉤子、受控表單、伺服器狀態的快取策略',
  },
  {
    name: '品質',
    days: 'Day 15-16、25-28',
    theme: '測試、專案結構、Core Web Vitals、資源最佳化、E2E、無障礙',
    deliverable: 'Vitest 與 Playwright 測試層、效能預算、a11y 檢查',
  },
  {
    name: 'Next.js',
    days: 'Day 17-24',
    theme: 'App Router、巢狀路由、Server 與 Client Components、表單與 Server Actions、認證、metadata、Route Handler',
    deliverable: '可用的 Next.js 15 應用骨架與認證流程',
  },
  {
    name: '上線與專案',
    days: 'Day 29-44',
    theme: '部署、監控、預約系統前端、效能實戰、測試驗收、總檢、交接',
    deliverable: 'v1.0.0:11 個頁面、兩種角色、可交接的完整系統',
  },
];

第二步,寫盤點腳本。這支腳本只做一件事:把「事實」數出來。它不評估品質、不下判斷,只回報檔案數、程式行數、元件數與測試檔數。刻意保持客觀,是因為結案報告一旦混入主觀評價就會失去可信度;判斷的部分留給人寫在報告的另一節。

// scripts/audit-project.mjs
// 掃描專案,輸出客觀的規模盤點。
// 執行:node scripts/audit-project.mjs
import { readdir, readFile } from 'node:fs/promises';
import path from 'node:path';

const ROOTS = ['app', 'components', 'lib', 'hooks', 'tests'];
const IGNORE = new Set(['node_modules', '.next', '.git', 'coverage']);

async function walk(dir) {
  const found = [];
  for (const entry of await readdir(dir, { withFileTypes: true })) {
    if (IGNORE.has(entry.name)) continue;
    const full = path.join(dir, entry.name);
    if (entry.isDirectory()) found.push(...(await walk(full)));
    else if (/\.(ts|tsx|mjs)$/.test(entry.name)) found.push(full);
  }
  return found;
}

const files = [];
for (const root of ROOTS) {
  try {
    files.push(...(await walk(root)));
  } catch {
    // 目錄還不存在就跳過,讓腳本在專案任何階段都能執行
  }
}

let totalLines = 0;
let componentFiles = 0;
let testFiles = 0;
let apiFiles = 0;

for (const file of files) {
  const normalized = file.split(path.sep).join('/');
  const source = await readFile(file, 'utf8');
  totalLines += source.split('\n').length;
  if (normalized.startsWith('components/') && normalized.endsWith('.tsx')) componentFiles += 1;
  if (/\.(test|spec)\./.test(normalized)) testFiles += 1;
  if (normalized.startsWith('lib/api/')) apiFiles += 1;
}

console.log('=== 專案盤點(客觀事實)===');
console.log(`TypeScript 檔案:${files.length}`);
console.log(`程式行數:${totalLines}`);
console.log(`元件檔(components/**/*.tsx):${componentFiles}`);
console.log(`資料層檔案(lib/api/**):${apiFiles}`);
console.log(`測試檔(*.test.* / *.spec.*):${testFiles}`);

第三步,把盤點結果寫成結案報告。這份報告不是給自己看的感想,而是給「未來要接手的人」看的入門資料,所以它必須包含三件客觀內容:交付了什麼、目前的規模、已知限制。產生過程全部自動化,避免手寫數字與實際專案不一致。

// scripts/build-delivery-report.mjs
// 讀盤點結果與 Git 版本,產生 docs/DELIVERY.md。
// 執行:node scripts/build-delivery-report.mjs
import { execFile } from 'node:child_process';
import { writeFile } from 'node:fs/promises';
import { promisify } from 'node:util';

const run = promisify(execFile);

const { stdout: audit } = await run(process.execPath, ['scripts/audit-project.mjs']);
const { stdout: sha } = await run('git', ['rev-parse', '--short', 'HEAD']);

const DELIVERABLES = [
  { name: '11 個頁面', detail: '公開 5、客戶 2、後台 4' },
  { name: '登入狀態機', detail: 'BOOTSTRAP / LOGIN / REFRESH / LOGOUT / EXPIRE' },
  { name: '設計系統', detail: 'components/ui 的 6 個基礎元件,以 CSS variables 控制主題' },
  { name: '資料層', detail: 'mock 與 live 雙模式,只有 lib/api-mode.ts 一個切換點' },
  { name: '錯誤處理', detail: 'Toast、ErrorBoundary、欄位驗證三層' },
  { name: '測試', detail: 'Vitest 單元、Playwright 端對端、axe 無障礙、四斷點檢視' },
  { name: '部署與維運', detail: 'Vercel 三層環境變數、CI、Runbook' },
];

const KNOWN_LIMITS = [
  'Serverless 冷啟動約 200-500 毫秒,屬預期行為',
  'mock 模式的示範資料重新整理後會還原',
  '尚未實作金流、訊息推播、評論評分',
];

const markdown = [
  '# 結案報告:預約管理系統前端 v1.0.0',
  '',
  `- 建置版本:${sha.trim()}`,
  `- 產生時間:${new Date().toISOString()}`,
  '',
  '## 交付內容',
  '',
  ...DELIVERABLES.map((item) => `- **${item.name}**:${item.detail}`),
  '',
  '## 客觀盤點',
  '',
  '```',
  audit.trim(),
  '```',
  '',
  '## 已知限制',
  '',
  ...KNOWN_LIMITS.map((limit) => `- ${limit}`),
  '',
].join('\n');

await writeFile('docs/DELIVERY.md', markdown, 'utf8');
console.log('已產生 docs/DELIVERY.md');

第四步,寫發布前檢查。標記版本之前先確認「交接資料、環境變數與版本號都對得上」。這支腳本的最大價值是把「發布前的儀式」變成可重複執行的檢查;只要有任何一項沒準備好,它就結束並列出問題,不會讓人靠記憶逐項確認。

// scripts/check-release.mjs
// v1.0.0 前的守門檢查:版本號、交接資料、環境變數範例是否同步。
// 執行:node scripts/check-release.mjs
import { readFile } from 'node:fs/promises';

const REQUIRED_DOCS = [
  'README.md',
  'RUNBOOK.md',
  'CONTRIBUTING.md',
  'docs/ARCHITECTURE.md',
  'docs/API-CONTRACT.md',
  'docs/env-vars.md',
  'docs/DELIVERY.md',
];

const REQUIRED_ENV = [
  'NEXT_PUBLIC_API_BASE_URL',
  'NEXT_PUBLIC_API_MODE',
  'NEXT_PUBLIC_APP_URL',
];

const problems = [];

const pkg = JSON.parse(await readFile('package.json', 'utf8'));
if (!/^1\.\d+\.\d+$/.test(pkg.version)) {
  problems.push(`版本號應為 1.x.y,目前是 ${pkg.version}`);
}

for (const doc of REQUIRED_DOCS) {
  try {
    const content = await readFile(doc, 'utf8');
    if (content.trim().length < 200) problems.push(`${doc} 內容過短`);
  } catch {
    problems.push(`${doc} 不存在`);
  }
}

const envExample = await readFile('.env.example', 'utf8');
for (const name of REQUIRED_ENV) {
  if (!envExample.includes(name)) problems.push(`.env.example 缺少 ${name}`);
}

if (problems.length > 0) {
  console.error('發布前檢查未通過:');
  for (const problem of problems) console.error(`- ${problem}`);
  process.exit(1);
}

console.log(`發布前檢查通過:v${pkg.version} 可以標記`);

第五步,把版本升到 1.0.0 並補上常用指令。我們刻意讓 verify 這一個指令涵蓋所有檢查,這樣不論是本機、CI 或未來的隊友,都只需要記住一個入口。

// package.json(節錄)
{
  "name": "booking-frontend",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "typecheck": "tsc --noEmit",
    "lint": "eslint .",
    "test": "vitest run",
    "test:e2e": "playwright test",
    "audit": "node scripts/audit-project.mjs",
    "report": "node scripts/build-delivery-report.mjs",
    "check:release": "node scripts/check-release.mjs",
    "verify": "pnpm typecheck && pnpm lint && pnpm test && pnpm test:e2e && pnpm build"
  }
}

第六步,跑一次完整驗收。以下六道指令就是 v1.0.0 的驗收流程,順序刻意「由快到慢」:能在 10 秒內失敗的檢查排在前面,避免跑完 3 分鐘的端對端測試才發現型別有錯。

# v1.0.0 驗收流程(由快到慢,任一步失敗就停止)
pnpm typecheck                 # 型別檢查,約 5 秒
pnpm lint                      # ESLint 9,約 3 秒
pnpm test                      # Vitest 單元與元件測試,約 8 秒
pnpm test:e2e                  # Playwright 端對端、a11y、四斷點,約 90 秒
pnpm audit                     # 盤點專案規模
pnpm report                    # 產生 docs/DELIVERY.md
pnpm check:release             # 發布前守門檢查
pnpm build                     # production 建置,確認能上線

# 全部通過後標記版本
git add -A
git commit -m "chore(release): v1.0.0 預約管理系統前端"
git tag -a v1.0.0 -m "預約管理系統前端 v1.0.0"
git push origin main --tags

第七步,把這整套流程放進 workflow。CI 的職責就是「用同一組指令驗證每一個 PR」,所以它與本機的驗收流程必須一模一樣;只要有一邊多做了什麼或少做了什麼,就會出現「本機過、CI 不過」的假警報。

# .github/workflows/verify.yml
name: verify

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  verify:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    env:
      NEXT_PUBLIC_API_MODE: mock
      NEXT_PUBLIC_API_BASE_URL: http://127.0.0.1:8000
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with: { version: 9 }
      - uses: actions/setup-node@v4
        with: { node-version: '22', cache: 'pnpm' }
      - run: pnpm install --frozen-lockfile
      - run: pnpm typecheck
      - run: pnpm lint
      - run: pnpm test
      - run: pnpm exec playwright install --with-deps chromium
      - run: pnpm test:e2e
      - run: pnpm check:release
      - run: pnpm build
      - uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: playwright-artifacts
          path: |
            playwright-report/
            tests/__screenshots__/

第八步,做一次能力盤點。結案報告記錄專案,能力盤點記錄自己。每一項都要求「說得出證據」,因為能力只有能展示才算數;寫不出證據的能力,就是下一步該補的地方。

// docs/SELF-ASSESSMENT.md 的資料來源:scripts/self-assessment.mjs
// 每一項能力都對應一個可以拿出來看的具體成果。
export const SKILLS = [
  {
    skill: 'TypeScript 型別設計',
    evidence: 'tsconfig 開啟 strict;公開介面都有明確型別;泛型用於清單與格式化工具',
  },
  {
    skill: 'React 元件與狀態',
    evidence: '設計系統 6 個基礎元件;useReducer 管理的登入狀態機;自訂鉤子 useMediaQuery',
  },
  {
    skill: 'Next.js App Router',
    evidence: '11 個頁面;Server 與 Client Component 的邊界決策;Route Handler 轉發層',
  },
  {
    skill: '資料取得與快取',
    evidence: '公開頁面 ISR 60 秒、個人頁面強制動態;TanStack Query 的 queryKeys 集中管理',
  },
  {
    skill: '測試',
    evidence: 'Vitest 覆蓋 reducer 與 API 客戶端;Playwright 覆蓋三條核心流程與無障礙掃描',
  },
  {
    skill: '效能',
    evidence: '效能預算檔與 CI 守門;圖片與字型最佳化;bundle 分析紀錄',
  },
  {
    skill: '無障礙與響應式',
    evidence: 'axe 掃 11 頁零嚴重違規;四斷點檢查水平溢出與觸控目標',
  },
  {
    skill: '部署與維運',
    evidence: 'Vercel 三層環境變數;CI workflow;Runbook 含已知限制',
  },
  {
    skill: '交接資料',
    evidence: 'README、架構地圖、API 契約、環境變數清單、三份 ADR、結案報告',
  },
];

常見錯誤與踩雷

第一個常見錯誤是「把結案報告寫成心得」。用了哪些形容詞不重要,重要的是「交付了什麼、規模多大、限制在哪」。我們的結案報告刻意分成三節:交付內容(可勾選的具體成果)、客觀盤點(腳本產生的數字)、已知限制(誠實列出沒做的事)。這三節加起來,讀者能在五分鐘內判斷「這個專案能不能拿去用」。

第二個踩雷是「盤點數字用手寫」。手寫的數字幾乎一定過期,而且會出現「報告寫 20 個元件、實際已經 26 個」這種落差。修法是把數字交給腳本,人只負責解讀。我們的 audit-project.mjs 只輸出事實、不做評價;評價寫在另一份紀錄裡,兩者不會互相污染。

第三個是「版本標記與驗收脫鉤」。先把版本號改好、push、才想起來要跑測試,於是把一個沒驗證過的版本標成正式版。修法是把順序固定下來:先跑完六道驗收,再標版本;check-release.mjs 就是用來把這個順序機械化,只要交接資料或環境變數沒備齊就擋下來。

第四個是「已知限制不敢寫」。怕寫出來顯得專案不完整,所以只寫優點。這是短視的做法:如果不寫「冷啟動會慢 200-500 毫秒」,接手的人會在第一次遇到時誤判成故障、花時間搶修,甚至做錯的處置。把限制寫清楚,等於把未來的一次誤判先擋掉。

第五個是「沒有定義『完成』」。專案很容易無限延伸:再加一個篩選、再補一個圖表、再把樣式打磨一下。沒有明確定義的完成線,專案就永遠不會進入「交付」狀態。今天的 v1.0.0 就是那條線:11 個頁面、兩角色、測試與無障礙通過、部署與交接資料齊備,到此為止;剩下的想法寫進待辦,不塞進 v1.0.0。

效能與實務提醒

驗收流程的「順序」比「內容」重要。我們把型別檢查放第一位,是因為它最快、最便宜、又能抓到最常見的錯誤(欄位改名、參數型別不符)。把它放最後的人,會在 CI 上白等三分鐘。這個原則可以推廣成:任何檢查流程都應該「把最便宜且最常見的失敗放前面」,這是投資報酬率最高的一種調校。

另一個提醒是「結案後不要馬上動地基」。v1.0.0 之後最常見的錯誤決策,是趁著記憶還新鮮就「順手」換掉狀態管理工具或重寫路由結構。這種重構在沒有明確需求時幾乎一定是虧的:它會讓所有已驗證過的行為重新變成未驗證,也讓交接資料立刻過期。要動架構就開一份 ADR,寫清楚「為什麼現在的地基不夠用」,再決定要不要動。

盤點腳本要放在 CI 還是本機?我們的建議是「本機為主、CI 為輔」。盤點結果是給人看的,不需要每次 PR 都跑;但 check-release.mjs 這種守門檢查就該進 CI,因為它的目的是「擋住不該發布的版本」。簡單的判斷方式:輸出報告的腳本放本機,會 exit 1 的腳本放 CI。

最後是「測試的維護成本要納入結案考量」。44 天下來,測試檔會變成專案裡僅次於元件檔的第二大類檔案。它們有自己的折舊:mock 的形狀會與真實 API 漂移、截圖基準會因設計微調而失效、選擇器會因文案改動而斷。結案時應該做一次測試健檢:刪掉重複覆蓋的案例、確認每個測試都能說出「它在保護哪個行為」。一份能被信任的測試套件,比一份很大的測試套件有用。

小結

今天把 44 天的成果收成一份可交付的 v1.0.0。我們寫了六階段的路徑回顧資料、一支只輸出事實的盤點腳本、一支自動產生結案報告的腳本、一支發布前守門檢查、一份涵蓋全部檢查的 verify 指令、一份與本機一致的 CI workflow,以及一份九項的能力盤點。整個專案維持 Day 31–43 的共用設定,沒有新增任何執行期依賴。

回顧整條路徑,最值得留下的不是任何一個技術名詞,而是幾個反覆出現的原則:把主觀判斷換成可驗證的門檻(Day 42)、把規範從口耳相傳變成檢查項(Day 43)、把最便宜的失敗放在流程最前面(今天)、以及誠實寫下限制而不是掩蓋它(今天的已知限制)。這幾條原則跟框架版本無關,明年換了新的工具依然適用。

至於這個專案接下來最該補的三個地方,我們也一併寫進報告的自評段落:第一是「真實資料的邊界處理」——目前 mock 的資料量很小,分頁、排序、極長文字都還沒被驗證;第二是「同時編輯」——兩個管理者同時確認同一筆預約時的行為還沒定義;第三是「國際化」——所有文案都寫死在元件裡,還沒有抽成資源檔。這三項都不是缺陷,而是「v1.0.0 的範圍之外」,把它們寫下來,下一個版本才有起點。

結語

今天的重點是把「學完」變成「交付」。我們用了 44 天從 Node.js 與 TypeScript 走到一個能上線、能測試、能交接的預約系統前端;最後這一天則用腳本與檢查把成果固定下來,讓它不依賴任何人的記憶。明天,我們會做這個系列的最後一篇:延伸路線。那一天不寫新功能,而是把「下一步該往哪裡走」講清楚——包含深度方向(資料庫與 ORM、伺服器端渲染的進階議題、可觀測性)與廣度方向(測試策略、設計系統、DevOps),以及一份 90 天的學習計畫與幾個把預約系統延伸成新作品的具體提案。

延伸資源

  • Next.js 官方文件:https://nextjs.org/docs/app,App Router、資料取得與建置流程的完整說明。
  • React 官方文件:https://react.dev/,元件、狀態與鉤子的標準寫法。
  • Vitest 官方文件:https://vitest.dev/,單元測試與覆蓋率設定。
  • Playwright 官方文件:https://playwright.dev/,端對端測試、裝置模擬與 CI 整合。
  • Keep a Changelog:https://keepachangelog.com/zh-TW/1.1.0/,版本變更紀錄的撰寫慣例。
  • Day 40 測試與驗收:原文連結,本系列測試金字塔與 CI 的建立過程。

留言

這個網誌中的熱門文章

Day 2 變數與資料型別

Day 2 變數與資料型別 引言 寫程式的過程中,變數與資料型別是處理資料的基礎。變數是存放資料的容器,資料型別則決定這筆資料有哪些特性、可以進行哪些操作。學會定義變數、認識各種資料型別,是學好 Python 的關鍵一步。 這篇文章會帶你了解 Python 中變數的觀念、如何定義變數,以及常見的資料型別,包括整數、浮點數、字串、布林值,還有串列、元組、字典與集合等容器型別。我們也會介紹變數的命名規則與撰寫風格建議,以及如何用 type() 檢查資料型別。 什麼是變數?如何在 Python 中定義變數 變數是在程式執行時用來存放資料的名稱。透過定義變數,我們可以給一筆資料一個名字,並在程式的其他地方用這個名字取用該筆資料。在 Python 中,變數不需要事先宣告型別,因為 Python 是動態型別語言,變數的型別由指定給它的值決定。 定義變數的基本語法 在 Python 中定義變數非常簡單,只要用賦值符號 = 把值指定給變數即可。例如: x = 5 # 定義變數 x,並把整數 5 賦值給它 name = "Alice" # 定義變數 name,並把字串 "Alice" 賦值給它 在這裡,x 是一個變數,被賦予整數 5;name 是另一個變數,被賦予字串 "Alice"。 變數的更新與覆寫 變數的值可以修改,也就是說,我們可以在程式的不同地方給同一個變數新的值。例如: x = 10 # x 最初被賦予 10 x = 15 # x 的值現在被更新為 15 這樣就能依照需求,在程式執行過程中靈活調整變數的值。 Python 的動態型別系統 Python 和某些靜態型別語言不同,定義變數時不需要宣告型別。賦值時,Python 會根據值自動判斷變數的型別。例如: x = 5 # x 是整數 x = 3.14 # x 變成浮點數 x = "Hi" # x 變成字串 同一個變數在程式執行過程中可以存放不同型別的值,這是 Python 的彈性之一。 常見資料型別 在 Python 中,資料型別決定我們可以對變數進行哪些操作...

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門 隨著人工智慧(AI)與深度學習(Deep Learning)快速發展,越來越多人對這些技術產生興趣。不論你是想踏入 AI 領域的初學者,還是已經有程式基礎的開發者,學好 Python 與深度學習框架(例如 PyTorch),都能為你打開更多可能。 為什麼選擇 Python? Python 已經是資料科學與人工智慧領域的首選語言。它的語法簡潔、容易上手,而且擁有龐大的生態系與大量開源函式庫。無論是資料處理、資料視覺化,還是建立機器學習與深度學習模型,Python 都能勝任。對想進入 AI 或資料科學領域的人來說,它幾乎是必備工具。 PyTorch 是什麼? PyTorch 是由 Meta(原 Facebook)AI 研究團隊開發的開源深度學習框架,以易用、靈活和動態計算圖著稱,是許多 AI 研究人員與開發者的首選。相較於其他框架,PyTorch 的寫法更貼近原生 Python,對初學者相對友善。無論是簡單的實驗,還是複雜的深度學習模型,PyTorch 都能提供強大的支援。 這個系列能帶給你什麼? 這個系列會從 Python 的基礎開始,帶你一步一步學習,最後能自己用 PyTorch 建立深度學習模型。即使你完全沒有寫過程式,也能跟著文章的節奏累積技能,理解 AI 與深度學習的核心觀念。 本系列涵蓋的主題 Python 基礎:從變數、條件判斷到函式與模組。 資料處理工具:用 NumPy 與 Pandas 有效率地操作資料。 資料視覺化:用 Matplotlib 與 Seaborn 把資料畫成圖表。 深度學習的數學基礎:線性代數、微積分與機率。 PyTorch 入門:理解張量、模型建構與 GPU 加速。 基礎深度學習模型:CNN 與 RNN 的實作應用。 深度學習專案實戰:從資料前處理到模型部署的端到端流程。 誰適合這個系列? 程式初學者 :如果你對 AI 充滿好奇,卻還沒寫過程式,系列的第一部分會帶你快速上手 Python,並幫助你理解深度學習的基本觀念。 資料科學愛好者 :如果你已經熟悉一些資料處理方法,進階部分會教你如何用 PyTorch 建構深度學習模型。 開發者與研究人員 :想更深入了...

Day 1 Python 簡介與環境設定

Day 1 Python 簡介與環境設定 引言 在現在的科技環境裡,程式設計已經是一項重要技能。無論你是對資料科學有興趣、想成為開發者,或是想踏入人工智慧(AI)領域,學會寫程式都能明顯提升你的競爭力。在眾多程式語言中,Python 因為語法簡單、功能強大、應用範圍廣泛,成為許多人進入程式世界的第一選擇。這篇文章會帶你認識 Python 的背景與優勢,並一步步教你在不同系統上安裝與設定 Python 開發環境,最後寫出第一支 Python 程式。 為什麼選擇 Python? Python 是一種高階程式語言,由 Guido van Rossum 在 1991 年發布。Python 的設計哲學強調程式碼的可讀性,並用縮排來定義程式區塊,這點和許多使用大括號的語言不同。簡潔的語法讓它成為初學者的理想選擇;就算是經驗豐富的開發者,也能用它完成複雜的專案。 Python 的優勢如下: 簡單易學 :Python 的語法清楚、結構簡潔,初學者很快就能上手。和其他語言相比,學習曲線相對平緩,不需要先弄懂一堆複雜觀念,就能開始寫程式。 應用範圍廣泛 :從資料科學、網頁開發、人工智慧、機器學習、自動化測試到網路爬蟲,Python 都有大量開源函式庫與工具支援,而且在這些領域都扮演關鍵角色。 豐富的函式庫與框架 :Python 的函式庫生態系非常龐大。做資料分析有 NumPy、Pandas;開發網站有 Django、Flask;做深度學習有 TensorFlow、PyTorch。各種需求幾乎都能找到對應的套件,讓開發更有效率。 跨平台支援 :Python 支援 Windows、macOS、Linux 等作業系統,程式通常不需要太多修改就能跨平台執行,讓開發與部署更有彈性。 活躍的社群 :Python 擁有龐大的開發者社群。學習或開發上遇到問題,幾乎都能在社群與論壇(例如 Stack Overflow)找到答案,對初學者來說是很強的後盾,也能減少卡關時的挫折感。 Python 的應用領域 Python 的流行與強大功能,讓許多領域都開始大量使用它。以下是幾個常見的應用方向: 資料科學 :隨著大數據與人工智慧興起,資料科學大量使用 Python。NumPy、Pandas 與 Matplotlib 等工具能處理和分析龐...