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

Go Modules

module คือกลุ่มของ Go packages ที่มี version ร่วมกันและแจกจ่ายเป็นหน่วยเดียว โปรเจกต์ Go สมัยใหม่ทุกโปรเจกต์เริ่มต้นด้วย module ระบบ module แทนที่ workflow GOPATH แบบเก่าใน Go 1.11 และกลายเป็นค่าเริ่มต้นใน Go 1.16

Playground note: คำสั่ง go mod ต้องการ go binary และ file system — ไม่สามารถรันใน in-browser runner ได้ ให้ทำตามขั้นตอนด้านล่างใน terminal ของคุณ

Terminal window
mkdir myapp && cd myapp
go mod init github.com/yourname/myapp

คำสั่งนี้สร้างไฟล์ go.mod — manifest ของ module:

module github.com/yourname/myapp
go 1.22

module path (github.com/yourname/myapp) ทำหน้าที่ทั้งเป็น import path prefix สำหรับ packages ของคุณเองและเป็น identifier ที่ modules อื่นใช้เมื่อ depend บน module ของคุณ ไม่จำเป็นต้องเป็น URL จริงระหว่าง development แต่ต้องไม่ซ้ำกันหากคุณเผยแพร่ใน Go module proxy

หลังจากเพิ่ม dependency คุณจะพบสองไฟล์ใน root ของ module:

go.mod — ประกาศ module path, Go version ขั้นต่ำ, และ dependencies ทั้งหมดทั้งทางตรงและทางอ้อม:

module github.com/yourname/myapp
go 1.22
require (
github.com/go-chi/chi/v5 v5.1.0
golang.org/x/text v0.14.0 // indirect
)

go.sum — ทะเบียน cryptographic checksum ทุก zip archive ของ dependency และ go.mod ถูก hash ที่นี่ Go toolchain ตรวจสอบ hash เหล่านี้ทุก build เพื่อรับประกัน reproducibility และป้องกัน supply-chain attacks ให้ commit ทั้งสองไฟล์ลง version control

Terminal window
# เพิ่ม module เวอร์ชันล่าสุด
go get github.com/go-chi/chi/v5
# เพิ่มเวอร์ชันที่ระบุ
go get github.com/go-chi/chi/[email protected]
# อัปเกรด dependency เป็น patch/minor release ล่าสุด
go get -u github.com/go-chi/chi/v5

หลังจาก go get source code ของคุณสามารถ import package ได้:

import "github.com/go-chi/chi/v5"

เมื่อเวลาผ่านไป code และ dependencies อาจไม่สอดคล้องกัน — คุณอาจลบ import หรือเพิ่มโดยไม่ได้รัน go get go mod tidy แก้ไขทั้งสองกรณี:

Terminal window
go mod tidy

คำสั่งนี้เพิ่ม require lines ที่ขาดหาย ลบ require lines สำหรับ packages ที่ไม่ได้ import แล้ว และอัปเดต go.sum ให้ตรงกัน รันก่อน commit ทุกครั้ง

Go บังคับใช้กฎที่เรียกว่า semantic import versioning: หาก module ออก v2 ขึ้นไป import path ต้องรวม major version suffix ด้วย

Terminal window
# v1 — ไม่ต้องใช้ suffix
go get github.com/foo/[email protected]
# import "github.com/foo/bar"
# v2+ — /v2 suffix เป็นส่วนหนึ่งของ import path
go get github.com/foo/bar/[email protected]
# import "github.com/foo/bar/v2"

ซึ่งหมายความว่า major version สองเวอร์ชันของ module เดียวกันสามารถอยู่ร่วมกันใน binary เดียวได้โดยไม่ขัดแย้ง การเปลี่ยน import path เป็นเจตนา: v2 API อนุญาตให้ไม่เข้ากันกับ v1

สิ่งที่ได้ประโยชน์ต้นทุน
go.mod (explicit versioning)reproducible build, dependency ชัดเจนต้อง update เมื่อ dependency เปลี่ยน — go mod tidy บ่อยๆ
semantic versioningbackward compatibility contract ชัดเจนmajor version bump ทำ import path เปลี่ยน — migration cost
go.sum (hash verification)ป้องกัน supply chain attack, verify integrityต้อง commit go.sum ด้วย — หลายคนลืม
go mod vendorair-gapped build ได้, ไม่ต้องพึ่ง networkvendor/ directory ใหญ่, ต้อง sync ทุก dependency update
  • go get เหมือน npm installgo get update go.mod และ download source ไม่ install binary แยก ต่างจาก npm มาก
  • สามารถ ignore go.sumgo.sum ต้อง commit ร่วมกับ go.mod เพื่อ verify dependency integrity — ถ้าขาด build อาจไม่ reproducible
  • replace directive ใช้ใน production ได้replace directive ควรเป็น temporary เท่านั้น (เช่น local testing) ไม่ควรอยู่ใน production go.mod
  • GOPATH/pkg/mod เป็น module cache ถาวรgo clean -modcache ล้าง cache ได้ — ไม่ใช่ permanent storage ควร treat เป็น cache

💡 ตัวอย่างจากของจริง

Kubernetes มี go.mod ที่มี dependency หลักร้อยตัว — vendor/ ถูก commit เพื่อให้ build reproducible ในทุก environment

Go ecosystem: semantic versioning + go.sum hash verification ทำให้ supply chain attack ยากขึ้นมาก — Kubernetes, Docker, Prometheus ทั้งหมด depend on this

Docker: multi-stage Dockerfile ใช้ go mod download ก่อน copy source เพื่อ cache layer — rebuild เร็วขึ้นมากเมื่อ source เปลี่ยนแต่ dependency ไม่เปลี่ยน

คำสั่งใด initialise Go module ใหม่ใน directory ปัจจุบัน?
วัตถุประสงค์ของ go.sum คืออะไร?
go mod tidy ทำอะไร?
module ออก v2.0.0 พร้อม breaking changes import path ต้องเปลี่ยนอย่างไร?