Husky ที่ไม่ใช่หมา

Kongkom Sumlee
Lotus’s IT
Published in
6 min readNov 24, 2023
Photo by Daily Paws

Husky ในที่นี้ไม่ใช่หมา! แต่ Husky เป็นเครื่องมือช่วยในการพัฒนาโค้ดในเรื่องของการจัดการและควบคุม Git Hooks ในโปรเจคของเรา ในบทความนี้ เราจะกล่าวถึงว่าทำไมเราถึงควรใช้ Husky และ กล่าวถึงวิธีการติดตั้ง รวมไปถึงประโยชน์ที่เราจะได้รับจากการใช้ Husky กับ Visual Studio Code (VSCode)

Git hooks with husky Photo by Aamir Saleem

ทำไมเราควรใช้ Husky

Husky เป็นเครื่องมือที่มีประโยชน์ในการจัดการ Git hooks ซึ่งเป็นส่วนหนึ่งของระบบควบคุมเวอร์ชัน Git โดยทำให้เราสามารถการตรวจสอบก่อนหรือหลังจากที่เกิด procressใน Git ได้ เราเลือกใช้ Husky เพราะหลังจากที่มีการ commit หรือ push ให้ได้ผลลัพธ์ที่ตามที่เราต้องการก่อนที่จะถูกบันทึก

นี่คือเหตุผลที่เราพิจารณาใช้ Husky ในโปรเจคของเรา:

  1. การทดสอบโค้ด (test): เราสามารถให้ Husky run unit test เพื่อทดสอบโค้ดของเราก่อนที่เราจะ commit โค้ดนี้ เพื่อช่วยในการค้นหาข้อผิดพลาดและป้องกันการ commit โค้ดที่ไม่ได้ผ่านการทดสอบ
  2. รักษามาตรฐานโค้ด (lint): เราสามารถใช้ Husky เพื่อตรวจสอบว่าโค้ดของเราเป็นไปตามมาตรฐานที่กำหนดไว้หรือไม่ เช่น การใช้ linters, formatters, หรือ tools อื่นๆ ที่ช่วยในการรักษามาตรฐานโค้ด
  3. ป้องกันข้อมูลที่ไม่เอาไว้ใจ (verify data): เราสามารถให้ Husky ทำงานก่อน push เพื่อตรวจสอบความถูกต้องของโค้ดก่อนที่จะนำขึ้นไปยัง repository
  4. การป้องกันการ commit ที่ไม่เกี่ยวข้อง (validate commit): เราสามารถให้ Husky ทำงานใน pre-commit hooks เพื่อตรวจสอบความถูกต้องของการ commit และป้องกันการ commit ที่ไม่เกี่ยวข้อง
  5. ป้องกันการทำ Rebase ที่ไม่ได้บันทึก (prevent uncommitted changes): เราสามารถใช้ Husky เพื่อป้องกันการ rebase ที่ไม่ได้บันทึกหรือทำการ rebase ที่มีการแก้ไขโค้ดที่ไม่ถูกต้อง

การใช้ Husky ช่วยให้การพัฒนาโค้ดของเราเป็นไปอย่างเรียบร้อยและปลอดภัยมากขึ้น แต่ก็ควรระมัดระวังในการตั้งค่า Husky ให้เหมาะสมกับโปรเจคของเราเพื่อป้องกันการทำงานที่เราไม่คาดคิดหรือไม่พึงประสงค์ได้

วิธีการติดตั้ง Husky ในรูปแบบ Manual

การติดตั้ง Husky กับ VSCode ไม่ยากเลย เราต้องทำตามขั้นตอนเหล่านี้:

  1. ติดตั้ง Node.js และ npm: ก่อนที่เราจะติดตั้ง Husky, เราต้องมี Node.js และ npm ติดตั้งในเครื่องของเรา เราสามารถดาวน์โหลดและติดตั้งทั้งคู่ได้จาก เว็บไซต์ Node.js.
  2. สร้างไฟล์ package.json ถ้ายังไม่มี: เราสามารถสร้างไฟล์ package.json ด้วยคำสั่ง
npm init -y

หรือ

yarn init -y

3. ติดตั้ง Husky:

  • ใช้คำสั่ง
npm install husky --save-dev

หรือ

yarn add husky --dev

เพื่อติดตั้ง Husky เป็น dependency ของโปรเจค

