--- title: 後端環境相關 tags: [環境相關] --- # 後端環境相關 > 主要採用 JavaScript,並補充 TypeScript 專案的建構方式 ## 後端建立環境指令與順序 1. 🧰 專案初始化與安裝流程 2. ⚙️ 開發用指令(scripts) 3. 📌 需手動建立的檔案建議(.env、結構) 📁 推測的檔案內容依據: - 框架:Express - 驗證系統:Passport(local + jwt) - 資料庫:MongoDB(Mongoose) - 加密:bcrypt - 環境變數:dotenv - 開發工具:nodemon + eslint + prettier ## 🧾 整體安裝清單懶人表(依順序) | 類別 | 套件 | 安裝指令 | | ------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | 建立環境 | `express dotenv` | `npm install express dotenv` | | 建立環境(開發用) | `nodemon eslint ...` | `npm install -D nodemon eslint @eslint/js eslint-config-prettier eslint-plugin-prettier globals` | | 常駐工具 | `cors http-status-codes validator` | `npm install cors http-status-codes validator` | | 功能型功能 | `bcrypt jsonwebtoken mongoose passport passport-local passport-jwt` | `npm install bcrypt jsonwebtoken mongoose passport passport-local passport-jwt` | --- # 🧰 專案初始化與安裝流程 ## 💿 進入專案資料夾裡面放後端的區域 ``` cd back ``` --- ## 1️⃣ 建立環境(系統框架與開發基礎) > 📌 目的:讓 Express 專案可以跑起來、有伺服器、有環境變數、能熱重啟、能檢查語法 ### 📍 初始化 Node 專案 ``` npm init --yes npm i -D nodemon ``` #### 📝 改動 packge.json 設定為 module 語法 ``` "type": "module", ``` 設定開發用指令(scripts) ``` "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "nodemon index.js", "start": "node index.js" }, ``` ### 📍 安裝框架與環境變數工具 ``` npm i express dotenv ``` ### 📌 需手動建立的檔案建議(.env、.gitignore) #### 📝 建立檔案.env > 內容為:環境變數等不能說的秘密 檔名 ``` .env ``` #### 📝 建立檔案.gitignore > 內容為:要設定讓 git 忽略的檔案 檔名 ``` .gitignore ``` 內容(最少) ``` .env node_modules dump/* !dump/.gitkeep ``` #### 📁 建立資料夾 models > 內容:定義資料庫的資料結構(Schema)、驗證規則與資料模型 ``` models ``` **用途說明**: - 定義資料表/集合的欄位結構與資料型態 - 設定欄位驗證規則(必填、長度、格式等) - 定義資料模型的方法(如密碼加密、資料查詢等) **常見檔案範例**: - `user.js`:使用者資料模型 - `product.js`:商品資料模型 - `order.js`:訂單資料模型 **Mongoose 範例**: ```js import { Schema, model } from "mongoose"; const userSchema = new Schema({ account: { type: String, required: true, unique: true }, email: { type: String, required: true }, password: { type: String, required: true }, }); export default model("users", userSchema); ``` #### 📁 建立資料夾 controllers > 內容:處理業務邏輯,對資料庫執行增刪改查(CRUD)操作 ``` controllers ``` **用途說明**: - 接收路由傳來的請求資料 - 呼叫 models 進行資料庫操作 - 處理資料處理邏輯與錯誤處理 - 回傳處理結果給前端 **常見檔案範例**: - `userController.js`:處理使用者相關操作(註冊、登入、更新資料等) - `productController.js`:處理商品相關操作(新增、查詢、修改、刪除) - `orderController.js`:處理訂單相關操作 **Controller 範例**: ```js import User from "../models/user.js"; import { StatusCodes } from "http-status-codes"; export const register = async (req, res) => { try { await User.create(req.body); res.status(StatusCodes.OK).json({ success: true, message: "註冊成功" }); } catch (error) { res .status(StatusCodes.INTERNAL_SERVER_ERROR) .json({ success: false, message: "註冊失敗" }); } }; ``` #### 📁 建立資料夾 middlewares > 內容:處理請求前後的中介邏輯,如身分驗證、資料驗證、錯誤處理等 ``` middlewares ``` **用途說明**: - **身分驗證**:檢查使用者是否登入、token 是否有效 - **權限控制**:檢查使用者是否有權限執行某操作 - **資料驗證**:驗證請求資料格式是否正確 - **錯誤處理**:統一處理錯誤回應格式 **常見檔案範例**: - `auth.js`:身分驗證中介軟體(如 JWT 驗證) - `validator.js`:資料驗證中介軟體 - `errorHandler.js`:錯誤處理中介軟體 - `upload.js`:檔案上傳處理中介軟體 **Middleware 範例**: ```js import passport from "passport"; import { StatusCodes } from "http-status-codes"; // JWT 驗證中介軟體 export const auth = (req, res, next) => { passport.authenticate("jwt", { session: false }, (error, user, info) => { if (error || !user) { return res .status(StatusCodes.UNAUTHORIZED) .json({ success: false, message: "未登入" }); } req.user = user; next(); })(req, res, next); }; ``` #### 📁 建立資料夾 routers > 內容:定義 API 路由規則,將請求分配給對應的 controller ``` routers ``` **用途說明**: - 定義 API 端點路徑(如 `/api/users`, `/api/products`) - 指定 HTTP 方法(GET, POST, PUT, DELETE) - 串接 middlewares 與 controllers - 組織與管理 API 結構 **常見檔案範例**: - `userRouter.js`:使用者相關路由(註冊、登入、個人資料) - `productRouter.js`:商品相關路由 - `orderRouter.js`:訂單相關路由 **Router 範例**: ```js import { Router } from "express"; import { register, login, getProfile } from "../controllers/userController.js"; import { auth } from "../middlewares/auth.js"; const router = Router(); router.post("/register", register); router.post("/login", login); router.get("/profile", auth, getProfile); // 需要驗證身分 export default router; ``` **在 index.js 中使用**: ```js import userRouter from "./routers/userRouter.js"; app.use("/api/users", userRouter); ``` #### 📝 建立檔案 index.js 檔名 ``` index.js ``` > 內容: ```js import "dotenv/config"; import express from "express"; import mongoose from "mongoose"; import { StatusCodes } from "http-status-codes"; import cors from "cors"; // routes(根據不同專案有不同的東西) // import 路由名稱 from '路由檔案' // passport.js import "./passport.js"; // 連線資料庫 1.設環境變數 2.成功 3.失敗 mongoose .connect(process.env.DB_URL) .then(() => { console.log("☑️ 資料庫連接成功"); mongoose.set("sanitizeFilter", true); }) .catch((err) => { console.log("⛔ 資料庫連線失敗"); console.error("資料庫連線失敗", err); }); // 建立 express 伺服器 const app = express(); app.use(express.json()); // 使用 CORS 中介軟體(處理跨域請求) app.use(cors()); // ↓錯誤處理 app.use((err, req, res, _next) => { res.status(StatusCodes.BAD_REQUEST).json({ sucess: false, message: "Json格式錯誤", }); }); // 設置路由(根據不同專案有不同的東西) // app.use('/路由檔案', 路由名稱) // 處理未定義的路由 app.all(/.*/, (req, res) => { res.status(StatusCodes.NOT_FOUND).json({ success: false, message: "找不到該路由", }); }); // 監聽與啟動 app.listen(4000, () => { console.log("伺服器啟動"); }); ``` ### 📍 安裝開發用工具(語法檢查、自動重啟) > 檢查語法是否符合規則(eslint / oslint / tslint…) > 檔案變動時自動重啟伺服器(開發用) ``` npm init @eslint/config@latest ``` ``` npm i -D nodemon prettier eslint-plugin-prettier eslint-config-prettier ``` #### 📝 eslint.config.js 內容 檔名 ``` eslint.config.js ``` 檔案內容 ``` import js from '@eslint/js' import globals from 'globals' import { defineConfig } from 'eslint/config' import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended' export default defineConfig([ { files: ['**/*.{js,mjs,cjs}'], plugins: { js }, extends: ['js/recommended'], }, { files: ['**/*.{js,mjs,cjs}'], languageOptions: { globals: globals.node } }, eslintPluginPrettierRecommended, { rules: { 'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], }, }, ]) ``` #### 📝 .prettierrc.json 內容 檔名 ``` .prettierrc.json ``` 檔案內容 ``` { "$schema": "https://json.schemastore.org/prettierrc", "printWidth": 100, "semi": false, "singleQuote": true } ``` > 補充:index.js 是進入點 --- ## 2️⃣ 常駐工具型功能(必裝輔助開發用,不是主流程但超常出現) > 📌 目的:提升錯誤處理與 API 品質,跨域通訊、欄位驗證也能幫忙 ``` npm i cors http-status-codes validator ``` 1. cors:讓前端能 call API(跨網域) 2. http-status-codes:不要手寫 404、200 之類的數字 3. validator:欄位驗證(ex: email、長度) --- ## 3️⃣ 明確功能型功能(安裝你需要用的功能套件,依需求增減) > 📌 目的:實作帳號登入、密碼加密、token 機制、資料庫操作,依需求增減 資料庫:MongoDB ``` npm i mongoose ``` mongoose:操作 MongoDB 各種驗證 ``` npm i bcrypt jsonwebtoken mongoose passport passport-local passport-jwt ``` 1. bcrypt:密碼加密與比對 2. jsonwebtoken:產出 JWT token 3. passport:登入驗證框架 4. passport-local:帳號密碼策略 5. passport-jwt:JWT 身分驗證策略 ## 4️⃣ (選用)使用 TypeScript > 📌 目的:提升開發體驗、型別安全、減少執行時錯誤 ### 📍 安裝 TypeScript 相關套件 ```bash npm install -D typescript @types/node @types/express ts-node npm install -D @types/cors @types/bcrypt @types/jsonwebtoken @types/validator npm install -D @types/passport @types/passport-local @types/passport-jwt ``` **套件說明**: | 套件 | 用途 | | ----------------------- | -------------------------------- | | `typescript` | TypeScript 編譯器 | | `@types/node` | Node.js 型別定義 | | `@types/express` | Express 型別定義 | | `ts-node` | 直接執行 TypeScript 檔案(開發用) | | `@types/cors` | CORS 套件型別定義 | | `@types/bcrypt` | bcrypt 套件型別定義 | | `@types/jsonwebtoken` | JWT 套件型別定義 | | `@types/validator` | validator 套件型別定義 | | `@types/passport` | Passport 主套件型別定義 | | `@types/passport-local` | Passport Local 策略型別定義 | | `@types/passport-jwt` | Passport JWT 策略型別定義 | ### 📝 建立 tsconfig.json 檔名: ``` tsconfig.json ``` 內容: ```json { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "node", "outDir": "./dist", "rootDir": "./", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "allowSyntheticDefaultImports": true, "types": ["node"] }, "include": ["**/*.ts"], "exclude": ["node_modules", "dist"] } ``` **設定說明**: - `target`: 編譯後的 JavaScript 版本 - `module`: 模組系統(使用 ESNext 支援 ES Modules) - `outDir`: 編譯後的檔案輸出資料夾 - `strict`: 啟用所有嚴格型別檢查 - `esModuleInterop`: 改善 CommonJS 與 ES Module 互通性 ### 📝 調整 package.json 將 scripts 區塊修改為: ```json { "type": "module", "scripts": { "dev": "nodemon --exec ts-node index.ts", "build": "tsc", "start": "node dist/index.js", "type-check": "tsc --noEmit" } } ``` **指令說明**: - `npm run dev`: 開發模式,使用 ts-node 直接執行 TypeScript - `npm run build`: 編譯 TypeScript 為 JavaScript - `npm start`: 執行編譯後的 JavaScript(正式環境) - `npm run type-check`: 只檢查型別,不編譯 ### 📝 調整 ESLint 設定 安裝 TypeScript ESLint 套件: ```bash npm install -D typescript-eslint ``` 修改 `eslint.config.js`: ```js import js from "@eslint/js"; import globals from "globals"; import tseslint from "typescript-eslint"; import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended"; import { defineConfig } from "eslint/config"; export default defineConfig( js.configs.recommended, tseslint.configs.recommended, { files: ["**/*.{js,mjs,cjs,ts}"], languageOptions: { globals: globals.node, }, }, { files: ["**/*.ts"], rules: { "no-unused-vars": "off", "@typescript-eslint/no-unused-vars": [ "warn", { argsIgnorePattern: "^_" }, ], }, }, eslintPluginPrettierRecommended ); ``` ### 📁 檔案結構調整 將原本的 `.js` 檔案改為 `.ts`: ``` 專案根目錄/ ├── index.ts (原 index.js) ├── passport.ts (原 passport.js) ├── models/ │ └── user.ts (原 user.js) ├── controllers/ │ └── userController.ts ├── middlewares/ │ └── auth.ts ├── routers/ │ └── userRouter.ts └── dist/ (編譯後的輸出資料夾) ``` ### 📝 TypeScript 範例:User Model ```ts import { Schema, model, Document } from "mongoose"; // 定義介面 export interface IUser extends Document { account: string; email: string; password: string; } // 定義 Schema const userSchema = new Schema<IUser>({ account: { type: String, required: true, unique: true }, email: { type: String, required: true }, password: { type: String, required: true }, }); // 匯出模型 export default model<IUser>("users", userSchema); ``` ### 📝 TypeScript 範例:Controller ```ts import { Request, Response } from "express"; import User from "../models/user.js"; import { StatusCodes } from "http-status-codes"; export const register = async (req: Request, res: Response): Promise<void> => { try { await User.create(req.body); res.status(StatusCodes.OK).json({ success: true, message: "註冊成功" }); } catch (error) { res .status(StatusCodes.INTERNAL_SERVER_ERROR) .json({ success: false, message: "註冊失敗" }); } }; ``` ### 📝 TypeScript 範例:index.ts ```ts import "dotenv/config"; import express, { Request, Response, NextFunction } from "express"; import mongoose from "mongoose"; import { StatusCodes } from "http-status-codes"; import cors from "cors"; // routes // import userRouter from './routers/userRouter.js' // passport.js import "./passport.js"; // 連線資料庫 mongoose .connect(process.env.DB_URL as string) .then(() => { console.log("☑️ 資料庫連接成功"); mongoose.set("sanitizeFilter", true); }) .catch((err) => { console.log("⛔ 資料庫連線失敗"); console.error("資料庫連線失敗", err); }); // 建立 express 伺服器 const app = express(); app.use(express.json()); // 使用 CORS app.use(cors()); // 錯誤處理 app.use((err: Error, req: Request, res: Response, _next: NextFunction) => { res.status(StatusCodes.BAD_REQUEST).json({ success: false, message: "Json格式錯誤", }); }); // 設置路由 // app.use('/api/users', userRouter) // 處理未定義的路由 app.all(/.*/, (req: Request, res: Response) => { res.status(StatusCodes.NOT_FOUND).json({ success: false, message: "找不到該路由", }); }); // 監聽與啟動 const PORT = process.env.PORT || 4000; app.listen(PORT, () => { console.log(`伺服器啟動於 port ${PORT}`); }); ``` ### ⚠️ 注意事項 1. **import 路徑需加 .js 副檔名**(即使是 TypeScript 檔案) ```ts import User from "../models/user.js"; // ✅ 正確 import User from "../models/user"; // ❌ 可能出錯 ``` 2. **型別定義不完整時的處理** ```ts // 如果某個套件沒有 @types,可以建立 types/custom.d.ts declare module "some-package"; ``` 3. **環境變數型別安全** ```ts // 可以建立 types/env.d.ts declare global { namespace NodeJS { interface ProcessEnv { DB_URL: string; JWT_SECRET: string; PORT?: string; } } } export {}; ``` ### 🎯 TypeScript vs JavaScript 決策 | 情境 | 建議 | | -------------------------- | ------------- | | 小型專案、快速開發 | JavaScript | | 多人協作、大型專案 | TypeScript ✅ | | 需要高度型別安全 | TypeScript ✅ | | 學習成本考量 | JavaScript | | 與前端 TypeScript 專案整合 | TypeScript ✅ | --- # 🧩 後端套件分類表(含 `dependencies` 與 `devDependencies`) | 套件名稱 | 安裝位置 | 類型 | 用途說明 | 代表常見用途 | | ---------------------------- | -------- | -------- | ------------------- | ---------------------------- | | `express` | ✅ 後端 | Web 框架 | 架設 API Server | 處理請求與回應 | | `dotenv` | ✅ 後端 | 設定工具 | 管理 `.env` 變數 | API 金鑰 | | `nodemon` | ✅ 後端 | 開發工具 | 變更自動重啟 server | 提升開發效率 | | `cors` | ✅ 後端 | 中介軟體 | 解決跨域問題 | 前後端分離 | | `body-parser` | ✅ 後端 | 請求解析 | 拿到 req.body | POST/PUT 資料 | | `jsonwebtoken` | ✅ 後端 | 驗證 | 處理 JWT 驗證 | 登入憑證 | | `bcryptjs` / `bcrypt` | ✅ 後端 | 加密 | 密碼加密比對 | 登入系統 | | `mongoose` / `mysql2` / `pg` | ✅ 後端 | DB 驅動 | 資料庫連線操作 | MongoDB / MySQL / PostgreSQL | | `multer` | ✅ 後端 | 檔案處理 | 處理檔案上傳 | 上傳圖片 | ## 📁 一、建立環境款(系統框架與開發支援) | 套件名 | 用途說明 | 適合場景 | | --------------------------------------------------- | ------------------------------------------------------ | ----------------------------------- | | `express` | 建立 HTTP 伺服器與路由管理,是整個後端的基礎 | 所有 Express 專案必備 | | `dotenv` | 讀取 `.env` 檔案設定環境變數 | 區分開發、正式環境設定(如 DB URI) | | `nodemon` | 檔案變動時自動重啟伺服器(開發用) | 提高開發效率,不需手動重啟 | | `eslint` / `@eslint/js` | 程式碼風格檢查器(靜態分析) | 寫 code 時維持一致風格 | | `eslint-config-prettier` / `eslint-plugin-prettier` | 整合 Prettier 與 ESLint,避免衝突 | 同時使用兩者時很常用 | | `globals` | 提供 ESLint 可辨識的全域變數(如 `window`, `process`) | 靜態檢查時避免誤報錯誤 | --- ## 🛠️ 二、常駐工具型功能款(幾乎每個專案會加的功能輔助) | 套件名 | 用途說明 | 適合場景 | | ------------------- | ------------------------------------------ | ---------------------- | | `cors` | 處理跨來源請求,允許前端與後端不同來源通訊 | 前後端分離開發中必裝 | | `http-status-codes` | 提供標準 HTTP 狀態碼常數,避免寫死數字 | 統一錯誤回應格式 | | `validator` | 驗證 email、網址、字串格式等(輕量、常用) | 表單驗證、後端欄位檢查 | --- ## 🎯 三、明確功能型功能款(為了特定需求裝的) | 套件名 | 用途說明 | 適合場景 | | ---------------- | ----------------------------------- | ----------------------------- | | `bcrypt` | 加密密碼、驗證密碼 | 帳號登入系統、保護使用者資料 | | `jsonwebtoken` | 產生與驗證 JWT(token 機制) | 登入後產出 token、驗證使用者 | | `mongoose` | 操作 MongoDB 的 ODM(資料模型管理) | 資料庫存取、欄位定義與驗證 | | `passport` | 使用者驗證中介系統 | 處理登入、登出、身分驗證 | | `passport-local` | `passport` 的本地帳密登入策略 | 基本帳號密碼登入 | | `passport-jwt` | `passport` 的 JWT 驗證策略 | 支援使用 JWT token 登入持久化 | --- # 👀 無用的知識增加了 ## 各種驗證套件差別 ### ✅ 一、**前端送表單前要檢查資料對不對** > ➤ 負責人:`validator` 🧪 格式錯誤例子: - Email 不合法 - 密碼太短 - 名稱為空 ```js validator.isEmail(email); // ✅ or ❌ ``` ### ✅ 二、**登入時要比對使用者密碼** > ➤ 負責人:`bcrypt` 🔐 一進資料庫前就加密,登入時也用它來比對: ```js bcrypt.compare(使用者輸入的密碼, 資料庫的加密密碼); ``` ### ✅ 三、**登入成功後,要頒發「通關憑證」** > ➤ 負責人:`jsonwebtoken` 🎫 就像辦完護照拿到簽證,使用者登入成功後,產生一張 **JWT token**。 ```js const token = jwt.sign(payload, secretKey, { expiresIn: "1h" }); ``` ### ✅ 四、**之後每次請求,要驗證使用者憑證是否合法** > ➤ 負責人:`passport` + `passport-jwt` 🕵️ 守門系統來了,這邊會攔截請求,看 token 是否正確(如:有沒有過期?有沒有被竄改?) ```js passport.use(new JwtStrategy(...)) ``` ### ✅ 五、**第一次登入的帳號密碼邏輯** > ➤ 負責人:`passport-local` 👮 檢查帳號密碼正確性(第一次登入用的驗證策略) ```js passport.use(new LocalStrategy(帳號密碼檢查邏輯)); ``` --- ### 📌 小整理圖: ``` 🔎 表單送出前 —— validator 🔐 密碼上路前 —— bcrypt(加密儲存) ✅ 登入成功時 —— jsonwebtoken(產出 token) 🧠 架構整合者 —— passport  └─ passport-local:帳密比對邏輯(登入那刻)  └─ passport-jwt:驗證 JWT token(後續請求) ``` --- ### 總整理 | 套件 | 分類 | 簡單比喻 | 驗證什麼? | | ---------------------- | -------------- | -------------------- | -------------------------- | | `validator` | 格式驗證 | 格式小警察 | email 格式、必填欄位、長度 | | `bcrypt` | 加密驗證 | 把密碼攪爛後存起來 | 使用者輸入密碼對不對 | | `jsonwebtoken` (`jwt`) | 身分憑證 | 成功登入後發的票 | JWT 有效嗎?是誰? | | `passport` | 驗證系統架構 | 驗證流程主控中心 | 調度各種驗證方式 | | `passport-local` | 登入策略 | 傳統帳號密碼比對方式 | 使用者帳號密碼是否正確 | | `passport-jwt` | token 驗證策略 | 持票者是否合法 | JWT 是否有效、是否過期 | ## validator 為什麼是常駐工具? ### 🧪 validator 屬於「常駐工具型功能」的理由 ✅ 1. 它不是為了某個功能而來,而是「幫你寫任何功能時更安全」 你寫會員系統會用 validator(驗證 email) 你寫商品系統也會用(名稱長度限制) 寫留言表單、報名表單、客服系統……都用得到 > 它的角色是「資料的守門員」,而不是「功能的實作者」 ### ✅ 2. 範圍極廣,不只登入/註冊才用 不像: passport = 為了登入驗證設計 bcrypt = 為了密碼比對設計 jwt = 為了登入產出 token 這三個是為了「身份驗證」這一個功能而存在,沒做登入就用不到。 但 validator 像是萬用刀: 是你送出任何資料給後端時,都要有人檢查格式 它不是功能,是習慣 ### ✅ 3. 你可能根本不做登入,也會用它 例如你只做一個「留言板」,完全匿名: 不需要 passport、bcrypt、jwt 但還是會用 validator → 限制留言內容字數、email 格式、避免空值 | 工具 | 是否功能導向? | 是否常駐? | 分類 | | ----------------------------- | ------------------------- | ----------------------- | ----------------- | | `passport` / `bcrypt` / `jwt` | ✅ 明確是為了登入、權限 | ❌ 沒做就不會用 | 🎯 明確功能型功能 | | `validator` | ❌ 不是某個功能的專屬工具 | ✅ 幾乎什麼功能都能用上 | 🛠 常駐工具型功能 | --- ## 📦 比較各種資料庫對應的套件選擇(給 Node.js 用) 不同資料庫有不同的 Node.js 連接方式與套件選擇。 ### 1️⃣ MongoDB - ✅ 套件:`mongoose`(ODM) - 功能:提供資料模型、驗證、自動轉換格式等功能 - 📦 替代選項:`mongodb`(原生驅動)→ 比較底層、自由度高但需自己寫邏輯 ``` npm i mongoose ``` ### 2️⃣ MySQL / MariaDB(關聯式資料庫) #### 👉 常見套件: | 套件 | 類型 | 說明 | | ----------- | ----------- | ------------------------------------------------ | | `mysql2` | 原生 client | 操作資料庫的最基本工具,查詢語法需自己寫 | | `sequelize` | ORM | 幫你抽象成「模型」,支援關聯、驗證、migration 等 | 🔧 安裝範例: ``` npm i mysql2 sequelize ``` 📘 建議搭配: - `dotenv`:放 DB 帳密 - `sequelize-cli`(選用):管理 migration、seed 資料 ### 3️⃣ PostgreSQL(關聯式,功能強大) #### 👉 常見套件: | 套件 | 類型 | 說明 | | ----------- | ----------- | ----------------------------------------------------- | | `pg` | 原生 client | 輕量、穩定、官方推薦 | | `sequelize` | ORM | 也支援 PostgreSQL(多資料庫通用) | | `prisma` | ORM | 現代化 ORM,更嚴謹、支援 type 安全(TypeScript 友善) | 🔧 安裝範例: ``` npm install pg sequelize ``` 或 ``` npm install prisma @prisma/client ``` ### 4️⃣ SQLite(輕量型,適合測試用) - 套件:`sqlite3` 或 `better-sqlite3` - ORM:同樣可以搭配 `sequelize` 或 `prisma` 🔧 安裝範例: ``` npm install sqlite3 sequelize ``` ### 5️⃣ 其他(非傳統資料庫) #### 🧰 Google Sheet × Node.js 的資料存取方式 🎯 **Google Sheet** 的使用邏輯比較不一樣:它不是傳統的資料庫,但可以當作**簡易資料儲存後台**。如果你想在 Node.js 中把 Google Sheet 當作資料來源或儲存工具,這邊有一套常見工具和方式可以用: ✅ 常見用途: - 表單送出資料 → 存到 Google Sheet - 後台設定資料 → 存在 Google Sheet 當成資料庫用 - 顯示表格資訊(例如後台管理員表、產品庫存表) #### 📦 套件選擇與安裝 ✅ 最主流方式:使用 Google 官方 API 套件 ``` npm i googleapis ``` 📁 會用到的東西: | 工具 | 用途說明 | | ------------ | --------------------------------------------------- | | `googleapis` | 官方 SDK,支援 Sheets API(也支援 Drive、Gmail 等) | | `dotenv` | 儲存你的憑證與 Google Sheet ID | #### 🗂️ Google Sheet 串接概念流程 1. **在 Google Cloud Platform 建立專案** 2. **啟用 Google Sheets API** 3. **建立服務帳號並下載 JSON 憑證** 4. **與你的 Sheet 分享編輯權給那個服務帳號的 email** 5. **在 Node.js 中使用 `googleapis` 將憑證讀進來、連接 Sheet** 6. **讀取 / 寫入資料** #### ✅ 套件與初始化步驟懶人表 | 類別 | 套件 | 安裝指令 | | ---------- | ------------ | ------------------------ | | 建立環境 | `dotenv` | `npm install dotenv` | | 功能型功能 | `googleapis` | `npm install googleapis` | 📦 如果你不想處理複雜的授權流程,也可以用 Google 提供的「App Script + Webhook」或用第三方平台如 [SheetDB](https://sheetdb.io/)、[Sheet.best](https://sheet.best/) 這類工具,但彈性較低。 #### 🎯 使用情境與限制提醒 | 優點 | 限制 | | ------------------------------ | ------------------------------------ | | 免費、上手快、適合簡單資料儲存 | 不適合大量資料操作(有限 API 限速) | | 資料可視化、多人共編方便 | 欄位與資料架構不夠嚴謹(不像資料庫) | | 不用架設 DB 就能快速測試 | 權限管理複雜、容易洩漏憑證 | #### 🚀 決策建議 | 想要這樣用… | 推薦方案 | | ------------------------------ | ----------------------------------------- | | 當成後台可視資料庫(小型系統) | ✅ Google Sheet + `googleapis` | | 當成表單資料收集庫 | ✅ Google Form + AppScript / `googleapis` | | 如果日後有複雜關聯查詢 | ❌ 建議改用 MongoDB / MySQL 等真資料庫 | ### 🎯 資料庫懶人決策建議 | 資料庫 | 套件選擇 | 建議用途 | | --------------- | --------------------------------- | ------------------------------------ | | MongoDB | `mongoose` | 文件型資料,彈性高,NoSQL 專案首選 | | MySQL / MariaDB | `mysql2` + `sequelize` | 有資料表設計(欄位明確、關聯明確) | | PostgreSQL | `pg` + `prisma`(或 `sequelize`) | 關聯型但要更強功能,支援 JSON 欄位等 | | SQLite | `sqlite3` + `sequelize` | 測試開發、本機 demo 用 |