บทนำ
จะดีแค่ไหน ถ้าเราเริ่มโปรเจคใหม่ได้โดยไม่ต้องเสียเวลาไปกับการตั้งค่า (Config) เดิมๆ ที่น่าเบื่อ?
บทความนี้จะเปลี่ยนความเบื่อหน่ายนั้น ให้กลายเป็นการสร้าง ‘Generator’ Script สุดเท่ด้วย Bun เพื่อให้คุณสร้างโปรเจคใหม่ทั้งหมดได้ภายในคำสั่งเดียว!
เพื่อให้เข้าใจเนื้อหาได้ง่ายขึ้น ผู้อ่านควรมีพื้นฐานในเรื่องต่อไปนี้:
- ความเข้าใจพื้นฐานเกี่ยวกับ Command-Line
- ความรู้เบื้องต้นเกี่ยวกับ TypeScript
- มี
Bunติดตั้งในเครื่อง - ใช้
gitและมีบัญชีของ Github
ถ้าเตรียมตัวพร้อมแล้ว ก็มาเริ่มสร้าง CLI ของเรากันเลย!
ภาพรวมของโปรเจค
ในบทความนี้ เราจะมาสร้างเครื่องมือ Command-Line (CLI) ของเราเอง โดยหน้าที่หลักของมันคือการดึง (fetch) โครงสร้างโปรเจคเริ่มต้น (template) ที่เราได้เตรียมไว้จาก Public Repository บน GitHub ของเราเอง
ซึ่งเราจะทำให้ CLI สามารถเลือก “รูปแบบ” ของโปรเจคที่ต้องการได้ โดยใช้ประโยชน์จาก Branch บน Git เพื่อแยกโปรเจคแต่ละเวอร์ชันออกจากกัน เช่น เลือกระหว่างโปรเจคเวอร์ชันพื้นฐาน (จาก branch main) หรือเวอร์ชันที่มีการตั้งค่าเพิ่มเติม (จาก branch อื่นๆ)
เมื่อทำเสร็จแล้ว เราจะสามารถรันคำสั่งได้ในรูปแบบนี้:
mycli <command> <args>
ขั้นตอนการตั้งค่าโปรเจกต์
1. สร้างโปรเจกต์
เริ่มต้นด้วยการสร้างโปรเจกต์ใหม่ด้วยคำสั่งของ Bun ผ่าน Terminal
bun init -y
2. ติดตั้ง Dependencies
จากนั้น ติดตั้ง Package ที่จำเป็นสำหรับใช้สร้างแอปพลิเคชัน Command Line (CLI)
bun add commander consola degit inquirer kleur ora
หน้าที่ของแต่ละ Package:
commander: เครื่องมือหลักที่ช่วยให้เราสร้างแอปพลิเคชัน CLI ได้ง่ายขึ้นconsola: ใช้สำหรับตกแต่งข้อความที่แสดงผลใน Terminal ให้อ่านง่ายและสวยงามdegit: เครื่องมือสำหรับดึงโค้ดจาก Git Repository (เช่น GitHub)inquirer: ช่วยสร้างหน้าต่างโต้ตอบกับผู้ใช้ (Interactive Prompt) เช่น การตั้งคำถามให้ผู้ใช้เลือกตอบkleur: ใช้สำหรับเพิ่มสีสันให้กับตัวอักษรใน Terminalora: แสดงสัญลักษณ์ Loading (Spinner) ขณะที่โปรแกรมกำลังรอประมวลผล
3. เตรียมโครงสร้างไฟล์ (File Structure)
เพื่อให้ง่ายต่อการพัฒนา ในเบื้องต้นเราจะจัดโครงสร้างไฟล์ของโปรเจกต์ตามรูปแบบดังนี้ครับ
my-cli-app/
├── src/
│ └── index.ts
├── node_modules/
├── package.json
└── bun.lockb
การสร้างคำสั่ง CLI พื้นฐาน
1. เขียนโค้ดเริ่มต้น
เปิดไฟล์ src/index.ts และเพิ่มโค้ดต่อไปนี้เพื่อสร้างคำสั่งพื้นฐานที่สุดของ CLI
import { program } from "commander";
import consola from "consola";
program
.version("1.0.0")
.name("my-cli")
.description("CLI สำหรับสร้างโปรเจกต์เริ่มต้น")
.action(() => {
consola.info("ยินดีต้อนรับสู่ My-CLI!");
});
program.parse(process.argv);
คำอธิบายโค้ด:
program: คือ Object หลักจากcommanderที่ใช้กำหนดค่าต่างๆ ของ CLI เช่น ชื่อ (.name), คำอธิบาย (.description), และเวอร์ชัน (.version).action(): ฟังก์ชันที่กำหนดว่า CLI จะต้องทำอะไรเมื่อถูกเรียกใช้งาน.parse(process.argv): คำสั่งที่ใช้ประมวลผล Input ที่ผู้ใช้ป้อนผ่าน Command Line โดยprocess.argvจะเก็บค่าทั้งหมดที่ส่งเข้ามาconsola.info(): เป็นการเรียกใช้consolaเพื่อแสดงข้อความพร้อมไอคอนℹสีฟ้า ทำให้ผลลัพธ์ดูสวยงามและเป็นระเบียบ
2. ทดลองรันคำสั่ง
บันทึกไฟล์และทดลองรันสคริปต์ผ่าน Terminal ด้วยคำสั่ง:
bun run src/index.ts
ผลลัพธ์ที่คาดหวัง:
การสร้างคำสั่งย่อยและ Input แบบมีตัวเลือก
ในส่วนนี้เราจะสร้างคำสั่งย่อย (Subcommand) สำหรับจัดการโปรเจกต์ Django และเพิ่มความสามารถในการรับ Input จากผู้ใช้
ส่วนที่ 1: สร้างคำสั่งย่อย django
1. สร้างไฟล์คำสั่งย่อย
เริ่มต้นด้วยการสร้างไฟล์สำหรับคำสั่งย่อยชื่อ django.command.ts ภายในโฟลเดอร์ src/commands/ และใส่โค้ดต่อไปนี้
// src/commands/django.command.ts
import { Command } from "commander";
import consola from "consola";
export const DjangoCommand = new Command("django")
.alias("gdj")
.description("Commands for generating Django projects")
.action(async () => {
consola.info("Django command is called!");
});
new Command("django"): ใช้สำหรับสร้างคำสั่งย่อยชื่อdjango.alias("gdj"): กำหนดชื่อเรียกสั้นๆ (alias) ของคำสั่ง
2. เพิ่มคำสั่งย่อยเข้าคำสั่งหลัก
กลับไปที่ไฟล์ src/index.ts เพื่อนำเข้า DjangoCommand ให้เป็นส่วนหนึ่งของโปรแกรมหลัก
// src/index.ts
import { program } from "commander";
import consola from "consola";
import { DjangoCommand } from "./commands/django.command"; // เพิ่มบรรทัดนี้
program
.version("1.0.0")
.name("my-cli")
.description("CLI สำหรับสร้างโปรเจกต์เริ่มต้น")
.action(() => {
consola.info("ยินดีต้อนรับสู่ My-CLI!");
});
program.addCommand(DjangoCommand); // เพิ่มบรรทัดนี้
program.parse(process.argv);
program.addCommand(): เป็นเมธอดสำหรับเพิ่มคำสั่งย่อยเข้าไปในโปรแกรมหลัก
3. ตรวจสอบผลลัพธ์
ทดลองรันคำสั่งโดยเรียกดูหน้าช่วยเหลือ (-h) เพื่อดูว่ามีคำสั่งอะไรให้ใช้บ้าง
bun run src/index.ts -h
จะเห็นว่ามีคำสั่ง django พร้อมชื่อย่อ gdj ปรากฏขึ้นมาในรายการ Commands
ส่วนที่ 2: เพิ่มตัวเลือก (Prompt) และสถานะ Loading
1. แก้ไขไฟล์คำสั่งย่อย
กลับไปที่ไฟล์ src/commands/django.command.ts เพื่อเพิ่มโค้ดสำหรับรับ Input จากผู้ใช้ด้วย inquirer และแสดงสถานะ Loading ด้วย ora
// src/commands/django.command.ts
import { Command } from "commander";
import consola from "consola";
import inquirer from "inquirer"; // เพิ่มบรรทัดนี้
import ora from "ora"; // เพิ่มบรรทัดนี้
const PROJECT_TYPE_CHOICES = [
{ name: "DRF Project With PostgreSQL", value: "original" },
{ name: "DRF Mock Project", value: "mock" },
];
export const DjangoCommand = new Command("django")
.alias("gdj")
.description("Commands for generating Django projects")
.action(async () => {
// inquirer prompt
const answers = await inquirer.prompt([
{
type: "list",
name: "projectType",
message: "Select a project type:",
choices: PROJECT_TYPE_CHOICES,
},
{
type: "input",
name: "projectName",
message: "Enter the project name:",
default: "my-django-project",
},
]);
// ora spinner
const spinner = ora("Cloning project template...").start();
await new Promise((resolve) => setTimeout(resolve, 2000)); // จำลองการทำงาน 2 วินาที
spinner.succeed("Project cloned successfully!");
});
inquirer.prompt([...]): สร้างชุดคำถามเพื่อรับ Input จากผู้ใช้แบบโต้ตอบora("...").start(): เริ่มแสดงผลสถานะ Loading (spinner)spinner.succeed(): หยุดการ Loading และแสดงข้อความว่าทำสำเร็จ (หรือใช้spinner.stop()เพื่อหยุดเฉยๆ)
2. ทดลองรันคำสั่ง
ทดลองรันคำสั่งย่อย django (หรือใช้ชื่อย่อ gdj)
bun run src/index.ts gdj
ผลลัพธ์ที่ได้คือ โปรแกรมจะแสดงรายการให้เลือกประเภทโปรเจกต์, ถามชื่อโปรเจกต์, และแสดงสถานะ Loading ก่อนจะจบการทำงานครับ
To Be Continue…
สำหรับ EP นี้ก็ขอตัดจบไว้เพียงเท่านี้ก่อนนะครับ เดี๋ยวบทความจะยาวเกินไป ใน EP หน้าเราจะมาทำในส่วนการ Generate Project กันต่อครับและจะปิดท้ายด้วยการ ใส่สีให้ตัวอักษรให้สวยงามกันนะครับ อย่าลืมมาติดตามกันต่อด้วยนะคร้าบ