4. เพิ่มคำสั่งที่จะให้ Husky ทำงาน:

  • เพิ่มคำสั่งที่เราต้องการให้ Husky ทำงานตามที่เราต้องการ โดยเราทำในไฟล์ package.json ในส่วน "husky":
"husky": {
"hooks": {
"pre-commit": "npm test",
"pre-push": "npm run lint"
}
}

ตอนนี้เราเป็นเจ้าของ Husky และ พร้อมที่จะเพิ่มประสิทธิภาพให้โปรเจคของเราแล้ว

**หมายเหตุ: ขั้นตอนการติดตั้ง ที่ผ่านมาเป็นขั้นตอนการติดตั้ง Husky ในรูปแบบ manual ขั้นตอนการติดตั้ง Husky ในรูปแบบ automatic มีดังนี้

การติดตั้ง Husky ในรูปแบบ Automatic มีดังนี้

  1. ใช้คำสั่งนี้เพื่อติดตั้ง Husky:

npm:

npx husky-init && npm install

yarn:

yarn dlx husky-init --yarn2 && yarn

pnpm:

pnpm dlx husky-init && pnpm install

bun:

bunx husky-init && bun install

คำสั่งเหล่านี้

  • จะเพิ่ม script “prepare” ในไฟล์ package.json
  • สร้างไฟล์ pre-commit hook
  • กำหนด Git hooks path

2. หากต้องการเพิ่ม Git Hook (husky add):

  • ตัวอย่างคำสั่ง
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'

ขั้นตอนนี้จะเพิ่ม Git Hook commit-msg และกำหนดคำสั่งที่ต้องการให้ Husky ดำเนินการเมื่อเกิดเหตุการณ์นี้

หมายเหตุ: หากคุณใช้ Windows และพบปัญหาเมื่อใช้คำสั่ง npx husky add

  • ลองใช้คำสั่ง
node node_modules/husky/lib/bin add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'

คำสั่งนี้ควรจะช่วยแก้ไขปัญหาที่เกิดขึ้นได้

ทั้งหมดนี้จะช่วยในการติดตั้งและกำหนดค่า Husky ในโปรเจคของเรา อย่าลืมแก้ไขไฟล์ Git Hooks ตามความต้องการของโปรเจค และรัน npm install เพื่อติดตั้ง dependencies ที่ Husky ต้องการ

ตัวอย่าง คำสั่ง Git Hook ที่ Husky Support

  • pre-commit: ทำงานก่อน commit
"husky": {
"hooks": {
"pre-commit": "npm test"
}
}
  • pre-push: ทำงานก่อน push
"husky": {
"hooks": {
"pre-push": "npm run lint"
}
}
  • pre-rebase: ทำงานก่อน rebase
"husky": {
"hooks": {
"pre-rebase": "npm run build"
}
}
  • pre-merge-commit: ทำงานก่อน merge commit
"husky": {
"hooks": {
"pre-merge-commit": "npm run format"
}
}
  • pre-merge-base: ทำงานก่อน merge base
"husky": {
"hooks": {
"pre-merge-base": "npm run security-check"
}
}
  • post-commit: ทำงานหลังจาก commit
"husky": {
"hooks": {
"post-commit": "npm run after-commit"
}
}
  • post-push: ทำงานหลังจาก push
"husky": {
"hooks": {
"post-push": "npm run after-push"
}
}
  • post-rebase: ทำงานหลังจากที่ rebase ถูกทำ
"husky": {
"hooks": {
"post-rebase": "npm run after-rebase"
}
}
  • post-merge-commit: ทำงานหลังจาก merge commit
"husky": {
"hooks": {
"post-merge-commit": "npm run after-merge-commit"
}
}
  • post-merge-base: ทำงานหลังจาก merge base
"husky": {
"hooks": {
"post-merge-base": "npm run after-merge-base"
}
}
  • pre-applypatch: ทำงานก่อน patch
"husky": {
"hooks": {
"pre-applypatch": "echo 'pre-applypatch hook'"
}
}
  • post-applypatch: ทำงานหลังจาก patch
"husky": {
"hooks": {
"post-applypatch": "echo 'post-applypatch hook'"
}
}
  • pre-commit-msg: ทำงานก่อน commit message
"husky": {
"hooks": {
"pre-commit-msg": "echo 'pre-commit-msg hook'"
}
}
  • commit-msg: ทำงาน commit message
