線上課程觀課進度管理小工具開發日誌
Day 6:JavaScript 程式碼執行排序:遞迴函數、Call Stack、Task Queue
Call Stack;遞迴函數與 call stack 的關係;Task Queue(非同步的概念再釐清)
Day 9:「修煉圈圈 Practice Rings」Web app 開發日誌 - 2025 六角 AI Vibe Coding 體驗營期末大魔王作業
這份筆記旨在記錄 2025 六角 Vibe Coding 體驗營每日作業 Day 21 的期末專案成果,從一個簡單的個人痛點出發,透過與 AI(在我這個情境中是 Perplexity)協作,在一天內完成了一個包含前後端的全端網頁小工具:「修煉圈圈 Practice Rings」。
<100 subscribers
線上課程觀課進度管理小工具開發日誌
Day 6:JavaScript 程式碼執行排序:遞迴函數、Call Stack、Task Queue
Call Stack;遞迴函數與 call stack 的關係;Task Queue(非同步的概念再釐清)
Day 9:「修煉圈圈 Practice Rings」Web app 開發日誌 - 2025 六角 AI Vibe Coding 體驗營期末大魔王作業
這份筆記旨在記錄 2025 六角 Vibe Coding 體驗營每日作業 Day 21 的期末專案成果,從一個簡單的個人痛點出發,透過與 AI(在我這個情境中是 Perplexity)協作,在一天內完成了一個包含前後端的全端網頁小工具:「修煉圈圈 Practice Rings」。
練習題目模組化重構時,思考 修煉圈圈 這個先前 Vibe Coding 做的小專案可以重構的方式,才發現 js 和 css 內建語法模組概念的不同,記錄一下思考過程。
模組化 是將大的程式碼拆分成小的、獨立的、可重複使用的單元(模組),每個模組:
職責單一
易於維護
易於測試
可以獨立開發
未模組化程式碼(1000+ 行)
↓
❌ 難以理解
❌ 難以維護
❌ 容易出錯
❌ 難以分工協作
模組化程式碼(多個 100-200 行檔案)
↓
✅ 清晰易懂
✅ 易於維護
✅ 測試簡單
✅ 便於團隊協作
開發階段(Developer Experience)
├─ 程式碼清晰易懂
├─ 容易定位問題
├─ 方便重複使用
└─ 便於團隊協作
↓ 建置/合併工具 ↓
生產環境(Browser Performance)
├─ 減少 HTTP 請求
├─ 檔案大小最小化
├─ 瀏覽器快速解析
└─ 性能最優化
JavaScript 有 原生的模組系統,開發者可以直接使用 import 和 export。
// 方式 1:具名導出
export function add(a, b) {
return a + b;
}
export const PI = 3.14159;
export class Calculator {
multiply(a, b) {
return a * b;
}
}
// 方式 2:預設導出
export default function subtract(a, b) {
return a - b;
}
// 方式 3:混合導出
export function divide(a, b) {
return a / b;
}
export default { add, subtract, divide };
// 導入具名導出
import { add, PI } from './math.js';
// 導入預設導出
import subtract from './math.js';
// 導入所有內容
import * as math from './math.js';
// 混合導入
import subtract, { add, PI } from './math.js';
// 使用
console.log(add(2, 3)); // 5
console.log(PI); // 3.14159
console.log(subtract(5, 2)); // 3
src/
├─ logic/ # 純業務邏輯模組
│ ├─ calculator.js # 進度計算邏輯
│ ├─ formatter.js # 日期和時間格式化
│ ├─ messages.js # 勵志訊息生成
│ ├─ timer.js # 計時器邏輯
│ └─ date-navigation.js # 日期導航邏輯(純函數)
│
├─ state/ # 狀態管理模組
│ └─ store.js # 集中式狀態儲存
│
├─ services/ # API 服務模組
│ └─ api.js # 後端通訊
│
├─ views/ # UI 層模組
│ ├─ dom.js # DOM 元素快取
│ ├─ render.js # 協調層(統一渲染入口)
│ └─ components/ # UI 元件模組
│ ├─ day-card-view.js # 日卡片渲染
│ ├─ month-card-view.js # 月檢視渲染
│ ├─ rings-view.js # 進度圈渲染
│ ├─ timer-view.js # 計時器 UI
│ ├─ history-view.js # 歷史記錄 UI
│ └─ encourage-view.js # 勵志訊息 UI
│
└─ constants/ # 常數模組
└─ config.js # 應用配置
main.js (應用入口)
├─ import * as render from "./src/views/render.js"
├─ import * as timer from "./src/logic/timer.js"
├─ import { getState } from "./src/state/store.js"
└─ import * as dateNav from "./src/logic/date-navigation.js"
render.js (協調層)
├─ import * as dayCardView from "./components/day-card-view.js"
├─ import * as monthCardView from "./components/month-card-view.js"
├─ import * as ringsView from "./components/rings-view.js"
├─ import * as timerView from "./components/timer-view.js"
├─ import * as historyView from "./components/history-view.js"
├─ import * as encourageView from "./components/encourage-view.js"
└─ import { getState } from "../state/store.js"
各元件模組
└─ import 所需的邏輯模組 和 狀態管理
語言原生支援 - 無需額外工具
清晰的依賴關係 - 一眼看出模組間的關係
程式碼複用 - 同一函數可多次導入使用
易於測試 - 可獨立測試各個模組
優雅的語法 - 簡潔易讀
CSS 沒有原生的模組系統,無法直接使用 @import 模組語法(它只能導入 CSS 檔案)。
歷史原因 - CSS 創建於 1994 年,當時無模組化概念
設計理念 - CSS 是聲明式語言,不適合傳統模組系統
演進緩慢 - CSS 標準更新速度遠低於 JavaScript
/* style.css */
/* ================================================ */
/* 1. BASE STYLES - 基礎樣式和變數定義 */
/* ================================================ */
:root {
--dora-blue: #009eff;
--dora-red: #e92024;
--dora-white: #ffffff;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Huninn', sans-serif;
background-color: var(--dora-bg);
}
/* ================================================ */
/* 2. TIMER SECTION - 計時器相關樣式 */
/* ================================================ */
.timer-section {
/* ... */
}
.timer-display {
/* ... */
}
/* ================================================ */
/* 3. RINGS SECTION - 進度圈相關樣式 */
/* ================================================ */
.rings-section {
/* ... */
}
.ring-circle {
/* ... */
}
/* ... 以此類推 */
優點:
簡單直接
無需額外工具
瀏覽器快速解析(單一檔案)
缺點:
檔案越來越大難以維護
無法自動優化
/* style.css - 主入口檔案 */
@import url('styles/base.css');
@import url('styles/timer.css');
@import url('styles/rings.css');
@import url('styles/history.css');
@import url('styles/modal.css');
@import url('styles/responsive.css');
styles/
├─ base.css # 變數、Reset、基礎
├─ timer.css # 計時器相關
├─ rings.css # 進度圈相關
├─ history.css # 歷史記錄相關
├─ modal.css # Modal 相關
└─ responsive.css # 手機版回應式
優點:
模組化程式碼
易於維護
無需建置工具
缺點:
多個 HTTP 請求(性能)
需要手動管理依賴
// main.scss
@import 'variables.scss';
@import 'base.scss';
@import 'timer.scss';
@import 'rings.scss';
@import 'history.scss';
@import 'responsive.scss';
功能:
變數、嵌套、混入
自動編譯為 CSS
支援導入其他 SCSS 檔案
// variables.scss
$primary-color: #009eff;
$border-radius: 15px;
// timer.scss
.timer-section {
color: $primary-color;
border-radius: $border-radius;
}
優點:
高級 CSS 特性
程式碼複用
編譯為最小化 CSS
缺點:
需要編譯工具
額外的學習成本
// Button.js
import styles from './Button.module.css';
export function Button() {
return <button className={styles.primary}>點擊</button>;
}
/* Button.module.css */
.primary {
background-color: #009eff;
color: white;
padding: 10px 20px;
}
編譯後會生成唯一的 class 名稱,避免衝突。
優點:
避免樣式衝突
組件級別的樣式作用域
與 JavaScript 框架整合
缺點:
需要建置工具
學習框架(React 等)
目前:style.css (1003 行)
├─ 1. BASE STYLES
├─ 2. TIMER SECTION
├─ 3. RINGS SECTION
├─ 4. HISTORY SECTION
├─ 5. MODAL / DAY CARD
├─ 6. MONTH VIEW
└─ 7. RESPONSIVE
問題:
❌ 檔案過大,難以維護
❌ 無法自動優化
✅ 但對於當前規模足夠
面向 | JavaScript | CSS |
|---|---|---|
原生支援 | ES6 Modules | 無原生系統 |
導入語法 |
| 無模組語法 |
開發方式 | 模組化(import/export) | 手動組織 |
語言特性 | 函數、類、對象 | 聲明式 |
依賴管理 | 自動追蹤 | 手動管理 |
程式碼複用 | 容易 | ⚠️ 需要工具 |
/* ===== JavaScript ===== */
// 具名導出和導入
export function add(a, b) {}
import { add } from './math.js';
// 預設導出和導入
export default subtract;
import subtract from './math.js';
// 萬用導入
import * as math from './math.js';
math.add(2, 3);
/* ===== CSS ===== */
/* 只能導入 CSS 檔案,無模組概念 */
@import url('base.css');
@import url('timer.css');
/* 結果:所有樣式會疊加到全局作用域 */
/* 無法像 JS 一樣「接收特定導出」 */
建置工具 是自動化開發流程的軟體,它在開發環境和生產環境之間起橋樑作用:
開發環境 (模組化程式碼)
↓
建置工具 (Webpack/Vite)
↓ 合併 + 壓縮 + 最小化
↓
生產環境 (最優化單一檔案)
// webpack.config.js
module.exports = {
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: __dirname + '/dist',
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
};
特點:
功能全面
生態龐大
配置複雜
學習曲線陡峭
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
build: {
outDir: 'dist',
}
})
特點:
配置簡單
開發速度快
現代化設計
預設最優化
# 無需配置檔案!
parcel build index.html
特點:
零配置
自動偵測
速度快
輸入(開發環境)
├─ src/main.js
├─ src/logic/timer.js
├─ src/views/render.js
├─ src/styles/base.css
├─ src/styles/timer.css
└─ src/styles/rings.css
↓ 建置工具處理 ↓
1. 解析 import/export
2. 遞迴收集所有依賴
3. 合併所有 JS 檔案
4. 合併所有 CSS 檔案
5. 壓縮 + 最小化
6. 生成 Source Map(偵錯用)
7. 添加指紋(cache busting)
輸出(生產環境)
├─ dist/bundle.abc123.js (合併+壓縮)
├─ dist/style.def456.css (合併+壓縮)
└─ dist/index.html (指向新檔案)
除了完整的建置工具,還有專門的 CSS 合併工具:
自動添加瀏覽器前綴
壓縮 CSS
處理兼容性
編譯 SCSS 為 CSS
自動合併 @import
線上或命令行工具
壓縮和合併 CSS
<!-- index.html -->
<link rel="stylesheet" href="style.css">
<script src="main.js"></script>
<!-- 瀏覽器處理 -->
網路請求:
GET /style.css (1003 行)
GET /main.js
GET /src/state/store.js
GET /src/logic/timer.js
GET /src/views/render.js
... (多個 HTTP 請求)
優點:易於開發調試
缺點:性能較差
<!-- 與開發環境完全相同 -->
<link rel="stylesheet" href="style.css">
<script src="main.js"></script>
<!-- 問題:無法自動優化 -->
- CSS 未壓縮
- JS 未合併
- 文件大小較大
- 多個 HTTP 請求
npm run dev
開發伺服器啟動
├─ 熱模組更新 (HMR)
├─ 即時編譯
├─ Source Map(原始碼對應)
└─ 快速刷新
開發者寫程式碼時:
file: src/logic/timer.js (修改)
↓ 自動編譯 ↓
瀏覽器自動刷新
↓
即時看到改動 (無需手動刷新)
npm run build
建置流程:
1. 解析依賴
2. 合併模組
3. 程式碼最小化
4. CSS 壓縮
5. 生成指紋版本
輸出結果:
dist/
├─ bundle.a1b2c3d4.js (合併+壓縮,50 KB)
├─ style.e5f6g7h8.css (合併+壓縮,15 KB)
├─ index.html
└─ assets/
HTML 自動指向新檔案名:
<link rel="stylesheet" href="style.e5f6g7h8.css">
<script src="bundle.a1b2c3d4.js"></script>
優點:
✅ 最小化 HTTP 請求(2 個)
✅ 最小化檔案大小
✅ 瀏覽器快速解析
✅ 指紋版本便於快取更新
無建置工具:
CSS: 1003 行 → 無壓縮 → ~30 KB
JS: 分散在多個檔案 → ~200 KB
HTTP 請求: 10+ 個
解析時間: 較長
有建置工具:
CSS: 1003 行 → 壓縮 → ~15 KB (-50%)
JS: 合併+壓縮 → ~50 KB (-75%)
HTTP 請求: 2-3 個 (-80%)
解析時間: 較短
結論:性能提升 3-5 倍!
JavaScript 模組化成熟度:★★★★★ - 使用 ES6 import/export - 清晰的目錄結構 - 邏輯分離完善 ⚠️ CSS 模組化成熟度:★★☆☆☆ - 單一檔案(1003 行) - 有清晰註解分組 - 尚未拆分成多個檔案 ⚠️ 建置工具成熟度:★☆☆☆☆ - 無建置工具 - 無自動優化 - 開發體驗簡單但性能有限
現在就可以做的:
改進 CSS 註解分組
使用更清晰的分隔符
添加 CSS 變數(已有)
整理選擇器順序
/* style.css */
/* ================================================= */
/* 1. BASE STYLES */
/* ================================================= */
/* 功能:CSS 變數、Reset、基礎樣式 */
:root { }
* { }
body { }
/* ================================================= */
/* 2. TIMER SECTION */
/* ================================================= */
/* 功能:計時器顯示、按鈕、模式標籤 */
.timer-section { }
.timer-display { }
/* ... */
如果 CSS 繼續增長:
src/styles/
├─ index.css (主入口,只做 @import)
├─ _variables.css
├─ _base.css
├─ _timer.css
├─ _rings.css
├─ _history.css
├─ _modal.css
└─ _responsive.css
/* index.css */
@import url('_variables.css');
@import url('_base.css');
@import url('_timer.css');
@import url('_rings.css');
@import url('_history.css');
@import url('_modal.css');
@import url('_responsive.css');
<!-- index.html -->
<link rel="stylesheet" href="src/styles/index.css">
當專案變複雜時考慮:
# 初始化 Vite
npm create vite@latest . -- --template vanilla
# 或 Webpack
npm install webpack webpack-cli --save-dev
優點:
自動合併 JS + CSS
自動壓縮最小化
開發時熱更新
性能優化
CSS 超過多少行?
│
├─ < 800 行 → 保持現狀 + 改進註解
│
├─ 800-1500 行 → 考慮 @import 拆分
│
└─ > 1500 行 → 引入建置工具或 Sass
JavaScript 複雜度如何?
│
├─ 低複雜度 → 無需建置工具
│
├─ 中複雜度 → 可考慮 Vite(簡單配置)
│
└─ 高複雜度 → 引入框架 + 建置工具
JavaScript: ✅ ES6 Modules (無工具)
CSS: ✅ 單一檔案 + 清晰註解
工具: ❌ 無
維護成本: 低
性能: 可接受
JavaScript: ✅ ES6 Modules
CSS: ✅ SCSS 或多檔案 @import
工具: ✅ Vite
維護成本: 中等
性能: 優秀
JavaScript: ✅ ES6 Modules + 框架 (React/Vue)
CSS: ✅ CSS Modules 或 CSS-in-JS
工具: ✅ Webpack / Vite + 框架配置
維護成本: 中等
性能: 最優
import/export 語法 ✅ 瀏覽器原生支援(現代瀏覽器) ✅ 清晰的依賴追蹤 ✅ 易於維護和測試
無 import/export 語法 ❌ 所有樣式應用到全局作用域 ✅ 但有多種替代方案(註解、@import、Sass、CSS Modules) ❌ 需要外部工具進行最佳化
開發環境:保持模組化(易於理解)
↓
建置工具:自動合併 + 壓縮 + 最小化
↓
生產環境:單一最優化檔案(性能最佳)
現在: 專注核心功能開發
未來: 當程式碼複雜度增加時考慮工具
遠期: 引入框架和完整工具鏈
練習題目模組化重構時,思考 修煉圈圈 這個先前 Vibe Coding 做的小專案可以重構的方式,才發現 js 和 css 內建語法模組概念的不同,記錄一下思考過程。
模組化 是將大的程式碼拆分成小的、獨立的、可重複使用的單元(模組),每個模組:
職責單一
易於維護
易於測試
可以獨立開發
未模組化程式碼(1000+ 行)
↓
❌ 難以理解
❌ 難以維護
❌ 容易出錯
❌ 難以分工協作
模組化程式碼(多個 100-200 行檔案)
↓
✅ 清晰易懂
✅ 易於維護
✅ 測試簡單
✅ 便於團隊協作
開發階段(Developer Experience)
├─ 程式碼清晰易懂
├─ 容易定位問題
├─ 方便重複使用
└─ 便於團隊協作
↓ 建置/合併工具 ↓
生產環境(Browser Performance)
├─ 減少 HTTP 請求
├─ 檔案大小最小化
├─ 瀏覽器快速解析
└─ 性能最優化
JavaScript 有 原生的模組系統,開發者可以直接使用 import 和 export。
// 方式 1:具名導出
export function add(a, b) {
return a + b;
}
export const PI = 3.14159;
export class Calculator {
multiply(a, b) {
return a * b;
}
}
// 方式 2:預設導出
export default function subtract(a, b) {
return a - b;
}
// 方式 3:混合導出
export function divide(a, b) {
return a / b;
}
export default { add, subtract, divide };
// 導入具名導出
import { add, PI } from './math.js';
// 導入預設導出
import subtract from './math.js';
// 導入所有內容
import * as math from './math.js';
// 混合導入
import subtract, { add, PI } from './math.js';
// 使用
console.log(add(2, 3)); // 5
console.log(PI); // 3.14159
console.log(subtract(5, 2)); // 3
src/
├─ logic/ # 純業務邏輯模組
│ ├─ calculator.js # 進度計算邏輯
│ ├─ formatter.js # 日期和時間格式化
│ ├─ messages.js # 勵志訊息生成
│ ├─ timer.js # 計時器邏輯
│ └─ date-navigation.js # 日期導航邏輯(純函數)
│
├─ state/ # 狀態管理模組
│ └─ store.js # 集中式狀態儲存
│
├─ services/ # API 服務模組
│ └─ api.js # 後端通訊
│
├─ views/ # UI 層模組
│ ├─ dom.js # DOM 元素快取
│ ├─ render.js # 協調層(統一渲染入口)
│ └─ components/ # UI 元件模組
│ ├─ day-card-view.js # 日卡片渲染
│ ├─ month-card-view.js # 月檢視渲染
│ ├─ rings-view.js # 進度圈渲染
│ ├─ timer-view.js # 計時器 UI
│ ├─ history-view.js # 歷史記錄 UI
│ └─ encourage-view.js # 勵志訊息 UI
│
└─ constants/ # 常數模組
└─ config.js # 應用配置
main.js (應用入口)
├─ import * as render from "./src/views/render.js"
├─ import * as timer from "./src/logic/timer.js"
├─ import { getState } from "./src/state/store.js"
└─ import * as dateNav from "./src/logic/date-navigation.js"
render.js (協調層)
├─ import * as dayCardView from "./components/day-card-view.js"
├─ import * as monthCardView from "./components/month-card-view.js"
├─ import * as ringsView from "./components/rings-view.js"
├─ import * as timerView from "./components/timer-view.js"
├─ import * as historyView from "./components/history-view.js"
├─ import * as encourageView from "./components/encourage-view.js"
└─ import { getState } from "../state/store.js"
各元件模組
└─ import 所需的邏輯模組 和 狀態管理
語言原生支援 - 無需額外工具
清晰的依賴關係 - 一眼看出模組間的關係
程式碼複用 - 同一函數可多次導入使用
易於測試 - 可獨立測試各個模組
優雅的語法 - 簡潔易讀
CSS 沒有原生的模組系統,無法直接使用 @import 模組語法(它只能導入 CSS 檔案)。
歷史原因 - CSS 創建於 1994 年,當時無模組化概念
設計理念 - CSS 是聲明式語言,不適合傳統模組系統
演進緩慢 - CSS 標準更新速度遠低於 JavaScript
/* style.css */
/* ================================================ */
/* 1. BASE STYLES - 基礎樣式和變數定義 */
/* ================================================ */
:root {
--dora-blue: #009eff;
--dora-red: #e92024;
--dora-white: #ffffff;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Huninn', sans-serif;
background-color: var(--dora-bg);
}
/* ================================================ */
/* 2. TIMER SECTION - 計時器相關樣式 */
/* ================================================ */
.timer-section {
/* ... */
}
.timer-display {
/* ... */
}
/* ================================================ */
/* 3. RINGS SECTION - 進度圈相關樣式 */
/* ================================================ */
.rings-section {
/* ... */
}
.ring-circle {
/* ... */
}
/* ... 以此類推 */
優點:
簡單直接
無需額外工具
瀏覽器快速解析(單一檔案)
缺點:
檔案越來越大難以維護
無法自動優化
/* style.css - 主入口檔案 */
@import url('styles/base.css');
@import url('styles/timer.css');
@import url('styles/rings.css');
@import url('styles/history.css');
@import url('styles/modal.css');
@import url('styles/responsive.css');
styles/
├─ base.css # 變數、Reset、基礎
├─ timer.css # 計時器相關
├─ rings.css # 進度圈相關
├─ history.css # 歷史記錄相關
├─ modal.css # Modal 相關
└─ responsive.css # 手機版回應式
優點:
模組化程式碼
易於維護
無需建置工具
缺點:
多個 HTTP 請求(性能)
需要手動管理依賴
// main.scss
@import 'variables.scss';
@import 'base.scss';
@import 'timer.scss';
@import 'rings.scss';
@import 'history.scss';
@import 'responsive.scss';
功能:
變數、嵌套、混入
自動編譯為 CSS
支援導入其他 SCSS 檔案
// variables.scss
$primary-color: #009eff;
$border-radius: 15px;
// timer.scss
.timer-section {
color: $primary-color;
border-radius: $border-radius;
}
優點:
高級 CSS 特性
程式碼複用
編譯為最小化 CSS
缺點:
需要編譯工具
額外的學習成本
// Button.js
import styles from './Button.module.css';
export function Button() {
return <button className={styles.primary}>點擊</button>;
}
/* Button.module.css */
.primary {
background-color: #009eff;
color: white;
padding: 10px 20px;
}
編譯後會生成唯一的 class 名稱,避免衝突。
優點:
避免樣式衝突
組件級別的樣式作用域
與 JavaScript 框架整合
缺點:
需要建置工具
學習框架(React 等)
目前:style.css (1003 行)
├─ 1. BASE STYLES
├─ 2. TIMER SECTION
├─ 3. RINGS SECTION
├─ 4. HISTORY SECTION
├─ 5. MODAL / DAY CARD
├─ 6. MONTH VIEW
└─ 7. RESPONSIVE
問題:
❌ 檔案過大,難以維護
❌ 無法自動優化
✅ 但對於當前規模足夠
面向 | JavaScript | CSS |
|---|---|---|
原生支援 | ES6 Modules | 無原生系統 |
導入語法 |
| 無模組語法 |
開發方式 | 模組化(import/export) | 手動組織 |
語言特性 | 函數、類、對象 | 聲明式 |
依賴管理 | 自動追蹤 | 手動管理 |
程式碼複用 | 容易 | ⚠️ 需要工具 |
/* ===== JavaScript ===== */
// 具名導出和導入
export function add(a, b) {}
import { add } from './math.js';
// 預設導出和導入
export default subtract;
import subtract from './math.js';
// 萬用導入
import * as math from './math.js';
math.add(2, 3);
/* ===== CSS ===== */
/* 只能導入 CSS 檔案,無模組概念 */
@import url('base.css');
@import url('timer.css');
/* 結果:所有樣式會疊加到全局作用域 */
/* 無法像 JS 一樣「接收特定導出」 */
建置工具 是自動化開發流程的軟體,它在開發環境和生產環境之間起橋樑作用:
開發環境 (模組化程式碼)
↓
建置工具 (Webpack/Vite)
↓ 合併 + 壓縮 + 最小化
↓
生產環境 (最優化單一檔案)
// webpack.config.js
module.exports = {
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: __dirname + '/dist',
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
};
特點:
功能全面
生態龐大
配置複雜
學習曲線陡峭
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
build: {
outDir: 'dist',
}
})
特點:
配置簡單
開發速度快
現代化設計
預設最優化
# 無需配置檔案!
parcel build index.html
特點:
零配置
自動偵測
速度快
輸入(開發環境)
├─ src/main.js
├─ src/logic/timer.js
├─ src/views/render.js
├─ src/styles/base.css
├─ src/styles/timer.css
└─ src/styles/rings.css
↓ 建置工具處理 ↓
1. 解析 import/export
2. 遞迴收集所有依賴
3. 合併所有 JS 檔案
4. 合併所有 CSS 檔案
5. 壓縮 + 最小化
6. 生成 Source Map(偵錯用)
7. 添加指紋(cache busting)
輸出(生產環境)
├─ dist/bundle.abc123.js (合併+壓縮)
├─ dist/style.def456.css (合併+壓縮)
└─ dist/index.html (指向新檔案)
除了完整的建置工具,還有專門的 CSS 合併工具:
自動添加瀏覽器前綴
壓縮 CSS
處理兼容性
編譯 SCSS 為 CSS
自動合併 @import
線上或命令行工具
壓縮和合併 CSS
<!-- index.html -->
<link rel="stylesheet" href="style.css">
<script src="main.js"></script>
<!-- 瀏覽器處理 -->
網路請求:
GET /style.css (1003 行)
GET /main.js
GET /src/state/store.js
GET /src/logic/timer.js
GET /src/views/render.js
... (多個 HTTP 請求)
優點:易於開發調試
缺點:性能較差
<!-- 與開發環境完全相同 -->
<link rel="stylesheet" href="style.css">
<script src="main.js"></script>
<!-- 問題:無法自動優化 -->
- CSS 未壓縮
- JS 未合併
- 文件大小較大
- 多個 HTTP 請求
npm run dev
開發伺服器啟動
├─ 熱模組更新 (HMR)
├─ 即時編譯
├─ Source Map(原始碼對應)
└─ 快速刷新
開發者寫程式碼時:
file: src/logic/timer.js (修改)
↓ 自動編譯 ↓
瀏覽器自動刷新
↓
即時看到改動 (無需手動刷新)
npm run build
建置流程:
1. 解析依賴
2. 合併模組
3. 程式碼最小化
4. CSS 壓縮
5. 生成指紋版本
輸出結果:
dist/
├─ bundle.a1b2c3d4.js (合併+壓縮,50 KB)
├─ style.e5f6g7h8.css (合併+壓縮,15 KB)
├─ index.html
└─ assets/
HTML 自動指向新檔案名:
<link rel="stylesheet" href="style.e5f6g7h8.css">
<script src="bundle.a1b2c3d4.js"></script>
優點:
✅ 最小化 HTTP 請求(2 個)
✅ 最小化檔案大小
✅ 瀏覽器快速解析
✅ 指紋版本便於快取更新
無建置工具:
CSS: 1003 行 → 無壓縮 → ~30 KB
JS: 分散在多個檔案 → ~200 KB
HTTP 請求: 10+ 個
解析時間: 較長
有建置工具:
CSS: 1003 行 → 壓縮 → ~15 KB (-50%)
JS: 合併+壓縮 → ~50 KB (-75%)
HTTP 請求: 2-3 個 (-80%)
解析時間: 較短
結論:性能提升 3-5 倍!
JavaScript 模組化成熟度:★★★★★ - 使用 ES6 import/export - 清晰的目錄結構 - 邏輯分離完善 ⚠️ CSS 模組化成熟度:★★☆☆☆ - 單一檔案(1003 行) - 有清晰註解分組 - 尚未拆分成多個檔案 ⚠️ 建置工具成熟度:★☆☆☆☆ - 無建置工具 - 無自動優化 - 開發體驗簡單但性能有限
現在就可以做的:
改進 CSS 註解分組
使用更清晰的分隔符
添加 CSS 變數(已有)
整理選擇器順序
/* style.css */
/* ================================================= */
/* 1. BASE STYLES */
/* ================================================= */
/* 功能:CSS 變數、Reset、基礎樣式 */
:root { }
* { }
body { }
/* ================================================= */
/* 2. TIMER SECTION */
/* ================================================= */
/* 功能:計時器顯示、按鈕、模式標籤 */
.timer-section { }
.timer-display { }
/* ... */
如果 CSS 繼續增長:
src/styles/
├─ index.css (主入口,只做 @import)
├─ _variables.css
├─ _base.css
├─ _timer.css
├─ _rings.css
├─ _history.css
├─ _modal.css
└─ _responsive.css
/* index.css */
@import url('_variables.css');
@import url('_base.css');
@import url('_timer.css');
@import url('_rings.css');
@import url('_history.css');
@import url('_modal.css');
@import url('_responsive.css');
<!-- index.html -->
<link rel="stylesheet" href="src/styles/index.css">
當專案變複雜時考慮:
# 初始化 Vite
npm create vite@latest . -- --template vanilla
# 或 Webpack
npm install webpack webpack-cli --save-dev
優點:
自動合併 JS + CSS
自動壓縮最小化
開發時熱更新
性能優化
CSS 超過多少行?
│
├─ < 800 行 → 保持現狀 + 改進註解
│
├─ 800-1500 行 → 考慮 @import 拆分
│
└─ > 1500 行 → 引入建置工具或 Sass
JavaScript 複雜度如何?
│
├─ 低複雜度 → 無需建置工具
│
├─ 中複雜度 → 可考慮 Vite(簡單配置)
│
└─ 高複雜度 → 引入框架 + 建置工具
JavaScript: ✅ ES6 Modules (無工具)
CSS: ✅ 單一檔案 + 清晰註解
工具: ❌ 無
維護成本: 低
性能: 可接受
JavaScript: ✅ ES6 Modules
CSS: ✅ SCSS 或多檔案 @import
工具: ✅ Vite
維護成本: 中等
性能: 優秀
JavaScript: ✅ ES6 Modules + 框架 (React/Vue)
CSS: ✅ CSS Modules 或 CSS-in-JS
工具: ✅ Webpack / Vite + 框架配置
維護成本: 中等
性能: 最優
import/export 語法 ✅ 瀏覽器原生支援(現代瀏覽器) ✅ 清晰的依賴追蹤 ✅ 易於維護和測試
無 import/export 語法 ❌ 所有樣式應用到全局作用域 ✅ 但有多種替代方案(註解、@import、Sass、CSS Modules) ❌ 需要外部工具進行最佳化
開發環境:保持模組化(易於理解)
↓
建置工具:自動合併 + 壓縮 + 最小化
↓
生產環境:單一最優化檔案(性能最佳)
現在: 專注核心功能開發
未來: 當程式碼複雜度增加時考慮工具
遠期: 引入框架和完整工具鏈
Share Dialog
Share Dialog
No comments yet