ข้ามไปยังเนื้อหา

Workspace & Feature Flag

เมื่อ TypeScript monorepo เติบโตเกิน package เดียว คุณจะใช้ npm (หรือ pnpm/yarn) workspaces Cargo มีเทียบเท่าแบบ first-class: workspace คือ Cargo.toml เดียวที่ root ซึ่งระบุ member crate ทั้งหมด member ทั้งหมดใช้ Cargo.lock เดียวและ target/ build directory เดียวร่วมกัน

TypeScript
# package.json (root)
{
"name": "my-monorepo",
"workspaces": [
"packages/api",
"packages/core",
"packages/cli"
]
}
# packages/core/package.json
{
"name": "@my/core",
"version": "1.0.0"
}
Rust
# Cargo.toml (rootworkspace manifest)
[workspace]
members = [
"crates/api",
"crates/core",
"crates/cli",
]
resolver = "2" # ใช้ resolver version 2 เสมอ
# crates/core/Cargo.toml
[package]
name = "core"
version = "0.1.0"
edition = "2021"
Terminal window
# TypeScript (npm workspaces)
npm run test --workspaces
npm run build --workspace packages/api
# Cargo
cargo build --workspace # build ทุก member
cargo test --workspace # test ทุก member
cargo build -p api # build เฉพาะ crate "api"
cargo test -p core # test เฉพาะ crate "core"
# Cargo.toml (root workspace manifest)
[workspace.dependencies]
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
# crates/api/Cargo.toml — inherit โดยไม่ต้องระบุ version ซ้ำ
[dependencies]
tokio = { workspace = true }
serde = { workspace = true }

วิธีนี้กัน version drift ข้าม workspace member ที่เป็นปัญหาที่พบบ่อยใน Node monorepo ที่ package ต่างตัวดึง patch version ไม่ตรงกันโดยไม่รู้ตัว

Feature flag คือคำตอบของ Rust สำหรับ optional peer dependency และการเรียก require() แบบมีเงื่อนไข ช่วยให้ผู้ใช้เลือกใช้ฟังก์ชันเพิ่มเติมโดยไม่ต้องจ่าย compile cost เมื่อไม่ต้องการ

Cargo.toml
[features]
default = ["json"] # feature ที่เปิดโดย default
json = ["dep:serde_json"] # feature "json" ดึง serde_json เข้ามา
async = ["dep:tokio"] # feature "async" ดึง tokio เข้ามา
full = ["json", "async"] # ความสะดวก: เปิดทุกอย่าง
[dependencies]
serde_json = { version = "1", optional = true }
tokio = { version = "1", optional = true }
src/lib.rs
#[cfg(feature = "json")]
pub mod json_support {
pub fn parse(s: &str) -> serde_json::Value {
serde_json::from_str(s).unwrap()
}
}
Terminal window
# Build โดยไม่มี default feature
cargo build --no-default-features
# เปิด feature เฉพาะ
cargo build --features "async,json"
# เปิดทุก feature
cargo build --all-features

Workspace และ feature flag ต้องการ project layout หลาย file จึงไม่มี browser Playground สำหรับบทนี้ สร้าง workspace ใน local ด้วย cargo new --lib และทดลองกับตัวอย่างข้างต้น

ใน Cargo workspace ไฟล์ Cargo.lock ที่ share เดียวอยู่ที่ไหน?
จะ build เฉพาะ crate หนึ่งใน workspace ได้อย่างไร?
Cargo feature flag มีจุดประสงค์อะไร?