"husky": {
"hooks": {
"commit-msg": "echo 'commit-msg hook'"
}
}

ข้อดีของ Husky

  1. ป้องกันข้อผิดพลาดก่อนที่จะ Commit: Husky ช่วยป้องกันการ Commit ที่มีข้อผิดพลาดโดยการรันการทดสอบหรือตรวจสอบโค้ดอัตโนมัติ ก่อนที่จะทำการ Commit ทำให้โค้ดที่มีคุณภาพมากขึ้น
  2. ทำงานอัตโนมัติ: การใช้ Husky ช่วยในการทำงานกับ Git Hooks โดยอัตโนมัติ ลดความลำบากในการพัฒนา
  3. ป้องกัน Commit ที่ไม่ผ่านทดสอบ: การให้ Husky รันทดสอบอัตโนมัติ ช่วยป้องกันการส่งโค้ดที่ไม่ผ่านการทดสอบ เพิ่มคุณภาพของโค้ด
  4. ควบคุมข้อความ Commit: Husky ช่วยในการควบคุมรูปแบบของข้อความ Commit ทำให้ประวัติของโค้ดมีความอ่านง่าย
  5. Customization: สามารถปรับแต่ง Hooks เพื่อตรงกับความต้องการของทีมหรือโปรเจค

ข้อเสียของ Husky

  1. เรียนรู้การใช้งาน: การใช้ Husky อาจต้องการเวลาในการเรียนรู้การใช้ Git Hooks และการกำหนดคำสั่งที่ถูกต้อง
  2. การปรับแต่งต้องการความเข้าใจ: การปรับแต่ง Husky ต้องการความเข้าใจในการใช้ Git Hooks และการกำหนดค่าที่ถูกต้อง
  3. ขึ้นอยู่กับทีม: การใช้ Husky ให้มีประสิทธิภาพขึ้นอยู่กับการนำไปใช้ในทีมพัฒนาและการเข้าใจของสมาชิกทีม
  4. ต้องปรับเพิ่มเติมสำหรับ project ใหญ่: สำหรับ project ใหญ่ และ ซับซ้อน การปรับ Husky อาจต้องใช้การกำหนดค่าเพิ่มเติม

สรุป

Husky เป็นเครื่องมือที่ไม่เพียงช่วยในการทำ Git Hooks อัตโนมัติ แต่ยังช่วยในการควบคุมคุณภาพของโค้ดและป้องกันข้อผิดพลาด การใช้ Husky กับ VSCode เป็นทางเลือกที่มีประสิทธิภาพสำหรับทีมพัฒนาที่ต้องจัดการ Git Hooks อย่างมีประสิทธิภาพและยืดหยุ่น ด้วยคุณสมบัติที่หลากหลาย Husky เป็นเครื่องมือที่น่าสนใจในการใช้ช่วยในการพัฒนาโค้ด

Example Project

ตัวอย่าง project ที่ใช้ express framework ในการพัฒนา และ ใช้ Husky ในการตรวจสอบความถูกต้องของโค้ด ด้วย es-lint ของโปรเจค โดยให้ husky รันคำสั่ง lint อัตโนมัติก่อน commit

ขั้นตอนการสร้าง Project

  1. สร้างไฟล์ package.jsonด้วยคำสั่ง
npm init -y

หรือ

yarn init -y

2. project ตัวที่สร้างใช้ typescript ดังนั้นต้องใช้ คำสั่ง

npx tsc --init

เพื่อกำหนด rule ของ typescript

{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"rootDir": "src",
"outDir": "dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"moduleResolution":"node",
"declaration": true,
"emitDecoratorMetadata":true,
"experimentalDecorators":true,
"noImplicitUseStrict":false,
"baseUrl":"src/app.ts",
"listFiles":false,
"noEmitHelpers":false,
"noImplicitReturns": true,
"suppressImplicitAnyIndexErrors": false
},
"include": [
"src/**/*"
],
"exclude":[
"node_modules"
],
"compileOnSave":false
}
tsconfig.json

3. ติดตั้ง library ที่ต้องใช้ สำคัญที่สุดคือตัว husky ที่เราจะต้องติดตั้ง

npm install --save-dev typescript
npm install express @types/express
npm install --save-dev eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser
npx husky-init && npm install
npm i nodemon --save-dev
dependencies for package.json (library)

4.สร้าง file eslint config ด้วยคำสั่ง

npm init @eslint/config
create file eslintconfig
{
"env": {
"node": true,
"es2016": true
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"unused-imports"
],
"ignore": [
"/dist/"
],
"rules": {
"camelcase": 0,
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "off",
"unused-imports/no-unused-imports": "error",
"@typescript-eslint/type-annotation-spacing": "error",
"space-before-function-paren": "off",
"@typescript-eslint/space-before-function-paren": ["error", "never"]
}
}

5. แก้ไข script ในตัว package.json

{
"name": "test-husky-lint-express-framework",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "node dist/app.js",
"dev": "nodemon src/app.ts",
"build": "npx tsc -p .",
"lint": "eslint **/src/*.ts **/src/**/*.ts",
"lint-autofix": "eslint **/src/*.ts **/src/**/*.ts --fix"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^6.12.0",
"@typescript-eslint/parser": "^6.12.0",
"eslint": "^8.54.0",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-n": "^16.3.1",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-unused-imports": "^3.0.0",
"husky": "^8.0.3",
"typescript": "^5.3.2"
},
"dependencies": {
"@types/express": "^4.17.21",
"express": "^4.18.2"
}
}

6. สร้าง husky folder ด้วยคำสั่ง

npx husky add .husky/pre-commit 'npm run lint'

7. สร้าง folder src และใน folder src สร้าง file app.ts โดยใส่ code ตัวอย่างดังนี้

import express, { Express, Request, Response } from 'express'

const app: Express = express()
const port: number = 3000

app.get('/', (req: Request, res: Response) => {
res.send('Hello, World!')
})

app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`)
})

8. ลองทดสอบ ยิง api ที่สร้างขึ้นว่าทำได้ปกติ ตามรูปดังนี้

9. ก่อนที่จะทำให้ husky ใช้งานได้ เราต้องใช้คำสั่ง

git init

เพื่อสร้างไฟล์ .git ใน project หลังจากนั้นเราจะสามาใช้ คำสั่ง git ต่างๆ ได้ ไม่ว่าจะเป็น git add, git commit เป็นต้น ซึ่ง husky จะรันก็ต่อเมื่อเรา ใช้คำสั่ง git commit

ตัวอย่างเมื่อ husky เริ่มทำงาน

  • กรณีที่ lint ไม่ error จะแสดงผลลัพธ์ดังรูป เมื่อเรา commit
  • กรณี lint error จะแสดงผลลัพธ์ดังรูป เมื่อเราเข้าไปแก้ไข commit เดิม

จะเห็นได้จาก ตัวอย่างโปรเจค Husky มีส่วนเข้ามาช่วยแก้ไขข้อผิดพลาดของโค้ดได้โดยเตือนเราให้กลับไปแก้ไข lint ที่ error ก่อนที่เราจะ commit โค้ด แต่ Husky ไม่ได้มีความสามารถเท่านี้ยัง รองรับคำสั่งของ Git Hooks อีกหลายคำสั่ง และถ้าใครอยากจะเอาโปรเจคนี้ไปลองเล่นสามารถ โหลดได้จาก link นี้

บทความนี้ อาจไม่ดีไปกว่าบทความอื่นที่เขียนเกี่ยวกับ Husky แต่ผมเขียนบทความนี้ขึ้น เพราะผมมองว่าเครื่องมือตัวนี้มันดีต่อการนำไปใช้กับโปรเจค ในเรื่องของการแก้ไขข้อผิดพลาดที่อาจเกิดขึ้นก่อนที่เราจะ upload โค้ดขึ้น repo และช่วยให้โปรเจคที่ทำมีประสิทธิภาพมากขึ้น อยากให้ผู้อ่านทุกคนลองนำเครื่องมือตัวนี้ไปใช้ ลองทำตาม example project หรือ clone โปรเจคไปลองเล่นดู เพื่อบทความนี้เป็นประโยชน์ต่อผู้อ่านที่ใช้เครื่องมือตัวนี้ให้เกิดประโยชน์ต่อไป สุดท้ายนี้ขอขอบคุณผู้อ่านที่อ่านบทความจนจบ ไว้เจอกันใหม่ในบทความถัดไปนะครับ แล้วฝากเอาไว้ว่า Husky ไม่ใช่หมา แต่เป็นเครื่องมือที่ช่วยให้โปรเจคเรามีประสิทธิภาพมากขึ้นครับ

Photo by Creative Commons มอนส์ CC0.

--

--