[{"data":1,"prerenderedAt":6354},["ShallowReactive",2],{"blogs-2026-03-30-how-to-use-uv":3,"next-blog-2026-03-30-how-to-use-uv":1188,"prev-blog-2026-03-30-how-to-use-uv":1188,"recommended-blog-2026-03-30-how-to-use-uv":1198,"related-blog-2026-03-30-how-to-use-uv":1199},{"id":4,"title":5,"body":6,"date":1183,"description":1184,"draft":1185,"extension":1186,"meta":1187,"navigation":137,"next":1188,"ogTitle":1189,"path":1190,"pin":1185,"prev":1188,"recommends":1188,"seo":1191,"sitemap":1192,"stem":1193,"tags":1194,"__hash__":1197},"content/blogs/2026-03-30-how-to-use-uv.md","เริ่มต้นใช้งาน uv ตัวจัดการ Python แห่งยุค 2026",{"type":7,"value":8,"toc":1156},"minimark",[9,14,30,34,39,65,69,93,96,108,111,156,160,166,170,234,238,244,306,310,313,372,375,413,416,430,434,438,461,464,472,476,594,598,656,670,674,733,737,741,749,919,933,936,940,992,996,1064,1068,1078,1126,1129,1132,1136,1152],[10,11,13],"h2",{"id":12},"uv-คืออะไร","uv คืออะไร",[15,16,17,21,22,29],"p",{},[18,19,20],"strong",{},"uv"," เป็นเครื่องมือจัดการ Python แบบครบวงจรที่เขียนด้วย Rust ทำงานได้เร็วกว่า pip ถึง 10-100 เท่า สามารถใช้แทน pip, pip-tools, pipx, poetry, pyenv ได้ในตัวเดียว พัฒนาโดยทีม ",[23,24,28],"a",{"href":25,"rel":26},"https://astral.sh/",[27],"nofollow","Astral"," ทีมเดียวกับที่ทำ Ruff (Python linter)",[10,31,33],{"id":32},"_1-วิธีติดตั้ง-uv-บน-macos","1. วิธีติดตั้ง uv บน macOS",[35,36,38],"h3",{"id":37},"ติดตั้งผ่าน-homebrew-แนะนำ","ติดตั้งผ่าน Homebrew (แนะนำ)",[40,41,46],"pre",{"className":42,"code":43,"language":44,"meta":45,"style":45},"language-sh shiki shiki-themes material-theme-lighter one-dark-pro github-dark","brew install uv\n","sh","",[47,48,49],"code",{"__ignoreMap":45},[50,51,54,58,62],"span",{"class":52,"line":53},"line",1,[50,55,57],{"class":56},"sosa_","brew",[50,59,61],{"class":60},"sAlJX"," install",[50,63,64],{"class":60}," uv\n",[35,66,68],{"id":67},"ติดตั้งผ่าน-standalone-installer","ติดตั้งผ่าน Standalone Installer",[40,70,72],{"className":42,"code":71,"language":44,"meta":45,"style":45},"curl -LsSf https://astral.sh/uv/install.sh | sh\n",[47,73,74],{"__ignoreMap":45},[50,75,76,79,83,86,90],{"class":52,"line":53},[50,77,78],{"class":56},"curl",[50,80,82],{"class":81},"sEoV_"," -LsSf",[50,84,85],{"class":60}," https://astral.sh/uv/install.sh",[50,87,89],{"class":88},"sbGrh"," |",[50,91,92],{"class":56}," sh\n",[15,94,95],{},"ตรวจสอบว่าติดตั้งสำเร็จด้วย",[40,97,99],{"className":42,"code":98,"language":44,"meta":45,"style":45},"uv version\n",[47,100,101],{"__ignoreMap":45},[50,102,103,105],{"class":52,"line":53},[50,104,20],{"class":56},[50,106,107],{"class":60}," version\n",[35,109,110],{"id":110},"อัปเดตเวอร์ชัน",[40,112,114],{"className":42,"code":113,"language":44,"meta":45,"style":45},"# ถ้าติดตั้งผ่าน Homebrew\nbrew upgrade uv\n\n# ถ้าติดตั้งผ่าน Standalone Installer\nuv self update\n",[47,115,116,122,132,139,145],{"__ignoreMap":45},[50,117,118],{"class":52,"line":53},[50,119,121],{"class":120},"sDKbk","# ถ้าติดตั้งผ่าน Homebrew\n",[50,123,125,127,130],{"class":52,"line":124},2,[50,126,57],{"class":56},[50,128,129],{"class":60}," upgrade",[50,131,64],{"class":60},[50,133,135],{"class":52,"line":134},3,[50,136,138],{"emptyLinePlaceholder":137},true,"\n",[50,140,142],{"class":52,"line":141},4,[50,143,144],{"class":120},"# ถ้าติดตั้งผ่าน Standalone Installer\n",[50,146,148,150,153],{"class":52,"line":147},5,[50,149,20],{"class":56},[50,151,152],{"class":60}," self",[50,154,155],{"class":60}," update\n",[10,157,159],{"id":158},"_2-รันเครื่องมือแบบง่าย-ๆ-ด้วย-uvx","2. รันเครื่องมือแบบง่าย ๆ ด้วย uvx",[15,161,162,165],{},[47,163,164],{},"uvx"," คือคำสั่งสำหรับรันเครื่องมือ Python แบบไม่ต้องติดตั้งถาวร มันจะสร้าง virtual environment ชั่วคราวให้อัตโนมัติ ใช้เสร็จก็ทิ้งไป เหมาะมากสำหรับเครื่องมือที่ใช้เป็นครั้งคราว",[35,167,169],{"id":168},"รัน-tool-แบบครั้งเดียว","รัน tool แบบครั้งเดียว",[40,171,173],{"className":42,"code":172,"language":44,"meta":45,"style":45},"# รัน ruff (Python linter) โดยไม่ต้องติดตั้ง\nuvx ruff check .\n\n# รัน black (code formatter)\nuvx black my_script.py\n\n# รัน httpie\nuvx httpie https://api.github.com\n",[47,174,175,180,193,197,202,212,217,223],{"__ignoreMap":45},[50,176,177],{"class":52,"line":53},[50,178,179],{"class":120},"# รัน ruff (Python linter) โดยไม่ต้องติดตั้ง\n",[50,181,182,184,187,190],{"class":52,"line":124},[50,183,164],{"class":56},[50,185,186],{"class":60}," ruff",[50,188,189],{"class":60}," check",[50,191,192],{"class":60}," .\n",[50,194,195],{"class":52,"line":134},[50,196,138],{"emptyLinePlaceholder":137},[50,198,199],{"class":52,"line":141},[50,200,201],{"class":120},"# รัน black (code formatter)\n",[50,203,204,206,209],{"class":52,"line":147},[50,205,164],{"class":56},[50,207,208],{"class":60}," black",[50,210,211],{"class":60}," my_script.py\n",[50,213,215],{"class":52,"line":214},6,[50,216,138],{"emptyLinePlaceholder":137},[50,218,220],{"class":52,"line":219},7,[50,221,222],{"class":120},"# รัน httpie\n",[50,224,226,228,231],{"class":52,"line":225},8,[50,227,164],{"class":56},[50,229,230],{"class":60}," httpie",[50,232,233],{"class":60}," https://api.github.com\n",[35,235,237],{"id":236},"ติดตั้ง-tool-แบบถาวร","ติดตั้ง tool แบบถาวร",[15,239,240,241],{},"ถ้าเป็นเครื่องมือที่ใช้บ่อย ๆ สามารถติดตั้งถาวรได้ด้วย ",[47,242,243],{},"uv tool install",[40,245,247],{"className":42,"code":246,"language":44,"meta":45,"style":45},"# ติดตั้ง ruff แบบถาวร\nuv tool install ruff\n\n# ติดตั้ง youtube-dl\nuv tool install yt-dlp\n\n# ติดตั้งจาก git repository\nuv tool install git+https://github.com/maurosoria/dirsearch\n",[47,248,249,254,266,270,275,286,290,295],{"__ignoreMap":45},[50,250,251],{"class":52,"line":53},[50,252,253],{"class":120},"# ติดตั้ง ruff แบบถาวร\n",[50,255,256,258,261,263],{"class":52,"line":124},[50,257,20],{"class":56},[50,259,260],{"class":60}," tool",[50,262,61],{"class":60},[50,264,265],{"class":60}," ruff\n",[50,267,268],{"class":52,"line":134},[50,269,138],{"emptyLinePlaceholder":137},[50,271,272],{"class":52,"line":141},[50,273,274],{"class":120},"# ติดตั้ง youtube-dl\n",[50,276,277,279,281,283],{"class":52,"line":147},[50,278,20],{"class":56},[50,280,260],{"class":60},[50,282,61],{"class":60},[50,284,285],{"class":60}," yt-dlp\n",[50,287,288],{"class":52,"line":214},[50,289,138],{"emptyLinePlaceholder":137},[50,291,292],{"class":52,"line":219},[50,293,294],{"class":120},"# ติดตั้งจาก git repository\n",[50,296,297,299,301,303],{"class":52,"line":225},[50,298,20],{"class":56},[50,300,260],{"class":60},[50,302,61],{"class":60},[50,304,305],{"class":60}," git+https://github.com/maurosoria/dirsearch\n",[35,307,309],{"id":308},"รัน-tool-แบบระบุเวอร์ชัน","รัน tool แบบระบุเวอร์ชัน",[15,311,312],{},"สามารถระบุเวอร์ชันของ tool ที่ต้องการรันได้เลย เหมาะสำหรับกรณีที่ต้องการใช้เวอร์ชันเฉพาะ หรือต้องการทดสอบกับหลาย ๆ เวอร์ชัน",[40,314,316],{"className":42,"code":315,"language":44,"meta":45,"style":45},"# รัน ruff เวอร์ชันที่ต้องการ\nuvx ruff@0.11.0 check .\n\n# รัน ruff เวอร์ชันล่าสุด\nuvx ruff@latest check .\n\n# รัน black เวอร์ชันเฉพาะ\nuvx black@24.4.2 my_script.py\n",[47,317,318,323,334,338,343,354,358,363],{"__ignoreMap":45},[50,319,320],{"class":52,"line":53},[50,321,322],{"class":120},"# รัน ruff เวอร์ชันที่ต้องการ\n",[50,324,325,327,330,332],{"class":52,"line":124},[50,326,164],{"class":56},[50,328,329],{"class":60}," ruff@0.11.0",[50,331,189],{"class":60},[50,333,192],{"class":60},[50,335,336],{"class":52,"line":134},[50,337,138],{"emptyLinePlaceholder":137},[50,339,340],{"class":52,"line":141},[50,341,342],{"class":120},"# รัน ruff เวอร์ชันล่าสุด\n",[50,344,345,347,350,352],{"class":52,"line":147},[50,346,164],{"class":56},[50,348,349],{"class":60}," ruff@latest",[50,351,189],{"class":60},[50,353,192],{"class":60},[50,355,356],{"class":52,"line":214},[50,357,138],{"emptyLinePlaceholder":137},[50,359,360],{"class":52,"line":219},[50,361,362],{"class":120},"# รัน black เวอร์ชันเฉพาะ\n",[50,364,365,367,370],{"class":52,"line":225},[50,366,164],{"class":56},[50,368,369],{"class":60}," black@24.4.2",[50,371,211],{"class":60},[15,373,374],{},"ติดตั้งถาวรแบบระบุเวอร์ชันก็ทำได้เช่นกัน",[40,376,378],{"className":42,"code":377,"language":44,"meta":45,"style":45},"uv tool install 'ruff==0.11.0'\nuv tool install 'black>=24.0,\u003C25.0'\n",[47,379,380,398],{"__ignoreMap":45},[50,381,382,384,386,388,392,395],{"class":52,"line":53},[50,383,20],{"class":56},[50,385,260],{"class":60},[50,387,61],{"class":60},[50,389,391],{"class":390},"snfNA"," '",[50,393,394],{"class":60},"ruff==0.11.0",[50,396,397],{"class":390},"'\n",[50,399,400,402,404,406,408,411],{"class":52,"line":124},[50,401,20],{"class":56},[50,403,260],{"class":60},[50,405,61],{"class":60},[50,407,391],{"class":390},[50,409,410],{"class":60},"black>=24.0,\u003C25.0",[50,412,397],{"class":390},[15,414,415],{},"ดูรายการเครื่องมือที่ติดตั้งไว้",[40,417,419],{"className":42,"code":418,"language":44,"meta":45,"style":45},"uv tool list\n",[47,420,421],{"__ignoreMap":45},[50,422,423,425,427],{"class":52,"line":53},[50,424,20],{"class":56},[50,426,260],{"class":60},[50,428,429],{"class":60}," list\n",[10,431,433],{"id":432},"_3-ใช้งานกับ-python-project","3. ใช้งานกับ Python Project",[35,435,437],{"id":436},"สร้าง-project-ใหม่","สร้าง Project ใหม่",[40,439,441],{"className":42,"code":440,"language":44,"meta":45,"style":45},"uv init my-project\ncd my-project\n",[47,442,443,453],{"__ignoreMap":45},[50,444,445,447,450],{"class":52,"line":53},[50,446,20],{"class":56},[50,448,449],{"class":60}," init",[50,451,452],{"class":60}," my-project\n",[50,454,455,459],{"class":52,"line":124},[50,456,458],{"class":457},"sJZfL","cd",[50,460,452],{"class":60},[15,462,463],{},"uv จะสร้างไฟล์ให้อัตโนมัติ",[40,465,470],{"className":466,"code":468,"language":469},[467],"language-text","my-project/\n├── .python-version\n├── README.md\n├── main.py\n└── pyproject.toml\n","text",[47,471,468],{"__ignoreMap":45},[35,473,475],{"id":474},"เพิ่มลบ-dependencies","เพิ่ม/ลบ Dependencies",[40,477,479],{"className":42,"code":478,"language":44,"meta":45,"style":45},"# เพิ่ม package\nuv add requests\nuv add flask sqlalchemy\n\n# เพิ่มแบบระบุเวอร์ชัน\nuv add 'requests==2.32.0'\n\n# เพิ่มจาก git\nuv add git+https://github.com/psf/requests\n\n# เพิ่มจาก requirements.txt ที่มีอยู่แล้ว\nuv add -r requirements.txt\n\n# ลบ package\nuv remove requests\n",[47,480,481,486,496,508,512,517,530,534,539,549,554,560,573,578,584],{"__ignoreMap":45},[50,482,483],{"class":52,"line":53},[50,484,485],{"class":120},"# เพิ่ม package\n",[50,487,488,490,493],{"class":52,"line":124},[50,489,20],{"class":56},[50,491,492],{"class":60}," add",[50,494,495],{"class":60}," requests\n",[50,497,498,500,502,505],{"class":52,"line":134},[50,499,20],{"class":56},[50,501,492],{"class":60},[50,503,504],{"class":60}," flask",[50,506,507],{"class":60}," sqlalchemy\n",[50,509,510],{"class":52,"line":141},[50,511,138],{"emptyLinePlaceholder":137},[50,513,514],{"class":52,"line":147},[50,515,516],{"class":120},"# เพิ่มแบบระบุเวอร์ชัน\n",[50,518,519,521,523,525,528],{"class":52,"line":214},[50,520,20],{"class":56},[50,522,492],{"class":60},[50,524,391],{"class":390},[50,526,527],{"class":60},"requests==2.32.0",[50,529,397],{"class":390},[50,531,532],{"class":52,"line":219},[50,533,138],{"emptyLinePlaceholder":137},[50,535,536],{"class":52,"line":225},[50,537,538],{"class":120},"# เพิ่มจาก git\n",[50,540,542,544,546],{"class":52,"line":541},9,[50,543,20],{"class":56},[50,545,492],{"class":60},[50,547,548],{"class":60}," git+https://github.com/psf/requests\n",[50,550,552],{"class":52,"line":551},10,[50,553,138],{"emptyLinePlaceholder":137},[50,555,557],{"class":52,"line":556},11,[50,558,559],{"class":120},"# เพิ่มจาก requirements.txt ที่มีอยู่แล้ว\n",[50,561,563,565,567,570],{"class":52,"line":562},12,[50,564,20],{"class":56},[50,566,492],{"class":60},[50,568,569],{"class":81}," -r",[50,571,572],{"class":60}," requirements.txt\n",[50,574,576],{"class":52,"line":575},13,[50,577,138],{"emptyLinePlaceholder":137},[50,579,581],{"class":52,"line":580},14,[50,582,583],{"class":120},"# ลบ package\n",[50,585,587,589,592],{"class":52,"line":586},15,[50,588,20],{"class":56},[50,590,591],{"class":60}," remove",[50,593,495],{"class":60},[35,595,597],{"id":596},"รัน-project","รัน Project",[40,599,601],{"className":42,"code":600,"language":44,"meta":45,"style":45},"# รันไฟล์ Python ใน project\nuv run main.py\n\n# รัน framework command เช่น Flask\nuv add flask\nuv run -- flask run -p 3000\n",[47,602,603,608,618,622,627,636],{"__ignoreMap":45},[50,604,605],{"class":52,"line":53},[50,606,607],{"class":120},"# รันไฟล์ Python ใน project\n",[50,609,610,612,615],{"class":52,"line":124},[50,611,20],{"class":56},[50,613,614],{"class":60}," run",[50,616,617],{"class":60}," main.py\n",[50,619,620],{"class":52,"line":134},[50,621,138],{"emptyLinePlaceholder":137},[50,623,624],{"class":52,"line":141},[50,625,626],{"class":120},"# รัน framework command เช่น Flask\n",[50,628,629,631,633],{"class":52,"line":147},[50,630,20],{"class":56},[50,632,492],{"class":60},[50,634,635],{"class":60}," flask\n",[50,637,638,640,642,645,647,649,652],{"class":52,"line":214},[50,639,20],{"class":56},[50,641,614],{"class":60},[50,643,644],{"class":81}," --",[50,646,504],{"class":60},[50,648,614],{"class":60},[50,650,651],{"class":81}," -p",[50,653,655],{"class":654},"snOyU"," 3000\n",[15,657,658,661,662,665,666,669],{},[47,659,660],{},"uv run"," จะจัดการ sync dependencies และสร้าง virtual environment ให้อัตโนมัติ ไม่ต้อง ",[47,663,664],{},"pip install"," หรือ ",[47,667,668],{},"source .venv/bin/activate"," เอง",[35,671,673],{"id":672},"จัดการเวอร์ชัน-python","จัดการเวอร์ชัน Python",[40,675,677],{"className":42,"code":676,"language":44,"meta":45,"style":45},"# ดูเวอร์ชัน Python ที่มีให้ติดตั้ง\nuv python list\n\n# ติดตั้ง Python เวอร์ชันที่ต้องการ\nuv python install 3.12\n\n# ตรึงเวอร์ชัน Python ของ project\nuv python pin 3.12\n",[47,678,679,684,693,697,702,713,717,722],{"__ignoreMap":45},[50,680,681],{"class":52,"line":53},[50,682,683],{"class":120},"# ดูเวอร์ชัน Python ที่มีให้ติดตั้ง\n",[50,685,686,688,691],{"class":52,"line":124},[50,687,20],{"class":56},[50,689,690],{"class":60}," python",[50,692,429],{"class":60},[50,694,695],{"class":52,"line":134},[50,696,138],{"emptyLinePlaceholder":137},[50,698,699],{"class":52,"line":141},[50,700,701],{"class":120},"# ติดตั้ง Python เวอร์ชันที่ต้องการ\n",[50,703,704,706,708,710],{"class":52,"line":147},[50,705,20],{"class":56},[50,707,690],{"class":60},[50,709,61],{"class":60},[50,711,712],{"class":654}," 3.12\n",[50,714,715],{"class":52,"line":214},[50,716,138],{"emptyLinePlaceholder":137},[50,718,719],{"class":52,"line":219},[50,720,721],{"class":120},"# ตรึงเวอร์ชัน Python ของ project\n",[50,723,724,726,728,731],{"class":52,"line":225},[50,725,20],{"class":56},[50,727,690],{"class":60},[50,729,730],{"class":60}," pin",[50,732,712],{"class":654},[10,734,736],{"id":735},"_4-อื่น-ๆ-ที่น่าสนใจ","4. อื่น ๆ ที่น่าสนใจ",[35,738,740],{"id":739},"รัน-script-พร้อม-dependencies-แบบ-inline","รัน Script พร้อม Dependencies แบบ Inline",[15,742,743,744],{},"สามารถประกาศ dependencies ไว้ในไฟล์ Python ได้เลย โดยใช้ inline metadata ตาม ",[23,745,748],{"href":746,"rel":747},"https://peps.python.org/pep-0723/",[27],"PEP 723",[40,750,755],{"className":751,"code":752,"filename":753,"language":754,"meta":45,"style":45},"language-python shiki shiki-themes material-theme-lighter one-dark-pro github-dark","# /// script\n# dependencies = [\n#   \"httpx\",\n# ]\n# ///\n\nimport httpx\n\nresp = httpx.get(\"https://peps.python.org/api/peps.json\")\ndata = resp.json()\nprint([(k, v[\"title\"]) for k, v in data.items()][:10])\n","fetch_peps.py","python",[47,756,757,765,770,775,780,787,791,801,805,839,857],{"__ignoreMap":45},[50,758,759,762],{"class":52,"line":53},[50,760,761],{"class":120},"#",[50,763,764],{"class":120}," /// script\n",[50,766,767],{"class":52,"line":124},[50,768,769],{"class":120},"# dependencies = [\n",[50,771,772],{"class":52,"line":134},[50,773,774],{"class":120},"#   \"httpx\",\n",[50,776,777],{"class":52,"line":141},[50,778,779],{"class":120},"# ]\n",[50,781,782,784],{"class":52,"line":147},[50,783,761],{"class":120},[50,785,786],{"class":120}," ///\n",[50,788,789],{"class":52,"line":214},[50,790,138],{"emptyLinePlaceholder":137},[50,792,793,797],{"class":52,"line":219},[50,794,796],{"class":795},"s36IK","import",[50,798,800],{"class":799},"sZDfs"," httpx\n",[50,802,803],{"class":52,"line":225},[50,804,138],{"emptyLinePlaceholder":137},[50,806,807,810,814,817,821,825,828,831,834,836],{"class":52,"line":541},[50,808,809],{"class":799},"resp ",[50,811,813],{"class":812},"sMTEB","=",[50,815,816],{"class":799}," httpx",[50,818,820],{"class":819},"stlKB",".",[50,822,824],{"class":823},"s5BH7","get",[50,826,827],{"class":819},"(",[50,829,830],{"class":390},"\"",[50,832,833],{"class":60},"https://peps.python.org/api/peps.json",[50,835,830],{"class":390},[50,837,838],{"class":819},")\n",[50,840,841,844,846,849,851,854],{"class":52,"line":551},[50,842,843],{"class":799},"data ",[50,845,813],{"class":812},[50,847,848],{"class":799}," resp",[50,850,820],{"class":819},[50,852,853],{"class":823},"json",[50,855,856],{"class":819},"()\n",[50,858,859,862,865,869,872,875,878,880,883,885,888,891,894,896,899,902,905,907,910,913,916],{"class":52,"line":556},[50,860,861],{"class":457},"print",[50,863,864],{"class":819},"([(",[50,866,868],{"class":867},"sb6-j","k",[50,870,871],{"class":819},",",[50,873,874],{"class":867}," v",[50,876,877],{"class":819},"[",[50,879,830],{"class":390},[50,881,882],{"class":60},"title",[50,884,830],{"class":390},[50,886,887],{"class":819},"])",[50,889,890],{"class":795}," for",[50,892,893],{"class":867}," k",[50,895,871],{"class":819},[50,897,898],{"class":867}," v ",[50,900,901],{"class":795},"in",[50,903,904],{"class":867}," data",[50,906,820],{"class":819},[50,908,909],{"class":823},"items",[50,911,912],{"class":819},"()][:",[50,914,915],{"class":654},"10",[50,917,918],{"class":819},"])\n",[40,920,922],{"className":42,"code":921,"language":44,"meta":45,"style":45},"uv run fetch_peps.py\n",[47,923,924],{"__ignoreMap":45},[50,925,926,928,930],{"class":52,"line":53},[50,927,20],{"class":56},[50,929,614],{"class":60},[50,931,932],{"class":60}," fetch_peps.py\n",[15,934,935],{},"uv จะอ่าน dependencies จาก comment ในไฟล์แล้วติดตั้งให้อัตโนมัติ เหมาะมากสำหรับ script เล็ก ๆ ที่ไม่อยากสร้าง project เต็มรูปแบบ",[35,937,939],{"id":938},"รัน-script-พร้อมระบุ-dependencies-ผ่าน-cli","รัน Script พร้อมระบุ Dependencies ผ่าน CLI",[40,941,943],{"className":42,"code":942,"language":44,"meta":45,"style":45},"# รัน script พร้อมติดตั้ง rich ให้อัตโนมัติ\nuv run --with rich example.py\n\n# ระบุเวอร์ชันได้\nuv run --with 'rich>12,\u003C13' example.py\n",[47,944,945,950,965,969,974],{"__ignoreMap":45},[50,946,947],{"class":52,"line":53},[50,948,949],{"class":120},"# รัน script พร้อมติดตั้ง rich ให้อัตโนมัติ\n",[50,951,952,954,956,959,962],{"class":52,"line":124},[50,953,20],{"class":56},[50,955,614],{"class":60},[50,957,958],{"class":81}," --with",[50,960,961],{"class":60}," rich",[50,963,964],{"class":60}," example.py\n",[50,966,967],{"class":52,"line":134},[50,968,138],{"emptyLinePlaceholder":137},[50,970,971],{"class":52,"line":141},[50,972,973],{"class":120},"# ระบุเวอร์ชันได้\n",[50,975,976,978,980,982,984,987,990],{"class":52,"line":147},[50,977,20],{"class":56},[50,979,614],{"class":60},[50,981,958],{"class":81},[50,983,391],{"class":390},[50,985,986],{"class":60},"rich>12,\u003C13",[50,988,989],{"class":390},"'",[50,991,964],{"class":60},[35,993,995],{"id":994},"ใช้-uv-ใน-docker","ใช้ uv ใน Docker",[40,997,1001],{"className":998,"code":999,"language":1000,"meta":45,"style":45},"language-dockerfile shiki shiki-themes material-theme-lighter one-dark-pro github-dark","FROM python:3.12-slim\n\n# ติดตั้ง uv\nCOPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/\n\n# ติดตั้ง dependencies\nCOPY pyproject.toml uv.lock ./\nRUN uv sync --frozen --no-dev\n\n# คัดลอก source code\nCOPY . .\n\nCMD [\"uv\", \"run\", \"main.py\"]\n","dockerfile",[47,1002,1003,1008,1012,1017,1022,1026,1031,1036,1041,1045,1050,1055,1059],{"__ignoreMap":45},[50,1004,1005],{"class":52,"line":53},[50,1006,1007],{},"FROM python:3.12-slim\n",[50,1009,1010],{"class":52,"line":124},[50,1011,138],{"emptyLinePlaceholder":137},[50,1013,1014],{"class":52,"line":134},[50,1015,1016],{},"# ติดตั้ง uv\n",[50,1018,1019],{"class":52,"line":141},[50,1020,1021],{},"COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/\n",[50,1023,1024],{"class":52,"line":147},[50,1025,138],{"emptyLinePlaceholder":137},[50,1027,1028],{"class":52,"line":214},[50,1029,1030],{},"# ติดตั้ง dependencies\n",[50,1032,1033],{"class":52,"line":219},[50,1034,1035],{},"COPY pyproject.toml uv.lock ./\n",[50,1037,1038],{"class":52,"line":225},[50,1039,1040],{},"RUN uv sync --frozen --no-dev\n",[50,1042,1043],{"class":52,"line":541},[50,1044,138],{"emptyLinePlaceholder":137},[50,1046,1047],{"class":52,"line":551},[50,1048,1049],{},"# คัดลอก source code\n",[50,1051,1052],{"class":52,"line":556},[50,1053,1054],{},"COPY . .\n",[50,1056,1057],{"class":52,"line":562},[50,1058,138],{"emptyLinePlaceholder":137},[50,1060,1061],{"class":52,"line":575},[50,1062,1063],{},"CMD [\"uv\", \"run\", \"main.py\"]\n",[35,1065,1067],{"id":1066},"ใช้-uv-แทน-pip-ได้เลย","ใช้ uv แทน pip ได้เลย",[15,1069,1070,1071,1074,1075,1077],{},"สำหรับคนที่ยังชินกับ pip สามารถใช้ ",[47,1072,1073],{},"uv pip"," แทนได้เลย แค่เติม ",[47,1076,20],{}," ข้างหน้า",[40,1079,1081],{"className":42,"code":1080,"language":44,"meta":45,"style":45},"uv pip install requests\nuv pip install -r requirements.txt\nuv pip freeze\nuv pip uninstall requests\n",[47,1082,1083,1094,1106,1115],{"__ignoreMap":45},[50,1084,1085,1087,1090,1092],{"class":52,"line":53},[50,1086,20],{"class":56},[50,1088,1089],{"class":60}," pip",[50,1091,61],{"class":60},[50,1093,495],{"class":60},[50,1095,1096,1098,1100,1102,1104],{"class":52,"line":124},[50,1097,20],{"class":56},[50,1099,1089],{"class":60},[50,1101,61],{"class":60},[50,1103,569],{"class":81},[50,1105,572],{"class":60},[50,1107,1108,1110,1112],{"class":52,"line":134},[50,1109,20],{"class":56},[50,1111,1089],{"class":60},[50,1113,1114],{"class":60}," freeze\n",[50,1116,1117,1119,1121,1124],{"class":52,"line":141},[50,1118,20],{"class":56},[50,1120,1089],{"class":60},[50,1122,1123],{"class":60}," uninstall",[50,1125,495],{"class":60},[10,1127,1128],{"id":1128},"สรุป",[15,1130,1131],{},"uv เป็นเครื่องมือที่ช่วยให้การจัดการ Python ง่ายขึ้นมาก ตั้งแต่การติดตั้ง Python เอง การจัดการ dependencies ไปจนถึงการรันเครื่องมือต่าง ๆ ทั้งหมดนี้ทำได้ด้วยคำสั่งเดียว และที่สำคัญคือเร็วมาก ๆ ลองใช้ดูครับ",[10,1133,1135],{"id":1134},"ref","Ref",[1137,1138,1139,1146],"ul",{},[1140,1141,1142],"li",{},[23,1143,1144],{"href":1144,"rel":1145},"https://docs.astral.sh/uv/",[27],[1140,1147,1148],{},[23,1149,1150],{"href":1150,"rel":1151},"https://github.com/astral-sh/uv",[27],[1153,1154,1155],"style",{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .sbGrh, html code.shiki .sbGrh{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F97583}html pre.shiki code .sDKbk, html code.shiki .sDKbk{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sJZfL, html code.shiki .sJZfL{--shiki-light:#6182B8;--shiki-default:#56B6C2;--shiki-dark:#79B8FF}html pre.shiki code .snOyU, html code.shiki .snOyU{--shiki-light:#F76D47;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .s36IK, html code.shiki .s36IK{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#C678DD;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sZDfs, html code.shiki .sZDfs{--shiki-light:#90A4AE;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sMTEB, html code.shiki .sMTEB{--shiki-light:#39ADB5;--shiki-default:#56B6C2;--shiki-dark:#F97583}html pre.shiki code .stlKB, html code.shiki .stlKB{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .s5BH7, html code.shiki .s5BH7{--shiki-light:#6182B8;--shiki-default:#61AFEF;--shiki-dark:#E1E4E8}html pre.shiki code .sb6-j, html code.shiki .sb6-j{--shiki-light:#6182B8;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}",{"title":45,"searchDepth":124,"depth":124,"links":1157},[1158,1159,1164,1169,1175,1181,1182],{"id":12,"depth":124,"text":13},{"id":32,"depth":124,"text":33,"children":1160},[1161,1162,1163],{"id":37,"depth":134,"text":38},{"id":67,"depth":134,"text":68},{"id":110,"depth":134,"text":110},{"id":158,"depth":124,"text":159,"children":1165},[1166,1167,1168],{"id":168,"depth":134,"text":169},{"id":236,"depth":134,"text":237},{"id":308,"depth":134,"text":309},{"id":432,"depth":124,"text":433,"children":1170},[1171,1172,1173,1174],{"id":436,"depth":134,"text":437},{"id":474,"depth":134,"text":475},{"id":596,"depth":134,"text":597},{"id":672,"depth":134,"text":673},{"id":735,"depth":124,"text":736,"children":1176},[1177,1178,1179,1180],{"id":739,"depth":134,"text":740},{"id":938,"depth":134,"text":939},{"id":994,"depth":134,"text":995},{"id":1066,"depth":134,"text":1067},{"id":1128,"depth":124,"text":1128},{"id":1134,"depth":124,"text":1135},"2026-03-30T00:00:00.000Z","แนะนำวิธีติดตั้งและใช้งาน uv เครื่องมือจัดการ Python ที่เร็วสุด ๆ ตั้งแต่ติดตั้ง รันเครื่องมือ ไปจนถึงจัดการ Project",false,"md",{},null,"How To Use UV","/blogs/2026-03-30-how-to-use-uv",{"title":5,"description":1184},{"loc":1190},"blogs/2026-03-30-how-to-use-uv",[1195,1196],"Development","Python","ln0_RTFwBSq-8FHRuC3G6a-_i9E1QKs1uN4wmNiENVg",[],[1200,2500,2602,2770,3314,3504,4440,4852,5429,5609,5762,6066,6237],{"id":1201,"title":1202,"body":1203,"date":2490,"description":2491,"draft":1185,"extension":1186,"meta":2492,"navigation":137,"next":1188,"ogTitle":2493,"path":2494,"pin":1185,"prev":1188,"recommends":1188,"seo":2495,"sitemap":2496,"stem":2497,"tags":2498,"__hash__":2499},"content/blogs/2024-01-20-simple-paginate.md","Simple Paginate",{"type":7,"value":1204,"toc":2486},[1205,1213,1216,1331,1334,1338,2087,2091,2478,2483],[1137,1206,1207,1210],{},[1140,1208,1209],{},"ปล. เป็น Code แบบ Simple",[1140,1211,1212],{},"ปล2. Code ตัวอย่างคือการใช้งานใน Express + Typescript + Mongoose",[15,1214,1215],{},"ใน output ที่ตอบกลับจะเป็น",[40,1217,1220],{"className":1218,"code":1219,"language":853,"meta":45,"style":45},"language-json shiki shiki-themes material-theme-lighter one-dark-pro github-dark","{\n  \"data\": [],\n  \"currentPage\": \"หน้าปัจจุบัน\",\n  \"nextPage\": \"หน้าถัดไปถ้ามี แต่ถ้าไม่มีจะเป็น Null\",\n  \"prevPage\": \"หน้าก่อนหน้าถ้ามี แต่ถ้าไม่มีจะเป็น Null\",\n  \"count\": \"จำนวน page ที่มี\"\n}\n",[47,1221,1222,1227,1245,1267,1287,1307,1326],{"__ignoreMap":45},[50,1223,1224],{"class":52,"line":53},[50,1225,1226],{"class":819},"{\n",[50,1228,1229,1233,1237,1239,1242],{"class":52,"line":124},[50,1230,1232],{"class":1231},"sObbn","  \"",[50,1234,1236],{"class":1235},"sVeMc","data",[50,1238,830],{"class":1231},[50,1240,1241],{"class":819},":",[50,1243,1244],{"class":819}," [],\n",[50,1246,1247,1249,1252,1254,1256,1259,1262,1264],{"class":52,"line":134},[50,1248,1232],{"class":1231},[50,1250,1251],{"class":1235},"currentPage",[50,1253,830],{"class":1231},[50,1255,1241],{"class":819},[50,1257,1258],{"class":390}," \"",[50,1260,1261],{"class":60},"หน้าปัจจุบัน",[50,1263,830],{"class":390},[50,1265,1266],{"class":819},",\n",[50,1268,1269,1271,1274,1276,1278,1280,1283,1285],{"class":52,"line":141},[50,1270,1232],{"class":1231},[50,1272,1273],{"class":1235},"nextPage",[50,1275,830],{"class":1231},[50,1277,1241],{"class":819},[50,1279,1258],{"class":390},[50,1281,1282],{"class":60},"หน้าถัดไปถ้ามี แต่ถ้าไม่มีจะเป็น Null",[50,1284,830],{"class":390},[50,1286,1266],{"class":819},[50,1288,1289,1291,1294,1296,1298,1300,1303,1305],{"class":52,"line":147},[50,1290,1232],{"class":1231},[50,1292,1293],{"class":1235},"prevPage",[50,1295,830],{"class":1231},[50,1297,1241],{"class":819},[50,1299,1258],{"class":390},[50,1301,1302],{"class":60},"หน้าก่อนหน้าถ้ามี แต่ถ้าไม่มีจะเป็น Null",[50,1304,830],{"class":390},[50,1306,1266],{"class":819},[50,1308,1309,1311,1314,1316,1318,1320,1323],{"class":52,"line":214},[50,1310,1232],{"class":1231},[50,1312,1313],{"class":1235},"count",[50,1315,830],{"class":1231},[50,1317,1241],{"class":819},[50,1319,1258],{"class":390},[50,1321,1322],{"class":60},"จำนวน page ที่มี",[50,1324,1325],{"class":390},"\"\n",[50,1327,1328],{"class":52,"line":219},[50,1329,1330],{"class":819},"}\n",[15,1332,1333],{},"ซึ่งจะทำให้ Frontend สามารถนำไปใช้งานได้ง่ายยิ่งขึ้น",[35,1335,1337],{"id":1336},"_1-สร้างไฟล์-utilspaginationutiljs","1. สร้างไฟล์ utils/pagination.util.js",[40,1339,1343],{"className":1340,"code":1341,"language":1342,"meta":45,"style":45},"language-js shiki shiki-themes material-theme-lighter one-dark-pro github-dark","interface PaginationParams {\n  perPage: number;\n  page: number;\n  skip: number;\n}\n\ninterface PaginationResponse\u003CT> {\n  data: T[];\n  currentPage: number;\n  nextPage?: number;\n  prevPage?: number;\n  count: number;\n}\n\nexport function buildPaginationParam(\n  page: string,\n  perPage: string,\n  limit: number\n): PaginationParams {\n  // Pagination\n  const pageInt = !Number.isNaN(parseInt(page)) ? parseInt(page) : 1\n  let perPageInt = !Number.isNaN(parseInt(perPage)) ? parseInt(perPage) : 10\n\n  // Set a maximum limit\n  perPageInt = Math.min(perPageInt, limit)\n\n  const skip = (pageInt - 1) * perPageInt\n\n  return {\n    perPage: perPageInt,\n    page: pageInt,\n    skip,\n  }\n}\n\nexport function buildResponsePagination\u003CT>(\n  data: T[],\n  page: number,\n  perPage: number,\n  totalCount: number\n): PaginationResponse\u003CT> {\n  const currentPage = page\n  const totalPages = Math.ceil(totalCount / perPage)\n\n  const hasNextPage = currentPage \u003C totalPages\n  const hasPrevPage = currentPage > 1\n\n  const nextPage = hasNextPage ? currentPage + 1 : undefined\n  const prevPage = hasPrevPage ? currentPage - 1 : undefined\n\n  return {\n    data,\n    currentPage,\n    nextPage,\n    prevPage,\n    count: totalCount,\n  }\n}\n","js",[47,1344,1345,1358,1373,1384,1395,1399,1403,1421,1436,1447,1462,1475,1486,1490,1494,1509,1522,1533,1544,1556,1562,1619,1664,1669,1675,1703,1708,1738,1743,1751,1764,1776,1784,1790,1795,1800,1817,1830,1841,1852,1862,1879,1892,1922,1927,1945,1962,1967,1996,2020,2025,2032,2040,2048,2056,2064,2077,2082],{"__ignoreMap":45},[50,1346,1347,1351,1355],{"class":52,"line":53},[50,1348,1350],{"class":1349},"sOHk9","interface",[50,1352,1354],{"class":1353},"sGnaQ"," PaginationParams",[50,1356,1357],{"class":819}," {\n",[50,1359,1360,1364,1366,1370],{"class":52,"line":124},[50,1361,1363],{"class":1362},"slt33","  perPage",[50,1365,1241],{"class":88},[50,1367,1369],{"class":1368},"s6Wr0"," number",[50,1371,1372],{"class":819},";\n",[50,1374,1375,1378,1380,1382],{"class":52,"line":134},[50,1376,1377],{"class":1362},"  page",[50,1379,1241],{"class":88},[50,1381,1369],{"class":1368},[50,1383,1372],{"class":819},[50,1385,1386,1389,1391,1393],{"class":52,"line":141},[50,1387,1388],{"class":1362},"  skip",[50,1390,1241],{"class":88},[50,1392,1369],{"class":1368},[50,1394,1372],{"class":819},[50,1396,1397],{"class":52,"line":147},[50,1398,1330],{"class":819},[50,1400,1401],{"class":52,"line":214},[50,1402,138],{"emptyLinePlaceholder":137},[50,1404,1405,1407,1410,1413,1416,1419],{"class":52,"line":219},[50,1406,1350],{"class":1349},[50,1408,1409],{"class":1353}," PaginationResponse",[50,1411,1412],{"class":819},"\u003C",[50,1414,1415],{"class":1353},"T",[50,1417,1418],{"class":819},">",[50,1420,1357],{"class":819},[50,1422,1423,1426,1428,1431,1434],{"class":52,"line":225},[50,1424,1425],{"class":1362},"  data",[50,1427,1241],{"class":88},[50,1429,1430],{"class":1353}," T",[50,1432,1433],{"class":799},"[]",[50,1435,1372],{"class":819},[50,1437,1438,1441,1443,1445],{"class":52,"line":541},[50,1439,1440],{"class":1362},"  currentPage",[50,1442,1241],{"class":88},[50,1444,1369],{"class":1368},[50,1446,1372],{"class":819},[50,1448,1449,1452,1456,1458,1460],{"class":52,"line":551},[50,1450,1451],{"class":1362},"  nextPage",[50,1453,1455],{"class":1454},"s_AEr","?",[50,1457,1241],{"class":88},[50,1459,1369],{"class":1368},[50,1461,1372],{"class":819},[50,1463,1464,1467,1469,1471,1473],{"class":52,"line":556},[50,1465,1466],{"class":1362},"  prevPage",[50,1468,1455],{"class":1454},[50,1470,1241],{"class":88},[50,1472,1369],{"class":1368},[50,1474,1372],{"class":819},[50,1476,1477,1480,1482,1484],{"class":52,"line":562},[50,1478,1479],{"class":1362},"  count",[50,1481,1241],{"class":88},[50,1483,1369],{"class":1368},[50,1485,1372],{"class":819},[50,1487,1488],{"class":52,"line":575},[50,1489,1330],{"class":819},[50,1491,1492],{"class":52,"line":580},[50,1493,138],{"emptyLinePlaceholder":137},[50,1495,1496,1499,1502,1506],{"class":52,"line":586},[50,1497,1498],{"class":795},"export",[50,1500,1501],{"class":1349}," function",[50,1503,1505],{"class":1504},"suMxZ"," buildPaginationParam",[50,1507,1508],{"class":819},"(\n",[50,1510,1512,1515,1517,1520],{"class":52,"line":1511},16,[50,1513,1377],{"class":1514},"stkEM",[50,1516,1241],{"class":88},[50,1518,1519],{"class":1368}," string",[50,1521,1266],{"class":819},[50,1523,1525,1527,1529,1531],{"class":52,"line":1524},17,[50,1526,1363],{"class":1514},[50,1528,1241],{"class":88},[50,1530,1519],{"class":1368},[50,1532,1266],{"class":819},[50,1534,1536,1539,1541],{"class":52,"line":1535},18,[50,1537,1538],{"class":1514},"  limit",[50,1540,1241],{"class":88},[50,1542,1543],{"class":1368}," number\n",[50,1545,1547,1550,1552,1554],{"class":52,"line":1546},19,[50,1548,1549],{"class":819},")",[50,1551,1241],{"class":88},[50,1553,1354],{"class":1353},[50,1555,1357],{"class":819},[50,1557,1559],{"class":52,"line":1558},20,[50,1560,1561],{"class":120},"  // Pagination\n",[50,1563,1565,1568,1572,1575,1578,1582,1584,1587,1590,1593,1595,1599,1602,1604,1607,1609,1611,1614,1616],{"class":52,"line":1564},21,[50,1566,1567],{"class":1349},"  const",[50,1569,1571],{"class":1570},"sUzmo"," pageInt",[50,1573,1574],{"class":812}," =",[50,1576,1577],{"class":812}," !",[50,1579,1581],{"class":1580},"sU9mH","Number",[50,1583,820],{"class":819},[50,1585,1586],{"class":1504},"isNaN",[50,1588,827],{"class":1589},"sbHgf",[50,1591,1592],{"class":1504},"parseInt",[50,1594,827],{"class":1589},[50,1596,1598],{"class":1597},"sLHrO","page",[50,1600,1601],{"class":1589},")) ",[50,1603,1455],{"class":1454},[50,1605,1606],{"class":1504}," parseInt",[50,1608,827],{"class":1589},[50,1610,1598],{"class":1597},[50,1612,1613],{"class":1589},") ",[50,1615,1241],{"class":1454},[50,1617,1618],{"class":654}," 1\n",[50,1620,1622,1625,1628,1630,1632,1634,1636,1638,1640,1642,1644,1647,1649,1651,1653,1655,1657,1659,1661],{"class":52,"line":1621},22,[50,1623,1624],{"class":1349},"  let",[50,1626,1627],{"class":1597}," perPageInt",[50,1629,1574],{"class":812},[50,1631,1577],{"class":812},[50,1633,1581],{"class":1580},[50,1635,820],{"class":819},[50,1637,1586],{"class":1504},[50,1639,827],{"class":1589},[50,1641,1592],{"class":1504},[50,1643,827],{"class":1589},[50,1645,1646],{"class":1597},"perPage",[50,1648,1601],{"class":1589},[50,1650,1455],{"class":1454},[50,1652,1606],{"class":1504},[50,1654,827],{"class":1589},[50,1656,1646],{"class":1597},[50,1658,1613],{"class":1589},[50,1660,1241],{"class":1454},[50,1662,1663],{"class":654}," 10\n",[50,1665,1667],{"class":52,"line":1666},23,[50,1668,138],{"emptyLinePlaceholder":137},[50,1670,1672],{"class":52,"line":1671},24,[50,1673,1674],{"class":120},"  // Set a maximum limit\n",[50,1676,1678,1681,1683,1686,1688,1691,1693,1696,1698,1701],{"class":52,"line":1677},25,[50,1679,1680],{"class":1597},"  perPageInt",[50,1682,1574],{"class":812},[50,1684,1685],{"class":1580}," Math",[50,1687,820],{"class":819},[50,1689,1690],{"class":1504},"min",[50,1692,827],{"class":1589},[50,1694,1695],{"class":1597},"perPageInt",[50,1697,871],{"class":819},[50,1699,1700],{"class":1597}," limit",[50,1702,838],{"class":1589},[50,1704,1706],{"class":52,"line":1705},26,[50,1707,138],{"emptyLinePlaceholder":137},[50,1709,1711,1713,1716,1718,1721,1724,1727,1730,1732,1735],{"class":52,"line":1710},27,[50,1712,1567],{"class":1349},[50,1714,1715],{"class":1570}," skip",[50,1717,1574],{"class":812},[50,1719,1720],{"class":1589}," (",[50,1722,1723],{"class":1597},"pageInt",[50,1725,1726],{"class":812}," -",[50,1728,1729],{"class":654}," 1",[50,1731,1613],{"class":1589},[50,1733,1734],{"class":812},"*",[50,1736,1737],{"class":1597}," perPageInt\n",[50,1739,1741],{"class":52,"line":1740},28,[50,1742,138],{"emptyLinePlaceholder":137},[50,1744,1746,1749],{"class":52,"line":1745},29,[50,1747,1748],{"class":795},"  return",[50,1750,1357],{"class":819},[50,1752,1754,1758,1760,1762],{"class":52,"line":1753},30,[50,1755,1757],{"class":1756},"sTQd7","    perPage",[50,1759,1241],{"class":819},[50,1761,1627],{"class":1597},[50,1763,1266],{"class":819},[50,1765,1767,1770,1772,1774],{"class":52,"line":1766},31,[50,1768,1769],{"class":1756},"    page",[50,1771,1241],{"class":819},[50,1773,1571],{"class":1597},[50,1775,1266],{"class":819},[50,1777,1779,1782],{"class":52,"line":1778},32,[50,1780,1781],{"class":1597},"    skip",[50,1783,1266],{"class":819},[50,1785,1787],{"class":52,"line":1786},33,[50,1788,1789],{"class":819},"  }\n",[50,1791,1793],{"class":52,"line":1792},34,[50,1794,1330],{"class":819},[50,1796,1798],{"class":52,"line":1797},35,[50,1799,138],{"emptyLinePlaceholder":137},[50,1801,1803,1805,1807,1810,1812,1814],{"class":52,"line":1802},36,[50,1804,1498],{"class":795},[50,1806,1501],{"class":1349},[50,1808,1809],{"class":1504}," buildResponsePagination",[50,1811,1412],{"class":819},[50,1813,1415],{"class":1353},[50,1815,1816],{"class":819},">(\n",[50,1818,1820,1822,1824,1826,1828],{"class":52,"line":1819},37,[50,1821,1425],{"class":1514},[50,1823,1241],{"class":88},[50,1825,1430],{"class":1353},[50,1827,1433],{"class":799},[50,1829,1266],{"class":819},[50,1831,1833,1835,1837,1839],{"class":52,"line":1832},38,[50,1834,1377],{"class":1514},[50,1836,1241],{"class":88},[50,1838,1369],{"class":1368},[50,1840,1266],{"class":819},[50,1842,1844,1846,1848,1850],{"class":52,"line":1843},39,[50,1845,1363],{"class":1514},[50,1847,1241],{"class":88},[50,1849,1369],{"class":1368},[50,1851,1266],{"class":819},[50,1853,1855,1858,1860],{"class":52,"line":1854},40,[50,1856,1857],{"class":1514},"  totalCount",[50,1859,1241],{"class":88},[50,1861,1543],{"class":1368},[50,1863,1865,1867,1869,1871,1873,1875,1877],{"class":52,"line":1864},41,[50,1866,1549],{"class":819},[50,1868,1241],{"class":88},[50,1870,1409],{"class":1353},[50,1872,1412],{"class":819},[50,1874,1415],{"class":1353},[50,1876,1418],{"class":819},[50,1878,1357],{"class":819},[50,1880,1882,1884,1887,1889],{"class":52,"line":1881},42,[50,1883,1567],{"class":1349},[50,1885,1886],{"class":1570}," currentPage",[50,1888,1574],{"class":812},[50,1890,1891],{"class":1597}," page\n",[50,1893,1895,1897,1900,1902,1904,1906,1909,1911,1914,1917,1920],{"class":52,"line":1894},43,[50,1896,1567],{"class":1349},[50,1898,1899],{"class":1570}," totalPages",[50,1901,1574],{"class":812},[50,1903,1685],{"class":1580},[50,1905,820],{"class":819},[50,1907,1908],{"class":1504},"ceil",[50,1910,827],{"class":1589},[50,1912,1913],{"class":1597},"totalCount",[50,1915,1916],{"class":812}," /",[50,1918,1919],{"class":1597}," perPage",[50,1921,838],{"class":1589},[50,1923,1925],{"class":52,"line":1924},44,[50,1926,138],{"emptyLinePlaceholder":137},[50,1928,1930,1932,1935,1937,1939,1942],{"class":52,"line":1929},45,[50,1931,1567],{"class":1349},[50,1933,1934],{"class":1570}," hasNextPage",[50,1936,1574],{"class":812},[50,1938,1886],{"class":1597},[50,1940,1941],{"class":812}," \u003C",[50,1943,1944],{"class":1597}," totalPages\n",[50,1946,1948,1950,1953,1955,1957,1960],{"class":52,"line":1947},46,[50,1949,1567],{"class":1349},[50,1951,1952],{"class":1570}," hasPrevPage",[50,1954,1574],{"class":812},[50,1956,1886],{"class":1597},[50,1958,1959],{"class":812}," >",[50,1961,1618],{"class":654},[50,1963,1965],{"class":52,"line":1964},47,[50,1966,138],{"emptyLinePlaceholder":137},[50,1968,1970,1972,1975,1977,1979,1982,1984,1987,1989,1992],{"class":52,"line":1969},48,[50,1971,1567],{"class":1349},[50,1973,1974],{"class":1570}," nextPage",[50,1976,1574],{"class":812},[50,1978,1934],{"class":1597},[50,1980,1981],{"class":1454}," ?",[50,1983,1886],{"class":1597},[50,1985,1986],{"class":812}," +",[50,1988,1729],{"class":654},[50,1990,1991],{"class":1454}," :",[50,1993,1995],{"class":1994},"scCEF"," undefined\n",[50,1997,1999,2001,2004,2006,2008,2010,2012,2014,2016,2018],{"class":52,"line":1998},49,[50,2000,1567],{"class":1349},[50,2002,2003],{"class":1570}," prevPage",[50,2005,1574],{"class":812},[50,2007,1952],{"class":1597},[50,2009,1981],{"class":1454},[50,2011,1886],{"class":1597},[50,2013,1726],{"class":812},[50,2015,1729],{"class":654},[50,2017,1991],{"class":1454},[50,2019,1995],{"class":1994},[50,2021,2023],{"class":52,"line":2022},50,[50,2024,138],{"emptyLinePlaceholder":137},[50,2026,2028,2030],{"class":52,"line":2027},51,[50,2029,1748],{"class":795},[50,2031,1357],{"class":819},[50,2033,2035,2038],{"class":52,"line":2034},52,[50,2036,2037],{"class":1597},"    data",[50,2039,1266],{"class":819},[50,2041,2043,2046],{"class":52,"line":2042},53,[50,2044,2045],{"class":1597},"    currentPage",[50,2047,1266],{"class":819},[50,2049,2051,2054],{"class":52,"line":2050},54,[50,2052,2053],{"class":1597},"    nextPage",[50,2055,1266],{"class":819},[50,2057,2059,2062],{"class":52,"line":2058},55,[50,2060,2061],{"class":1597},"    prevPage",[50,2063,1266],{"class":819},[50,2065,2067,2070,2072,2075],{"class":52,"line":2066},56,[50,2068,2069],{"class":1756},"    count",[50,2071,1241],{"class":819},[50,2073,2074],{"class":1597}," totalCount",[50,2076,1266],{"class":819},[50,2078,2080],{"class":52,"line":2079},57,[50,2081,1789],{"class":819},[50,2083,2085],{"class":52,"line":2084},58,[50,2086,1330],{"class":819},[35,2088,2090],{"id":2089},"_2-usage","2. Usage",[40,2092,2094],{"className":1340,"code":2093,"language":1342,"meta":45,"style":45},"const { page, perPage } = req.query\n\nconst {\n    perPage: perPageInt,\n    page: pageInt,\n    skip,\n} = buildPaginationParam(page as string, perPage as string, 10)\n\n// Find all post\nconst [posts, count] = await Promise.all([\n    await Post.find({})\n        .skip(skip)\n        .limit(perPageInt)\n        .lean(),\n    await Post.countDocuments(),\n])\n\nconst output = buildResponsePagination(\n    posts,\n    pageInt,\n    perPageInt,\n    count\n)\n\nres.send({\n    message: SuccessMessages.GetSuccess,\n    data: output.data,\n    currentPage: output.currentPage,\n    nextPage: output.nextPage || null,\n    prevPage: output.prevPage || null,\n    count: count,\n})\n",[47,2095,2096,2124,2128,2134,2144,2154,2160,2193,2197,2202,2236,2256,2270,2283,2295,2310,2314,2318,2331,2338,2345,2352,2357,2361,2365,2379,2396,2410,2424,2444,2462,2472],{"__ignoreMap":45},[50,2097,2098,2101,2104,2107,2109,2111,2114,2116,2119,2121],{"class":52,"line":53},[50,2099,2100],{"class":1349},"const",[50,2102,2103],{"class":819}," {",[50,2105,2106],{"class":1570}," page",[50,2108,871],{"class":819},[50,2110,1919],{"class":1570},[50,2112,2113],{"class":819}," }",[50,2115,1574],{"class":812},[50,2117,2118],{"class":1580}," req",[50,2120,820],{"class":819},[50,2122,2123],{"class":1597},"query\n",[50,2125,2126],{"class":52,"line":124},[50,2127,138],{"emptyLinePlaceholder":137},[50,2129,2130,2132],{"class":52,"line":134},[50,2131,2100],{"class":1349},[50,2133,1357],{"class":819},[50,2135,2136,2138,2140,2142],{"class":52,"line":141},[50,2137,1757],{"class":1362},[50,2139,1241],{"class":819},[50,2141,1627],{"class":1570},[50,2143,1266],{"class":819},[50,2145,2146,2148,2150,2152],{"class":52,"line":147},[50,2147,1769],{"class":1362},[50,2149,1241],{"class":819},[50,2151,1571],{"class":1570},[50,2153,1266],{"class":819},[50,2155,2156,2158],{"class":52,"line":214},[50,2157,1781],{"class":1570},[50,2159,1266],{"class":819},[50,2161,2162,2165,2167,2169,2171,2173,2176,2178,2180,2182,2184,2186,2188,2191],{"class":52,"line":219},[50,2163,2164],{"class":819},"}",[50,2166,1574],{"class":812},[50,2168,1505],{"class":1504},[50,2170,827],{"class":799},[50,2172,1598],{"class":1597},[50,2174,2175],{"class":795}," as",[50,2177,1519],{"class":1368},[50,2179,871],{"class":819},[50,2181,1919],{"class":1597},[50,2183,2175],{"class":795},[50,2185,1519],{"class":1368},[50,2187,871],{"class":819},[50,2189,2190],{"class":654}," 10",[50,2192,838],{"class":799},[50,2194,2195],{"class":52,"line":225},[50,2196,138],{"emptyLinePlaceholder":137},[50,2198,2199],{"class":52,"line":541},[50,2200,2201],{"class":120},"// Find all post\n",[50,2203,2204,2206,2209,2212,2214,2217,2220,2222,2225,2228,2230,2233],{"class":52,"line":551},[50,2205,2100],{"class":1349},[50,2207,2208],{"class":819}," [",[50,2210,2211],{"class":1570},"posts",[50,2213,871],{"class":819},[50,2215,2216],{"class":1570}," count",[50,2218,2219],{"class":819},"]",[50,2221,1574],{"class":812},[50,2223,2224],{"class":795}," await",[50,2226,2227],{"class":1368}," Promise",[50,2229,820],{"class":819},[50,2231,2232],{"class":1504},"all",[50,2234,2235],{"class":799},"([\n",[50,2237,2238,2241,2244,2246,2249,2251,2254],{"class":52,"line":556},[50,2239,2240],{"class":795},"    await",[50,2242,2243],{"class":1580}," Post",[50,2245,820],{"class":819},[50,2247,2248],{"class":1504},"find",[50,2250,827],{"class":799},[50,2252,2253],{"class":819},"{}",[50,2255,838],{"class":799},[50,2257,2258,2261,2264,2266,2268],{"class":52,"line":562},[50,2259,2260],{"class":819},"        .",[50,2262,2263],{"class":1504},"skip",[50,2265,827],{"class":799},[50,2267,2263],{"class":1597},[50,2269,838],{"class":799},[50,2271,2272,2274,2277,2279,2281],{"class":52,"line":575},[50,2273,2260],{"class":819},[50,2275,2276],{"class":1504},"limit",[50,2278,827],{"class":799},[50,2280,1695],{"class":1597},[50,2282,838],{"class":799},[50,2284,2285,2287,2290,2293],{"class":52,"line":580},[50,2286,2260],{"class":819},[50,2288,2289],{"class":1504},"lean",[50,2291,2292],{"class":799},"()",[50,2294,1266],{"class":819},[50,2296,2297,2299,2301,2303,2306,2308],{"class":52,"line":586},[50,2298,2240],{"class":795},[50,2300,2243],{"class":1580},[50,2302,820],{"class":819},[50,2304,2305],{"class":1504},"countDocuments",[50,2307,2292],{"class":799},[50,2309,1266],{"class":819},[50,2311,2312],{"class":52,"line":1511},[50,2313,918],{"class":799},[50,2315,2316],{"class":52,"line":1524},[50,2317,138],{"emptyLinePlaceholder":137},[50,2319,2320,2322,2325,2327,2329],{"class":52,"line":1535},[50,2321,2100],{"class":1349},[50,2323,2324],{"class":1570}," output",[50,2326,1574],{"class":812},[50,2328,1809],{"class":1504},[50,2330,1508],{"class":799},[50,2332,2333,2336],{"class":52,"line":1546},[50,2334,2335],{"class":1597},"    posts",[50,2337,1266],{"class":819},[50,2339,2340,2343],{"class":52,"line":1558},[50,2341,2342],{"class":1597},"    pageInt",[50,2344,1266],{"class":819},[50,2346,2347,2350],{"class":52,"line":1564},[50,2348,2349],{"class":1597},"    perPageInt",[50,2351,1266],{"class":819},[50,2353,2354],{"class":52,"line":1621},[50,2355,2356],{"class":1597},"    count\n",[50,2358,2359],{"class":52,"line":1666},[50,2360,838],{"class":799},[50,2362,2363],{"class":52,"line":1671},[50,2364,138],{"emptyLinePlaceholder":137},[50,2366,2367,2370,2372,2375,2377],{"class":52,"line":1677},[50,2368,2369],{"class":1580},"res",[50,2371,820],{"class":819},[50,2373,2374],{"class":1504},"send",[50,2376,827],{"class":799},[50,2378,1226],{"class":819},[50,2380,2381,2384,2386,2389,2391,2394],{"class":52,"line":1705},[50,2382,2383],{"class":1756},"    message",[50,2385,1241],{"class":819},[50,2387,2388],{"class":1580}," SuccessMessages",[50,2390,820],{"class":819},[50,2392,2393],{"class":1597},"GetSuccess",[50,2395,1266],{"class":819},[50,2397,2398,2400,2402,2404,2406,2408],{"class":52,"line":1710},[50,2399,2037],{"class":1756},[50,2401,1241],{"class":819},[50,2403,2324],{"class":1580},[50,2405,820],{"class":819},[50,2407,1236],{"class":1597},[50,2409,1266],{"class":819},[50,2411,2412,2414,2416,2418,2420,2422],{"class":52,"line":1740},[50,2413,2045],{"class":1756},[50,2415,1241],{"class":819},[50,2417,2324],{"class":1580},[50,2419,820],{"class":819},[50,2421,1251],{"class":1597},[50,2423,1266],{"class":819},[50,2425,2426,2428,2430,2432,2434,2436,2439,2442],{"class":52,"line":1745},[50,2427,2053],{"class":1756},[50,2429,1241],{"class":819},[50,2431,2324],{"class":1580},[50,2433,820],{"class":819},[50,2435,1273],{"class":1597},[50,2437,2438],{"class":812}," ||",[50,2440,2441],{"class":1994}," null",[50,2443,1266],{"class":819},[50,2445,2446,2448,2450,2452,2454,2456,2458,2460],{"class":52,"line":1753},[50,2447,2061],{"class":1756},[50,2449,1241],{"class":819},[50,2451,2324],{"class":1580},[50,2453,820],{"class":819},[50,2455,1293],{"class":1597},[50,2457,2438],{"class":812},[50,2459,2441],{"class":1994},[50,2461,1266],{"class":819},[50,2463,2464,2466,2468,2470],{"class":52,"line":1766},[50,2465,2069],{"class":1756},[50,2467,1241],{"class":819},[50,2469,2216],{"class":1597},[50,2471,1266],{"class":819},[50,2473,2474,2476],{"class":52,"line":1778},[50,2475,2164],{"class":819},[50,2477,838],{"class":799},[1137,2479,2480],{},[1140,2481,2482],{},"ที่ต้องกำหนด Limit ไว้ด้วย เนื่องจากป้องกันการ Dump ข้อมูลจาก database และลดการทำงานของ Server ได้",[1153,2484,2485],{},"html pre.shiki code .stlKB, html code.shiki .stlKB{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sObbn, html code.shiki .sObbn{--shiki-light:#39ADB5;--shiki-default:#E06C75;--shiki-dark:#79B8FF}html pre.shiki code .sVeMc, html code.shiki .sVeMc{--shiki-light:#9C3EDA;--shiki-default:#E06C75;--shiki-dark:#79B8FF}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sOHk9, html code.shiki .sOHk9{--shiki-light:#9C3EDA;--shiki-default:#C678DD;--shiki-dark:#F97583}html pre.shiki code .sGnaQ, html code.shiki .sGnaQ{--shiki-light:#E2931D;--shiki-default:#E5C07B;--shiki-dark:#B392F0}html pre.shiki code .slt33, html code.shiki .slt33{--shiki-light:#E53935;--shiki-default:#E06C75;--shiki-dark:#FFAB70}html pre.shiki code .sbGrh, html code.shiki .sbGrh{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F97583}html pre.shiki code .s6Wr0, html code.shiki .s6Wr0{--shiki-light:#E2931D;--shiki-default:#E5C07B;--shiki-dark:#79B8FF}html pre.shiki code .sZDfs, html code.shiki .sZDfs{--shiki-light:#90A4AE;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .s_AEr, html code.shiki .s_AEr{--shiki-light:#39ADB5;--shiki-default:#C678DD;--shiki-dark:#F97583}html pre.shiki code .s36IK, html code.shiki .s36IK{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#C678DD;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .suMxZ, html code.shiki .suMxZ{--shiki-light:#6182B8;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .stkEM, html code.shiki .stkEM{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E06C75;--shiki-default-font-style:italic;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .sDKbk, html code.shiki .sDKbk{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sUzmo, html code.shiki .sUzmo{--shiki-light:#90A4AE;--shiki-default:#E5C07B;--shiki-dark:#79B8FF}html pre.shiki code .sMTEB, html code.shiki .sMTEB{--shiki-light:#39ADB5;--shiki-default:#56B6C2;--shiki-dark:#F97583}html pre.shiki code .sU9mH, html code.shiki .sU9mH{--shiki-light:#90A4AE;--shiki-default:#E5C07B;--shiki-dark:#E1E4E8}html pre.shiki code .sbHgf, html code.shiki .sbHgf{--shiki-light:#E53935;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sLHrO, html code.shiki .sLHrO{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#E1E4E8}html pre.shiki code .snOyU, html code.shiki .snOyU{--shiki-light:#F76D47;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .sTQd7, html code.shiki .sTQd7{--shiki-light:#E53935;--shiki-default:#E06C75;--shiki-dark:#E1E4E8}html pre.shiki code .scCEF, html code.shiki .scCEF{--shiki-light:#39ADB5;--shiki-default:#D19A66;--shiki-dark:#79B8FF}",{"title":45,"searchDepth":124,"depth":124,"links":2487},[2488,2489],{"id":1336,"depth":134,"text":1337},{"id":2089,"depth":134,"text":2090},"2024-01-20T00:00:00.000Z","Code ตัวอย่างคือการใช้งานใน Express + Typescript + Mongoose",{},"Express Simple Paginate","/blogs/2024-01-20-simple-paginate",{"title":1202,"description":2491},{"loc":2494},"blogs/2024-01-20-simple-paginate",[1195],"yfJFDG2gdwKeg2oQvKQnBwJNymHvcE1__IA-XnBCTVc",{"id":2501,"title":2502,"body":2503,"date":2592,"description":2510,"draft":1185,"extension":1186,"meta":2593,"navigation":137,"next":1188,"ogTitle":2594,"path":2595,"pin":1185,"prev":1188,"recommends":2596,"seo":2597,"sitemap":2598,"stem":2599,"tags":2600,"__hash__":2601},"content/blogs/2024-06-06-openvpn-exclude-network.md","ตั้งค่าให้สามารถเชื่อมต่อ Local Network ได้ ตอนที่เชื่อม openvpn",{"type":7,"value":2504,"toc":2588},[2505,2508,2511,2515,2541,2544,2579,2582,2585],[15,2506,2507],{},"วิธีการแก้ไขปัญหาเชื่อมต่อ Internal Network ไม่ได้เมื่อมีการต่อ OPENVPN อยู่",[15,2509,2510],{},"แก้ไขไฟล์ openvpn config หากมีการ import เข้าไปใน openvpn gui แล้วสามารถค้นหาไฟล์การตั้งค่าได้ที่",[35,2512,2514],{"id":2513},"สำหรับ-macos","สำหรับ macos",[40,2516,2519],{"className":42,"code":2517,"filename":2518,"language":44,"meta":45,"style":45},"/Users/\u003Cyour_username_here>/Library/Application\\ Support/OpenVPN\\ Connect/profiles\n","⌘",[47,2520,2521],{"__ignoreMap":45},[50,2522,2523,2526,2529,2533,2536,2538],{"class":52,"line":53},[50,2524,2525],{"class":56},"/Users/",[50,2527,2528],{"class":799},"\u003Cyour_username_here>/Library/Application",[50,2530,2532],{"class":2531},"sicAX","\\ ",[50,2534,2535],{"class":799},"Support/OpenVPN",[50,2537,2532],{"class":2531},[50,2539,2540],{"class":799},"Connect/profiles\n",[15,2542,2543],{},"เพิ่ม config",[40,2545,2547],{"className":42,"code":2546,"language":44,"meta":45,"style":45},"# Exclude my home network routes\nroute 192.168.1.0 255.255.255.0 net_gateway\nroute 192.168.2.0 255.255.255.0 net_gateway\n",[47,2548,2549,2554,2568],{"__ignoreMap":45},[50,2550,2551],{"class":52,"line":53},[50,2552,2553],{"class":120},"# Exclude my home network routes\n",[50,2555,2556,2559,2562,2565],{"class":52,"line":124},[50,2557,2558],{"class":56},"route",[50,2560,2561],{"class":654}," 192.168.1.0",[50,2563,2564],{"class":654}," 255.255.255.0",[50,2566,2567],{"class":60}," net_gateway\n",[50,2569,2570,2572,2575,2577],{"class":52,"line":134},[50,2571,2558],{"class":56},[50,2573,2574],{"class":654}," 192.168.2.0",[50,2576,2564],{"class":654},[50,2578,2567],{"class":60},[35,2580,2581],{"id":2581},"ทดสอบ",[15,2583,2584],{},"ทำการเชื่อมต่อ openvpn ใหม่ จะพบว่าสามารถเชื่อมต่อ local network ได้แล้ว หลักการง่าย ๆ ก็คือการทำให้ request ที่ไปยัง destination ดังกล่าวไม่ถูกส่งเข้าไปยัง openvpn นั้นเอง",[1153,2586,2587],{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sZDfs, html code.shiki .sZDfs{--shiki-light:#90A4AE;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sicAX, html code.shiki .sicAX{--shiki-light:#90A4AE;--shiki-default:#56B6C2;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sDKbk, html code.shiki .sDKbk{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .snOyU, html code.shiki .snOyU{--shiki-light:#F76D47;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}",{"title":45,"searchDepth":124,"depth":124,"links":2589},[2590,2591],{"id":2513,"depth":134,"text":2514},{"id":2581,"depth":134,"text":2581},"2024-06-06T00:00:00.000Z",{},"Openvpn Split Tunnel","/blogs/2024-06-06-openvpn-exclude-network",[],{"title":2502,"description":2510},{"loc":2595},"blogs/2024-06-06-openvpn-exclude-network",[1195],"iwqqkGrIWNt77I1BcOLmGkvarDO_Hsc1kuKug1s02O4",{"id":2603,"title":2604,"body":2605,"date":2760,"description":2616,"draft":1185,"extension":1186,"meta":2761,"navigation":137,"next":1188,"ogTitle":2762,"path":2763,"pin":1185,"prev":1188,"recommends":2764,"seo":2765,"sitemap":2766,"stem":2767,"tags":2768,"__hash__":2769},"content/blogs/2025-04-14-dotenv-leak-lab.md","วิธีการลบ .env file ออกจาก git แบบถูกวิธี",{"type":7,"value":2606,"toc":2754},[2607,2614,2617,2620,2628,2643,2649,2657,2661,2687,2693,2703,2707,2712,2733,2739,2746,2751],[15,2608,2609],{},[2610,2611],"img",{"alt":2612,"src":2613},".env leak","/images/2025-04-14-dotenv-leak-lab/image-0.png",[15,2615,2616],{},"สมมติว่าเราเผลอ commit ไฟล์ .env ที่มี API key ไปแล้ว และ push ขึ้น GitHub เราต้องรีบลบมันออกทันที เพราะข้อมูลอาจถูกนำไปใช้ได้",[15,2618,2619],{},"สำหรับวิธีการลบ .env file แบบถูกวิธีให้ทำแบบนี้นะครับ พร้อมแล้วไปลุยกันเลยย",[35,2621,2623,2624,2627],{"id":2622},"_1-นำ-env-file-ไปใส่ใน-gitignore-ก่อน","1. นำ .env file ไปใส่ใน ",[47,2625,2626],{},".gitignore"," ก่อน",[40,2629,2631],{"className":42,"code":2630,"filename":2626,"language":44,"meta":45,"style":45},".env\n.env.*\n",[47,2632,2633,2638],{"__ignoreMap":45},[50,2634,2635],{"class":52,"line":53},[50,2636,2637],{"class":56},".env\n",[50,2639,2640],{"class":52,"line":124},[50,2641,2642],{"class":56},".env.*\n",[2644,2645,2646],"blockquote",{},[15,2647,2648],{},".env.:* เช่น .env.production .env.local .env.development",[15,2650,2651,2652,2656],{},"แนะนำให้ลองใช้ ",[23,2653,2654],{"href":2654,"rel":2655},"https://www.toptal.com/developers/gitignore",[27]," ผมใช้เป็นประจำครับ เป็นเครื่องมือในการช่วยสร้าง gitignore ไฟล์ชั้นดีเลย",[35,2658,2660],{"id":2659},"_2-ลบ-env-file-ออกจาก-git-แบบในทุก-ๆ-commits","2. ลบ .env file ออกจาก git แบบในทุก ๆ commits",[40,2662,2664],{"className":42,"code":2663,"language":44,"meta":45,"style":45},"git filter-branch --index-filter \"git rm -rf --cached --ignore-unmatch .env\" HEAD\n",[47,2665,2666],{"__ignoreMap":45},[50,2667,2668,2671,2674,2677,2679,2682,2684],{"class":52,"line":53},[50,2669,2670],{"class":56},"git",[50,2672,2673],{"class":60}," filter-branch",[50,2675,2676],{"class":81}," --index-filter",[50,2678,1258],{"class":390},[50,2680,2681],{"class":60},"git rm -rf --cached --ignore-unmatch .env",[50,2683,830],{"class":390},[50,2685,2686],{"class":60}," HEAD\n",[15,2688,2689],{},[2610,2690],{"alt":2691,"src":2692},"Output","/images/2025-04-14-dotenv-leak-lab/image-1.png",[15,2694,2695,2696,665,2699,2702],{},"ถ้าลบออกเฉย ๆ ด้วยคำสั่ง ",[47,2697,2698],{},"git rm -r --cached .env",[47,2700,2701],{},"rm .env"," แล้ว commit ไปใหม่ สิ่งที่จะเกิดขึ้นคือไฟล์จะหายไปแค่ commit ล่าสุดเท่านั้น แต่ถ้าไปดูใน commit history ไฟล์ดังกล่าวจะยังอยู่ครับ",[35,2704,2706],{"id":2705},"_3-push-git-ไฟล์อันใหม่ขึ้นไปด้วยคำสั่ง","3. push .git ไฟล์อันใหม่ขึ้นไปด้วยคำสั่ง",[2644,2708,2709],{},[15,2710,2711],{},"คำเตือน: คำสั่งนี้จะเปลี่ยนแปลงประวัติทั้งหมดของ Project ควรแน่ใจว่าไม่มีใครใช้งาน repository นี้อยู่ก่อนจะ push ด้วย --force",[40,2713,2715],{"className":42,"code":2714,"language":44,"meta":45,"style":45},"git push origin main --force\n",[47,2716,2717],{"__ignoreMap":45},[50,2718,2719,2721,2724,2727,2730],{"class":52,"line":53},[50,2720,2670],{"class":56},[50,2722,2723],{"class":60}," push",[50,2725,2726],{"class":60}," origin",[50,2728,2729],{"class":60}," main",[50,2731,2732],{"class":81}," --force\n",[15,2734,2735],{},[2610,2736],{"alt":2737,"src":2738},"Result","/images/2025-04-14-dotenv-leak-lab/image-2.png",[15,2740,2741,2742,2745],{},"เพียงแค่นี้ ",[47,2743,2744],{},".env"," file ก็จะถูกลบออกไปจาก Git ของเราเรียบร้อยแล้วครับ",[2644,2747,2748],{},[15,2749,2750],{},"Tip: ถ้าเคย push .env ขึ้น GitHub, Gitlab, Gitea หรือ Git Platform อื่น ๆ แล้ว อย่าลืมรีเซ็ต API key หรือ Token ที่อยู่ในไฟล์ด้วยนะครับ เพื่อความปลอดภัยสูงสุด",[1153,2752,2753],{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}",{"title":45,"searchDepth":124,"depth":124,"links":2755},[2756,2758,2759],{"id":2622,"depth":134,"text":2757},"1. นำ .env file ไปใส่ใน .gitignore ก่อน",{"id":2659,"depth":134,"text":2660},{"id":2705,"depth":134,"text":2706},"2025-04-14T00:00:00.000Z",{},"How To Remove .env From Git","/blogs/2025-04-14-dotenv-leak-lab",[],{"title":2604,"description":2616},{"loc":2763},"blogs/2025-04-14-dotenv-leak-lab",[1195],"_rppCmKhXtTHagenWhqCVs8oZJwTQsHy-HkKf2Q3jps",{"id":2771,"title":2772,"body":2773,"date":3304,"description":3305,"draft":1185,"extension":1186,"meta":3306,"navigation":137,"next":1188,"ogTitle":3307,"path":3308,"pin":1185,"prev":1188,"recommends":1188,"seo":3309,"sitemap":3310,"stem":3311,"tags":3312,"__hash__":3313},"content/blogs/2025-04-25-setup-nuxt-medium-zoom.md","วิธีการติดตั้งและใช้งาน Medium Zoom ใน Nuxt 3",{"type":7,"value":2774,"toc":3295},[2775,2780,2783,2786,2790,2832,2836,2845,2849,3072,3076,3084,3176,3183,3276,3279,3283,3292],[15,2776,2777],{},[2610,2778],{"alt":45,"src":2779},"/images/2025-04-25-setup-nuxt-medium-zoom/medium-zoom.png",[15,2781,2782],{},"วันนี้จะมาแนะนำวิธีการติดตั้ง Library นึงครับซึ่งจะทำให้รูปภายในเว็บไซต์ของเรามีลูกเล่นเหมือนกับรูปที่อยู่ภายในเว็บไซต์ Medium.com ครับ อยากรู้ว่าเป็นยังไงลองคลิกที่รูปด้านบนได้เลยครับ 👆",[10,2784,2785],{"id":2785},"วิธีการติดตั้ง",[35,2787,2789],{"id":2788},"_1-ติดตั้ง-library-ดังกล่าว","1. ติดตั้ง Library ดังกล่าว",[40,2791,2793],{"className":1340,"code":2792,"language":1342,"meta":45,"style":45},"npm install medium-zoom\n# หรือ\nyarn add medium-zoom\n",[47,2794,2795,2811,2819],{"__ignoreMap":45},[50,2796,2797,2800,2802,2805,2808],{"class":52,"line":53},[50,2798,2799],{"class":1597},"npm",[50,2801,61],{"class":1597},[50,2803,2804],{"class":1597}," medium",[50,2806,2807],{"class":812},"-",[50,2809,2810],{"class":1597},"zoom\n",[50,2812,2813,2816],{"class":52,"line":124},[50,2814,2815],{"class":799},"# ",[50,2817,2818],{"class":1597},"หรือ\n",[50,2820,2821,2824,2826,2828,2830],{"class":52,"line":134},[50,2822,2823],{"class":1597},"yarn",[50,2825,492],{"class":1597},[50,2827,2804],{"class":1597},[50,2829,2807],{"class":812},[50,2831,2810],{"class":1597},[35,2833,2835],{"id":2834},"_2-สร้าง-folder-และ-file-plugins","2. สร้าง Folder และ File Plugins",[40,2837,2839],{"className":42,"code":2838,"language":44,"meta":45,"style":45},"# เติม .client.ts เพื่อกำหนดว่า plugins นี้เป็นของฝั่ง client อย่างเดียวนะครับ\n",[47,2840,2841],{"__ignoreMap":45},[50,2842,2843],{"class":52,"line":53},[50,2844,2838],{"class":120},[35,2846,2848],{"id":2847},"_3-นำ-source-code-ไปวางภายในไฟล์ดังกล่าวได้เลยครับ","3. นำ Source Code ไปวางภายในไฟล์ดังกล่าวได้เลยครับ",[40,2850,2854],{"className":2851,"code":2852,"language":2853,"meta":45,"style":45},"language-typescript shiki shiki-themes material-theme-lighter one-dark-pro github-dark","import { defineNuxtPlugin } from '#app'\nimport mediumZoom, { Zoom } from 'medium-zoom'\n\nexport default defineNuxtPlugin((nuxtApp) => {\n  const selector = '.image-zoomable'\n  const zoom: Zoom = mediumZoom(selector, {})\n\n  nuxtApp.hook('page:finish', () => {\n    zoom.detach(selector).attach(selector)\n  })\n\n  nuxtApp.provide('mediumZoom', zoom)\n})\n","typescript",[47,2855,2856,2877,2902,2906,2929,2945,2972,2976,3004,3031,3038,3042,3066],{"__ignoreMap":45},[50,2857,2858,2860,2862,2865,2867,2870,2872,2875],{"class":52,"line":53},[50,2859,796],{"class":795},[50,2861,2103],{"class":819},[50,2863,2864],{"class":1597}," defineNuxtPlugin",[50,2866,2113],{"class":819},[50,2868,2869],{"class":795}," from",[50,2871,391],{"class":390},[50,2873,2874],{"class":60},"#app",[50,2876,397],{"class":390},[50,2878,2879,2881,2884,2886,2888,2891,2893,2895,2897,2900],{"class":52,"line":124},[50,2880,796],{"class":795},[50,2882,2883],{"class":1597}," mediumZoom",[50,2885,871],{"class":819},[50,2887,2103],{"class":819},[50,2889,2890],{"class":1597}," Zoom",[50,2892,2113],{"class":819},[50,2894,2869],{"class":795},[50,2896,391],{"class":390},[50,2898,2899],{"class":60},"medium-zoom",[50,2901,397],{"class":390},[50,2903,2904],{"class":52,"line":134},[50,2905,138],{"emptyLinePlaceholder":137},[50,2907,2908,2910,2913,2915,2917,2919,2922,2924,2927],{"class":52,"line":141},[50,2909,1498],{"class":795},[50,2911,2912],{"class":795}," default",[50,2914,2864],{"class":1504},[50,2916,827],{"class":799},[50,2918,827],{"class":819},[50,2920,2921],{"class":1514},"nuxtApp",[50,2923,1549],{"class":819},[50,2925,2926],{"class":1349}," =>",[50,2928,1357],{"class":819},[50,2930,2931,2933,2936,2938,2940,2943],{"class":52,"line":147},[50,2932,1567],{"class":1349},[50,2934,2935],{"class":1570}," selector",[50,2937,1574],{"class":812},[50,2939,391],{"class":390},[50,2941,2942],{"class":60},".image-zoomable",[50,2944,397],{"class":390},[50,2946,2947,2949,2952,2954,2956,2958,2960,2962,2965,2967,2970],{"class":52,"line":214},[50,2948,1567],{"class":1349},[50,2950,2951],{"class":1570}," zoom",[50,2953,1241],{"class":88},[50,2955,2890],{"class":1353},[50,2957,1574],{"class":812},[50,2959,2883],{"class":1504},[50,2961,827],{"class":1589},[50,2963,2964],{"class":1597},"selector",[50,2966,871],{"class":819},[50,2968,2969],{"class":819}," {}",[50,2971,838],{"class":1589},[50,2973,2974],{"class":52,"line":219},[50,2975,138],{"emptyLinePlaceholder":137},[50,2977,2978,2981,2983,2986,2988,2990,2993,2995,2997,3000,3002],{"class":52,"line":225},[50,2979,2980],{"class":1580},"  nuxtApp",[50,2982,820],{"class":819},[50,2984,2985],{"class":1504},"hook",[50,2987,827],{"class":1589},[50,2989,989],{"class":390},[50,2991,2992],{"class":60},"page:finish",[50,2994,989],{"class":390},[50,2996,871],{"class":819},[50,2998,2999],{"class":819}," ()",[50,3001,2926],{"class":1349},[50,3003,1357],{"class":819},[50,3005,3006,3009,3011,3014,3016,3018,3020,3022,3025,3027,3029],{"class":52,"line":541},[50,3007,3008],{"class":1580},"    zoom",[50,3010,820],{"class":819},[50,3012,3013],{"class":1504},"detach",[50,3015,827],{"class":1589},[50,3017,2964],{"class":1597},[50,3019,1549],{"class":1589},[50,3021,820],{"class":819},[50,3023,3024],{"class":1504},"attach",[50,3026,827],{"class":1589},[50,3028,2964],{"class":1597},[50,3030,838],{"class":1589},[50,3032,3033,3036],{"class":52,"line":551},[50,3034,3035],{"class":819},"  }",[50,3037,838],{"class":1589},[50,3039,3040],{"class":52,"line":556},[50,3041,138],{"emptyLinePlaceholder":137},[50,3043,3044,3046,3048,3051,3053,3055,3058,3060,3062,3064],{"class":52,"line":562},[50,3045,2980],{"class":1580},[50,3047,820],{"class":819},[50,3049,3050],{"class":1504},"provide",[50,3052,827],{"class":1589},[50,3054,989],{"class":390},[50,3056,3057],{"class":60},"mediumZoom",[50,3059,989],{"class":390},[50,3061,871],{"class":819},[50,3063,2951],{"class":1597},[50,3065,838],{"class":1589},[50,3067,3068,3070],{"class":52,"line":575},[50,3069,2164],{"class":819},[50,3071,838],{"class":799},[35,3073,3075],{"id":3074},"_4-วิธีการใช้งาน","4. วิธีการใช้งาน",[15,3077,3078],{},[18,3079,3080,3081],{},"ใช้กับ ",[47,3082,3083],{},"\u003Cimg />",[40,3085,3087],{"className":2851,"code":3086,"language":2853,"meta":45,"style":45},"\u003Cimg src=\"/images/logo.jpeg\" alt=\"logo\" class=\"image-zoomable\" />\n\n# เพิ่ม \"image-zoomable\" เข้าไปใน class ได้เลย\n",[47,3088,3089,3134,3138],{"__ignoreMap":45},[50,3090,3091,3093,3095,3098,3100,3102,3105,3107,3110,3112,3114,3117,3119,3122,3124,3126,3129,3131],{"class":52,"line":53},[50,3092,1412],{"class":812},[50,3094,2610],{"class":1597},[50,3096,3097],{"class":1597}," src",[50,3099,813],{"class":812},[50,3101,830],{"class":390},[50,3103,3104],{"class":60},"/images/logo.jpeg",[50,3106,830],{"class":390},[50,3108,3109],{"class":1597}," alt",[50,3111,813],{"class":812},[50,3113,830],{"class":390},[50,3115,3116],{"class":60},"logo",[50,3118,830],{"class":390},[50,3120,3121],{"class":1597}," class",[50,3123,813],{"class":812},[50,3125,830],{"class":390},[50,3127,3128],{"class":60},"image-zoomable",[50,3130,830],{"class":390},[50,3132,3133],{"class":812}," />\n",[50,3135,3136],{"class":52,"line":124},[50,3137,138],{"emptyLinePlaceholder":137},[50,3139,3140,3142,3145,3148,3151,3153,3155,3157,3160,3163,3166,3168,3171,3173],{"class":52,"line":134},[50,3141,2815],{"class":799},[50,3143,3144],{"class":1597},"เพิ",[50,3146,3147],{"class":799},"่",[50,3149,3150],{"class":1597},"ม",[50,3152,1258],{"class":390},[50,3154,3128],{"class":60},[50,3156,830],{"class":390},[50,3158,3159],{"class":1597}," เข",[50,3161,3162],{"class":799},"้",[50,3164,3165],{"class":1597},"าไปใน",[50,3167,3121],{"class":1349},[50,3169,3170],{"class":1353}," ได",[50,3172,3162],{"class":799},[50,3174,3175],{"class":1353},"เลย\n",[15,3177,3178],{},[18,3179,3080,3180],{},[47,3181,3182],{},"\u003Cnuxt-img />",[40,3184,3186],{"className":2851,"code":3185,"language":2853,"meta":45,"style":45},"\u003Cnuxt-img\n    src=\"/images/logo.jpeg\"\n    alt=\"logo\"\n    class=\"image-zoomable\"\n/>\n\n# ซึ่งเป็นการเติม class เช่นเดียวกันครับ\n",[47,3187,3188,3200,3213,3226,3239,3244,3248],{"__ignoreMap":45},[50,3189,3190,3192,3195,3197],{"class":52,"line":53},[50,3191,1412],{"class":812},[50,3193,3194],{"class":1597},"nuxt",[50,3196,2807],{"class":812},[50,3198,3199],{"class":1597},"img\n",[50,3201,3202,3205,3207,3209,3211],{"class":52,"line":124},[50,3203,3204],{"class":1597},"    src",[50,3206,813],{"class":812},[50,3208,830],{"class":390},[50,3210,3104],{"class":60},[50,3212,1325],{"class":390},[50,3214,3215,3218,3220,3222,3224],{"class":52,"line":134},[50,3216,3217],{"class":1597},"    alt",[50,3219,813],{"class":812},[50,3221,830],{"class":390},[50,3223,3116],{"class":60},[50,3225,1325],{"class":390},[50,3227,3228,3231,3233,3235,3237],{"class":52,"line":141},[50,3229,3230],{"class":1597},"    class",[50,3232,813],{"class":812},[50,3234,830],{"class":390},[50,3236,3128],{"class":60},[50,3238,1325],{"class":390},[50,3240,3241],{"class":52,"line":147},[50,3242,3243],{"class":812},"/>\n",[50,3245,3246],{"class":52,"line":214},[50,3247,138],{"emptyLinePlaceholder":137},[50,3249,3250,3252,3255,3257,3260,3263,3266,3268,3271,3273],{"class":52,"line":219},[50,3251,2815],{"class":799},[50,3253,3254],{"class":1597},"ซึ",[50,3256,3147],{"class":799},[50,3258,3259],{"class":1597},"งเป",[50,3261,3262],{"class":799},"็",[50,3264,3265],{"class":1597},"นการเติม",[50,3267,3121],{"class":1349},[50,3269,3270],{"class":1353}," เช",[50,3272,3147],{"class":799},[50,3274,3275],{"class":1353},"นเดียวกันครับ\n",[3277,3278],"hr",{},[10,3280,3282],{"id":3281},"references","References",[1137,3284,3285],{},[1140,3286,3287],{},[23,3288,3291],{"href":3289,"rel":3290},"https://www.npmjs.com/package/medium-zoom",[27],"Medium Zoom",[1153,3293,3294],{},"html pre.shiki code .sLHrO, html code.shiki .sLHrO{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#E1E4E8}html pre.shiki code .sMTEB, html code.shiki .sMTEB{--shiki-light:#39ADB5;--shiki-default:#56B6C2;--shiki-dark:#F97583}html pre.shiki code .sZDfs, html code.shiki .sZDfs{--shiki-light:#90A4AE;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sDKbk, html code.shiki .sDKbk{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .s36IK, html code.shiki .s36IK{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#C678DD;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .stlKB, html code.shiki .stlKB{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .suMxZ, html code.shiki .suMxZ{--shiki-light:#6182B8;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .stkEM, html code.shiki .stkEM{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E06C75;--shiki-default-font-style:italic;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .sOHk9, html code.shiki .sOHk9{--shiki-light:#9C3EDA;--shiki-default:#C678DD;--shiki-dark:#F97583}html pre.shiki code .sUzmo, html code.shiki .sUzmo{--shiki-light:#90A4AE;--shiki-default:#E5C07B;--shiki-dark:#79B8FF}html pre.shiki code .sbGrh, html code.shiki .sbGrh{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F97583}html pre.shiki code .sGnaQ, html code.shiki .sGnaQ{--shiki-light:#E2931D;--shiki-default:#E5C07B;--shiki-dark:#B392F0}html pre.shiki code .sbHgf, html code.shiki .sbHgf{--shiki-light:#E53935;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sU9mH, html code.shiki .sU9mH{--shiki-light:#90A4AE;--shiki-default:#E5C07B;--shiki-dark:#E1E4E8}",{"title":45,"searchDepth":124,"depth":124,"links":3296},[3297,3303],{"id":2785,"depth":124,"text":2785,"children":3298},[3299,3300,3301,3302],{"id":2788,"depth":134,"text":2789},{"id":2834,"depth":134,"text":2835},{"id":2847,"depth":134,"text":2848},{"id":3074,"depth":134,"text":3075},{"id":3281,"depth":124,"text":3282},"2025-04-25T00:00:00.000Z","วิธีการทำให้รูปของเรามีลูกเล่นเหมือนกับ Medium.com",{},"NuxtJS Medium Zoom","/blogs/2025-04-25-setup-nuxt-medium-zoom",{"title":2772,"description":3305},{"loc":3308},"blogs/2025-04-25-setup-nuxt-medium-zoom",[1195],"whVJldCP8LaTo3ruC26HfUr-1LznfTJBskZT-Cb3kN0",{"id":3315,"title":3316,"body":3317,"date":3491,"description":3492,"draft":1185,"extension":1186,"meta":3493,"navigation":137,"next":1188,"ogTitle":3494,"path":3495,"pin":1185,"prev":1188,"recommends":3496,"seo":3499,"sitemap":3500,"stem":3501,"tags":3502,"__hash__":3503},"content/blogs/2025-05-10-n8n-with-telegram-notify.md","ส่งการแจ้งเตือนไปยัง Telegram Bot ด้วย N8N",{"type":7,"value":3318,"toc":3486},[3319,3324,3328,3335,3338,3342,3345,3350,3357,3362,3379,3384,3391,3396,3407,3412,3419,3429,3434,3441,3446,3449,3454,3459,3465,3468,3473,3475],[15,3320,3321],{},[2610,3322],{"alt":45,"src":3323},"/images/2025-05-10-n8n-with-telegram-notify/images-d022bdb9-7169-4052-baaf-c1da8325bce2.jpg",[10,3325,3327],{"id":3326},"telegram-bot-คืออะไร","Telegram Bot คืออะไร",[15,3329,3330,3331,3334],{},"หลังจากที่ Line Notify ประกาศยุติการให้บริการไป Telegram ก็ขึ้นมาเป็นอันดับต้น ๆ ของการทำ Notification เนื่องด้วยเหตุผลหลัก ๆ คือ ",[18,3332,3333],{},"FREE"," และใช้งานส่งได้ไม่จำกัด แต่ผมเองจริง ๆ ย้ายมาใช้ Telegram ได้หลายปีแล้วครับ ช่วงแรก ๆ ก็ใช้ Line Notify แล้วก็ไปใช้ Discord แทน สุดท้ายมาจบที่ Telegram เพราะว่าต้องการจะใช้ Line เฉพาะคุยเรื่องส่วนตัว (ไม่อยากใช้ Line ในการทำงาน) ส่วน Discord ก็อยากเอาไว้ใช้ในการพูดคุยกับเพื่อน ๆ มากกว่า",[15,3336,3337],{},"ข้อดีของ Telegram Bot หลัก ๆ ในส่วนของการพัฒนาถือว่าง่ายมากครับมีทั้งแบบ Polling และ Webhook ให้ใช้งาน หลัง ๆ มาเลยใช้แต่ Telegram เป็นหลักเลยครับ",[10,3339,3341],{"id":3340},"วิธีการสร้าง-telegram-bot","วิธีการสร้าง Telegram Bot",[15,3343,3344],{},"ทำการ Add telegram ที่ชื่อว่า \"BotFather\" สามารถสแกน QR Code นี้ได้เลยครับผม โดยที่ BotFater จะเป็น Chat Bot ที่เอาไว้ใช้ในการสร้าง/จัดการ Bot ของเราเองนะครับ",[15,3346,3347],{},[2610,3348],{"alt":45,"src":3349},"/images/2025-05-10-n8n-with-telegram-notify/images-91fa3609-6307-47b8-9298-70fa23a34007.jpg",[15,3351,3352,3353,3356],{},"จากนั้นใช้ command ",[47,3354,3355],{},"/newbot"," เพื่อเป็นการเริ่มขั้นตอนในการสร้าง Bot ตัวใหม่ขึ้นมา แล้วจะมีการถามชื่อของ Bot ที่เราต้องการจะสร้างขึ้นมานะครับ",[15,3358,3359],{},[2610,3360],{"alt":45,"src":3361},"/images/2025-05-10-n8n-with-telegram-notify/images-c191577e-5e9c-40a9-8cbc-c43ee57882b1.jpg",[15,3363,3364,3365,3368,3369,3372,3373,665,3376],{},"เมื่อส่งชื่อไปแล้ว จะมีการถาม ",[47,3366,3367],{},"username"," ที่ต้องการใช้งาน ซึ่งจำเป็นต้องมีคำว่า ",[47,3370,3371],{},"bot"," ต่อท้าย เช่น ",[47,3374,3375],{},"demo_n8n_bot",[47,3377,3378],{},"DemoN8NBot",[15,3380,3381],{},[2610,3382],{"alt":45,"src":3383},"/images/2025-05-10-n8n-with-telegram-notify/images-88651bc7-c8c2-4dcf-8fd0-401709b44bce.jpg",[15,3385,3386,3387,3390],{},"จากนั้นจะได้รับ Token สำหรับจัดการ Bot มานะครับ ซึ่งตรงนี้ต้องรักษาเป็นความลับอย่างดี เพราะถ้าหากมีคนได้ Token นี้ไปจะทำให้สามารถเข้าถึงข้อมูลของ Bot ได้ครับ Copy เอา Token เก็บไว้ แล้วกดตรง ",[47,3388,3389],{},"t.me/\u003Cusername>"," เพื่อไปยัง Chat กับ Bot ได้เลย",[15,3392,3393],{},[2610,3394],{"alt":45,"src":3395},"/images/2025-05-10-n8n-with-telegram-notify/images-da1134ab-a6b2-4644-bd8a-11ef539abf44.jpg",[15,3397,3398,3399,3402,3403,3406],{},"จากนั้นเปิด browser แล้วไปที่ ",[47,3400,3401],{},"https://api.telegram.org/bot\u003CTOKEN>/getUpdates"," โดยให้แทนที่ ",[47,3404,3405],{},"\u003CTOKEN>"," ด้วย token ที่ copy เอาไว้ได้เลยครับ",[15,3408,3409],{},[2610,3410],{"alt":45,"src":3411},"/images/2025-05-10-n8n-with-telegram-notify/images-7f8a4bc4-8437-411f-8222-baa8ee3e25fe.jpg",[15,3413,3414,3415,3418],{},"จากนั้นให้ลองส่ง message อะไรก็ได้ไปยัง telegram bot ของเรา เพื่อค้นหา ",[47,3416,3417],{},"chat id"," เพื่อนำไปใช้งานใน N8N",[15,3420,3421,3422,3424,3425,3428],{},"หลังจากพิมพ์เสร็จแล้วเมื่อ refresh หน้าเว็บดูจะพบกับข้อมูลนะครับ ถ้าขึ้นแบบนี้แสดงว่าถูกต้อง แต่ถ้าไม่ขึ้นอาจจะลองเชค URL ดูว่าใส่ token ลงไปถูกรึเปล่า โดย ",[47,3423,3417],{}," จะอยู่ที่ ",[47,3426,3427],{},"chat: {id}"," ตามที่วงเอาไว้ สามารถ copy เก็บไว้ได้เลยครับ",[15,3430,3431],{},[2610,3432],{"alt":45,"src":3433},"/images/2025-05-10-n8n-with-telegram-notify/images-a198f69c-6c16-436f-a836-666e14a49c13.jpg",[15,3435,3436,3437,3440],{},"เข้าไปที่ N8N และเลือก Node ",[47,3438,3439],{},"Send a text message"," ของ telegram",[15,3442,3443],{},[2610,3444],{"alt":45,"src":3445},"/images/2025-05-10-n8n-with-telegram-notify/images-80f7301f-dd22-48e9-a4b9-b11166c4e11d.jpg",[15,3447,3448],{},"กดสร้าง Credential ใหม่ และนำ Token จาก Bot Father มาใส่",[15,3450,3451],{},[2610,3452],{"alt":45,"src":3453},"/images/2025-05-10-n8n-with-telegram-notify/images-579dd0eb-09a0-455f-94d4-2d401f8635e2.jpg",[15,3455,3456],{},[2610,3457],{"alt":45,"src":3458},"/images/2025-05-10-n8n-with-telegram-notify/images-205b9bf5-77c4-450f-be07-9bf7c3537e87.jpg",[15,3460,3461,3462],{},"จากนั้นกรอก Chat ID ที่ copy เก็บเอาไว้และกด \"Test Step\" ได้เลยครับ\n",[2610,3463],{"alt":45,"src":3464},"/images/2025-05-10-n8n-with-telegram-notify/images-b3fd3007-4360-4e16-afa7-8bc0d51c48e8.jpg",[15,3466,3467],{},"เพียงเท่านี้ก็จะสามารถส่งการแจ้งเตือนไปยัง Telegram ของเราด้วย Telegram Bot ได้แล้ว",[15,3469,3470],{},[2610,3471],{"alt":45,"src":3472},"/images/2025-05-10-n8n-with-telegram-notify/images-c7148489-9d38-4647-a3bf-e7f696f4ddcd.jpg",[10,3474,1128],{"id":1128},[15,3476,3477,3478,3481,3482,3485],{},"การส่งแจ้งเตือนไปยัง Telegram Bot ต้องการข้อมูล 2 อย่างคือ ",[47,3479,3480],{},"Telegram Token"," และ ",[47,3483,3484],{},"Chat ID"," ซึ่งเป็น Chat ของผู้ใช้งานที่ต้องการส่งข้อความไป โดยวิธีนี้ไม่จำเป็นต้องตั้งค่า Webhook ของ Telegram นะครับ ง่าย ๆ และใช้งานได้จริง ย้ายมาใช้ Telegram กันเยอะ ๆ นะครับ ของดีจริง",{"title":45,"searchDepth":124,"depth":124,"links":3487},[3488,3489,3490],{"id":3326,"depth":124,"text":3327},{"id":3340,"depth":124,"text":3341},{"id":1128,"depth":124,"text":1128},"2025-05-10T00:00:00.000Z","แนะนำวิธีการเชื่อมต่อ Telegram Bot และ N8N เพื่อส่งการแจ้งเตือนไปยัง Telegram สำหรับมือใหม่",{},"Telegram Bot With N8N","/blogs/2025-05-10-n8n-with-telegram-notify",[3497,3498],"n8n-part-1","n8n-part-2",{"title":3316,"description":3492},{"loc":3495},"blogs/2025-05-10-n8n-with-telegram-notify",[1195],"bdf-5m9xnGC3mhOzRjPySVqr5PC_xqfGkE6r8e8gH1A",{"id":3505,"title":3506,"body":3507,"date":4430,"description":4431,"draft":1185,"extension":1186,"meta":4432,"navigation":137,"next":1188,"ogTitle":4433,"path":4434,"pin":1185,"prev":1188,"recommends":1188,"seo":4435,"sitemap":4436,"stem":4437,"tags":4438,"__hash__":4439},"content/blogs/2025-05-23-nuxt-tailwindcss-nuxtui-setup.md","Cheat Sheet Nuxt x Tailwindcss x NuxtUI",{"type":7,"value":3508,"toc":4424},[3509,3513,3520,3546,3917,3921,4028,4032,4038,4055,4058,4075,4085,4119,4122,4172,4176,4182,4235,4241,4308,4315,4421],[10,3510,3512],{"id":3511},"init-nuxtjs","Init NuxtJS",[15,3514,3515,3516],{},"Docs: ",[23,3517,3518],{"href":3518,"rel":3519},"https://nuxt.com/docs/getting-started/installation",[27],[40,3521,3523],{"className":42,"code":3522,"language":44,"meta":45,"style":45},"npm create nuxt \u003Cproject-name>\n",[47,3524,3525],{"__ignoreMap":45},[50,3526,3527,3529,3532,3535,3537,3540,3543],{"class":52,"line":53},[50,3528,2799],{"class":56},[50,3530,3531],{"class":60}," create",[50,3533,3534],{"class":60}," nuxt",[50,3536,1941],{"class":88},[50,3538,3539],{"class":60},"project-nam",[50,3541,3542],{"class":799},"e",[50,3544,3545],{"class":88},">\n",[40,3547,3549],{"className":42,"code":3548,"language":44,"meta":45,"style":45},"✔ Which package manager would you like to use?\nnpm\n\n✔ Initialize git repository?\nYes\nℹ Initializing git repository...\n\n❯ Would you like to install any of the official modules?\n◼ @nuxt/content – The file-based CMS with support for Markdown, YAML, JSON\n◼ @nuxt/eslint – Project-aware, easy-to-use, extensible and future-proof ESLint integration\n◼ @nuxt/fonts – Add custom web fonts with performance in mind\n◼ @nuxt/icon – Icon module for Nuxt with 200,000+ ready to use icons from Iconify\n◼ @nuxt/image – Add images with progressive processing, lazy-loading, resizing and providers support\n◼ @nuxt/scripts – Add 3rd-party scripts without sacrificing performance\n◻ @nuxt/test-utils – Test utilities for Nuxt\n◼ @nuxt/ui – The Intuitive UI Library powered by Reka UI and Tailwind CSS\n",[47,3550,3551,3580,3585,3589,3602,3607,3620,3624,3655,3692,3722,3754,3795,3831,3857,3878],{"__ignoreMap":45},[50,3552,3553,3556,3559,3562,3565,3568,3571,3574,3577],{"class":52,"line":53},[50,3554,3555],{"class":56},"✔",[50,3557,3558],{"class":60}," Which",[50,3560,3561],{"class":60}," package",[50,3563,3564],{"class":60}," manager",[50,3566,3567],{"class":60}," would",[50,3569,3570],{"class":60}," you",[50,3572,3573],{"class":60}," like",[50,3575,3576],{"class":60}," to",[50,3578,3579],{"class":60}," use?\n",[50,3581,3582],{"class":52,"line":124},[50,3583,3584],{"class":56},"npm\n",[50,3586,3587],{"class":52,"line":134},[50,3588,138],{"emptyLinePlaceholder":137},[50,3590,3591,3593,3596,3599],{"class":52,"line":141},[50,3592,3555],{"class":56},[50,3594,3595],{"class":60}," Initialize",[50,3597,3598],{"class":60}," git",[50,3600,3601],{"class":60}," repository?\n",[50,3603,3604],{"class":52,"line":147},[50,3605,3606],{"class":56},"Yes\n",[50,3608,3609,3612,3615,3617],{"class":52,"line":214},[50,3610,3611],{"class":56},"ℹ",[50,3613,3614],{"class":60}," Initializing",[50,3616,3598],{"class":60},[50,3618,3619],{"class":60}," repository...\n",[50,3621,3622],{"class":52,"line":219},[50,3623,138],{"emptyLinePlaceholder":137},[50,3625,3626,3629,3632,3634,3636,3638,3640,3643,3646,3649,3652],{"class":52,"line":225},[50,3627,3628],{"class":56},"❯",[50,3630,3631],{"class":60}," Would",[50,3633,3570],{"class":60},[50,3635,3573],{"class":60},[50,3637,3576],{"class":60},[50,3639,61],{"class":60},[50,3641,3642],{"class":60}," any",[50,3644,3645],{"class":60}," of",[50,3647,3648],{"class":60}," the",[50,3650,3651],{"class":60}," official",[50,3653,3654],{"class":60}," modules?\n",[50,3656,3657,3660,3663,3666,3669,3672,3675,3678,3681,3683,3686,3689],{"class":52,"line":541},[50,3658,3659],{"class":56},"◼",[50,3661,3662],{"class":60}," @nuxt/content",[50,3664,3665],{"class":60}," –",[50,3667,3668],{"class":60}," The",[50,3670,3671],{"class":60}," file-based",[50,3673,3674],{"class":60}," CMS",[50,3676,3677],{"class":60}," with",[50,3679,3680],{"class":60}," support",[50,3682,890],{"class":60},[50,3684,3685],{"class":60}," Markdown,",[50,3687,3688],{"class":60}," YAML,",[50,3690,3691],{"class":60}," JSON\n",[50,3693,3694,3696,3699,3701,3704,3707,3710,3713,3716,3719],{"class":52,"line":551},[50,3695,3659],{"class":56},[50,3697,3698],{"class":60}," @nuxt/eslint",[50,3700,3665],{"class":60},[50,3702,3703],{"class":60}," Project-aware,",[50,3705,3706],{"class":60}," easy-to-use,",[50,3708,3709],{"class":60}," extensible",[50,3711,3712],{"class":60}," and",[50,3714,3715],{"class":60}," future-proof",[50,3717,3718],{"class":60}," ESLint",[50,3720,3721],{"class":60}," integration\n",[50,3723,3724,3726,3729,3731,3734,3737,3740,3743,3745,3748,3751],{"class":52,"line":556},[50,3725,3659],{"class":56},[50,3727,3728],{"class":60}," @nuxt/fonts",[50,3730,3665],{"class":60},[50,3732,3733],{"class":60}," Add",[50,3735,3736],{"class":60}," custom",[50,3738,3739],{"class":60}," web",[50,3741,3742],{"class":60}," fonts",[50,3744,3677],{"class":60},[50,3746,3747],{"class":60}," performance",[50,3749,3750],{"class":60}," in",[50,3752,3753],{"class":60}," mind\n",[50,3755,3756,3758,3761,3763,3766,3769,3771,3774,3776,3779,3782,3784,3787,3790,3792],{"class":52,"line":562},[50,3757,3659],{"class":56},[50,3759,3760],{"class":60}," @nuxt/icon",[50,3762,3665],{"class":60},[50,3764,3765],{"class":60}," Icon",[50,3767,3768],{"class":60}," module",[50,3770,890],{"class":60},[50,3772,3773],{"class":60}," Nuxt",[50,3775,3677],{"class":60},[50,3777,3778],{"class":60}," 200,000+",[50,3780,3781],{"class":60}," ready",[50,3783,3576],{"class":60},[50,3785,3786],{"class":60}," use",[50,3788,3789],{"class":60}," icons",[50,3791,2869],{"class":60},[50,3793,3794],{"class":60}," Iconify\n",[50,3796,3797,3799,3802,3804,3806,3809,3811,3814,3817,3820,3823,3825,3828],{"class":52,"line":575},[50,3798,3659],{"class":56},[50,3800,3801],{"class":60}," @nuxt/image",[50,3803,3665],{"class":60},[50,3805,3733],{"class":60},[50,3807,3808],{"class":60}," images",[50,3810,3677],{"class":60},[50,3812,3813],{"class":60}," progressive",[50,3815,3816],{"class":60}," processing,",[50,3818,3819],{"class":60}," lazy-loading,",[50,3821,3822],{"class":60}," resizing",[50,3824,3712],{"class":60},[50,3826,3827],{"class":60}," providers",[50,3829,3830],{"class":60}," support\n",[50,3832,3833,3835,3838,3840,3842,3845,3848,3851,3854],{"class":52,"line":580},[50,3834,3659],{"class":56},[50,3836,3837],{"class":60}," @nuxt/scripts",[50,3839,3665],{"class":60},[50,3841,3733],{"class":60},[50,3843,3844],{"class":60}," 3rd-party",[50,3846,3847],{"class":60}," scripts",[50,3849,3850],{"class":60}," without",[50,3852,3853],{"class":60}," sacrificing",[50,3855,3856],{"class":60}," performance\n",[50,3858,3859,3862,3865,3867,3870,3873,3875],{"class":52,"line":586},[50,3860,3861],{"class":56},"◻",[50,3863,3864],{"class":60}," @nuxt/test-utils",[50,3866,3665],{"class":60},[50,3868,3869],{"class":60}," Test",[50,3871,3872],{"class":60}," utilities",[50,3874,890],{"class":60},[50,3876,3877],{"class":60}," Nuxt\n",[50,3879,3880,3882,3885,3887,3889,3892,3895,3898,3901,3904,3907,3909,3911,3914],{"class":52,"line":1511},[50,3881,3659],{"class":56},[50,3883,3884],{"class":60}," @nuxt/ui",[50,3886,3665],{"class":60},[50,3888,3668],{"class":60},[50,3890,3891],{"class":60}," Intuitive",[50,3893,3894],{"class":60}," UI",[50,3896,3897],{"class":60}," Library",[50,3899,3900],{"class":60}," powered",[50,3902,3903],{"class":60}," by",[50,3905,3906],{"class":60}," Reka",[50,3908,3894],{"class":60},[50,3910,3712],{"class":60},[50,3912,3913],{"class":60}," Tailwind",[50,3915,3916],{"class":60}," CSS\n",[10,3918,3920],{"id":3919},"preventing-yarn-allow-only-npm","Preventing Yarn (Allow only NPM)",[40,3922,3924],{"className":42,"code":3923,"language":44,"meta":45,"style":45},"\"engines\": {\n    \"yarn\": \"Please use NPM!\",\n    \"node\": \"22.x\",\n    \"npm\": \">=6\"\n},\n\n# shell\necho \"22\" > .nvmrc\necho \"engine-strict=true\" > .npmrc\n",[47,3925,3926,3935,3951,3967,3981,3986,3990,3995,4012],{"__ignoreMap":45},[50,3927,3928,3931,3933],{"class":52,"line":53},[50,3929,3930],{"class":56},"\"engines\"",[50,3932,1241],{"class":457},[50,3934,1357],{"class":60},[50,3936,3937,3940,3942,3944,3947,3949],{"class":52,"line":124},[50,3938,3939],{"class":56},"    \"yarn\"",[50,3941,1241],{"class":457},[50,3943,1258],{"class":390},[50,3945,3946],{"class":60},"Please use NPM!",[50,3948,830],{"class":390},[50,3950,1266],{"class":60},[50,3952,3953,3956,3958,3960,3963,3965],{"class":52,"line":134},[50,3954,3955],{"class":56},"    \"node\"",[50,3957,1241],{"class":457},[50,3959,1258],{"class":390},[50,3961,3962],{"class":60},"22.x",[50,3964,830],{"class":390},[50,3966,1266],{"class":60},[50,3968,3969,3972,3974,3976,3979],{"class":52,"line":141},[50,3970,3971],{"class":56},"    \"npm\"",[50,3973,1241],{"class":457},[50,3975,1258],{"class":390},[50,3977,3978],{"class":60},">=6",[50,3980,1325],{"class":390},[50,3982,3983],{"class":52,"line":147},[50,3984,3985],{"class":799},"},\n",[50,3987,3988],{"class":52,"line":214},[50,3989,138],{"emptyLinePlaceholder":137},[50,3991,3992],{"class":52,"line":219},[50,3993,3994],{"class":120},"# shell\n",[50,3996,3997,4000,4002,4005,4007,4009],{"class":52,"line":225},[50,3998,3999],{"class":457},"echo",[50,4001,1258],{"class":390},[50,4003,4004],{"class":60},"22",[50,4006,830],{"class":390},[50,4008,1959],{"class":88},[50,4010,4011],{"class":60}," .nvmrc\n",[50,4013,4014,4016,4018,4021,4023,4025],{"class":52,"line":541},[50,4015,3999],{"class":457},[50,4017,1258],{"class":390},[50,4019,4020],{"class":60},"engine-strict=true",[50,4022,830],{"class":390},[50,4024,1959],{"class":88},[50,4026,4027],{"class":60}," .npmrc\n",[10,4029,4031],{"id":4030},"install-tailwindcss-version-4","Install Tailwindcss Version 4",[15,4033,3515,4034],{},[23,4035,4036],{"href":4036,"rel":4037},"https://tailwindcss.com/docs/installation/framework-guides/nuxt",[27],[40,4039,4041],{"className":42,"code":4040,"language":44,"meta":45,"style":45},"npm install tailwindcss @tailwindcss/vite\n",[47,4042,4043],{"__ignoreMap":45},[50,4044,4045,4047,4049,4052],{"class":52,"line":53},[50,4046,2799],{"class":56},[50,4048,61],{"class":60},[50,4050,4051],{"class":60}," tailwindcss",[50,4053,4054],{"class":60}," @tailwindcss/vite\n",[15,4056,4057],{},"Edit",[40,4059,4063],{"className":4060,"code":4061,"language":4062,"meta":45,"style":45},"language-vue shiki shiki-themes material-theme-lighter one-dark-pro github-dark","import tailwindcss from \"@tailwindcss/vite\"; export default defineNuxtConfig({\n... vite: { plugins: [ tailwindcss(), ], }, });\n","vue",[47,4064,4065,4070],{"__ignoreMap":45},[50,4066,4067],{"class":52,"line":53},[50,4068,4069],{"class":799},"import tailwindcss from \"@tailwindcss/vite\"; export default defineNuxtConfig({\n",[50,4071,4072],{"class":52,"line":124},[50,4073,4074],{"class":799},"... vite: { plugins: [ tailwindcss(), ], }, });\n",[15,4076,4077,4078,4081,4082],{},"Create a tailwindcss config file ",[47,4079,4080],{},"mkdir -p assets/css"," ",[47,4083,4084],{},"touch assets/css/main.css",[40,4086,4090],{"className":4087,"code":4088,"language":4089,"meta":45,"style":45},"language-css shiki shiki-themes material-theme-lighter one-dark-pro github-dark","@import 'tailwindcss';\n@import '@nuxt/ui';\n","css",[47,4091,4092,4106],{"__ignoreMap":45},[50,4093,4094,4097,4099,4102,4104],{"class":52,"line":53},[50,4095,4096],{"class":795},"@import",[50,4098,391],{"class":390},[50,4100,4101],{"class":60},"tailwindcss",[50,4103,989],{"class":390},[50,4105,1372],{"class":819},[50,4107,4108,4110,4112,4115,4117],{"class":52,"line":124},[50,4109,4096],{"class":795},[50,4111,391],{"class":390},[50,4113,4114],{"class":60},"@nuxt/ui",[50,4116,989],{"class":390},[50,4118,1372],{"class":819},[15,4120,4121],{},"edit nuxt config file",[40,4123,4125],{"className":2851,"code":4124,"language":2853,"meta":45,"style":45},"export default defineNuxtConfig({\n    ...\n    css: ['~/assets/css/main.css'],\n});\n",[47,4126,4127,4140,4145,4164],{"__ignoreMap":45},[50,4128,4129,4131,4133,4136,4138],{"class":52,"line":53},[50,4130,1498],{"class":795},[50,4132,2912],{"class":795},[50,4134,4135],{"class":1504}," defineNuxtConfig",[50,4137,827],{"class":799},[50,4139,1226],{"class":819},[50,4141,4142],{"class":52,"line":124},[50,4143,4144],{"class":88},"    ...\n",[50,4146,4147,4150,4153,4155,4158,4160,4162],{"class":52,"line":134},[50,4148,4149],{"class":1597},"    css",[50,4151,4152],{"class":799},": [",[50,4154,989],{"class":390},[50,4156,4157],{"class":60},"~/assets/css/main.css",[50,4159,989],{"class":390},[50,4161,2219],{"class":799},[50,4163,1266],{"class":819},[50,4165,4166,4168,4170],{"class":52,"line":141},[50,4167,2164],{"class":819},[50,4169,1549],{"class":799},[50,4171,1372],{"class":819},[10,4173,4175],{"id":4174},"nuxt-layout","Nuxt Layout",[15,4177,3515,4178],{},[23,4179,4180],{"href":4180,"rel":4181},"https://nuxt.com/docs/guide/directory-structure/layouts",[27],[40,4183,4185],{"className":4060,"code":4184,"language":4062,"meta":45,"style":45},"\u003Ctemplate>\n  \u003CNuxtLayout>\n    \u003CNuxtPage />\n  \u003C/NuxtLayout>\n\u003C/template>\n",[47,4186,4187,4197,4207,4217,4226],{"__ignoreMap":45},[50,4188,4189,4191,4195],{"class":52,"line":53},[50,4190,1412],{"class":819},[50,4192,4194],{"class":4193},"s0Prt","template",[50,4196,3545],{"class":819},[50,4198,4199,4202,4205],{"class":52,"line":124},[50,4200,4201],{"class":819},"  \u003C",[50,4203,4204],{"class":4193},"NuxtLayout",[50,4206,3545],{"class":819},[50,4208,4209,4212,4215],{"class":52,"line":134},[50,4210,4211],{"class":819},"    \u003C",[50,4213,4214],{"class":4193},"NuxtPage",[50,4216,3133],{"class":819},[50,4218,4219,4222,4224],{"class":52,"line":141},[50,4220,4221],{"class":819},"  \u003C/",[50,4223,4204],{"class":4193},[50,4225,3545],{"class":819},[50,4227,4228,4231,4233],{"class":52,"line":147},[50,4229,4230],{"class":819},"\u003C/",[50,4232,4194],{"class":4193},[50,4234,3545],{"class":819},[15,4236,4237,4238],{},"Create a new file ",[47,4239,4240],{},"layouts/default.vue",[40,4242,4244],{"className":4060,"code":4243,"language":4062,"meta":45,"style":45},"\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cp>Some default layout content shared across all pages\u003C/p>\n    \u003Cslot />\n  \u003C/div>\n\u003C/template>\n",[47,4245,4246,4254,4263,4280,4292,4300],{"__ignoreMap":45},[50,4247,4248,4250,4252],{"class":52,"line":53},[50,4249,1412],{"class":819},[50,4251,4194],{"class":4193},[50,4253,3545],{"class":819},[50,4255,4256,4258,4261],{"class":52,"line":124},[50,4257,4201],{"class":819},[50,4259,4260],{"class":4193},"div",[50,4262,3545],{"class":819},[50,4264,4265,4267,4269,4271,4274,4276,4278],{"class":52,"line":134},[50,4266,4211],{"class":819},[50,4268,15],{"class":4193},[50,4270,1418],{"class":819},[50,4272,4273],{"class":799},"Some default layout content shared across all pages",[50,4275,4230],{"class":819},[50,4277,15],{"class":4193},[50,4279,3545],{"class":819},[50,4281,4282,4284,4287,4290],{"class":52,"line":141},[50,4283,4211],{"class":819},[50,4285,4286],{"class":4193},"slot",[50,4288,1916],{"class":4289},"sRwpp",[50,4291,3545],{"class":819},[50,4293,4294,4296,4298],{"class":52,"line":147},[50,4295,4221],{"class":819},[50,4297,4260],{"class":4193},[50,4299,3545],{"class":819},[50,4301,4302,4304,4306],{"class":52,"line":214},[50,4303,4230],{"class":819},[50,4305,4194],{"class":4193},[50,4307,3545],{"class":819},[15,4309,4310,4311,4314],{},"Create a ",[47,4312,4313],{},"pages"," folder",[40,4316,4318],{"className":4060,"code":4317,"language":4062,"meta":45,"style":45},"\u003Ctemplate>\n  \u003Cdiv>Login Page\u003C/div>\n\u003C/template>\n\n\u003Cscript setup lang=\"ts\">\ndefinePageMeta({\n  layout: 'no-auth',\n})\n\u003C/script>\n",[47,4319,4320,4328,4345,4353,4357,4382,4391,4407,4413],{"__ignoreMap":45},[50,4321,4322,4324,4326],{"class":52,"line":53},[50,4323,1412],{"class":819},[50,4325,4194],{"class":4193},[50,4327,3545],{"class":819},[50,4329,4330,4332,4334,4336,4339,4341,4343],{"class":52,"line":124},[50,4331,4201],{"class":819},[50,4333,4260],{"class":4193},[50,4335,1418],{"class":819},[50,4337,4338],{"class":799},"Login Page",[50,4340,4230],{"class":819},[50,4342,4260],{"class":4193},[50,4344,3545],{"class":819},[50,4346,4347,4349,4351],{"class":52,"line":134},[50,4348,4230],{"class":819},[50,4350,4194],{"class":4193},[50,4352,3545],{"class":819},[50,4354,4355],{"class":52,"line":141},[50,4356,138],{"emptyLinePlaceholder":137},[50,4358,4359,4361,4364,4368,4371,4373,4375,4378,4380],{"class":52,"line":147},[50,4360,1412],{"class":819},[50,4362,4363],{"class":4193},"script",[50,4365,4367],{"class":4366},"s4x1N"," setup",[50,4369,4370],{"class":4366}," lang",[50,4372,813],{"class":819},[50,4374,830],{"class":390},[50,4376,4377],{"class":60},"ts",[50,4379,830],{"class":390},[50,4381,3545],{"class":819},[50,4383,4384,4387,4389],{"class":52,"line":214},[50,4385,4386],{"class":1504},"definePageMeta",[50,4388,827],{"class":799},[50,4390,1226],{"class":819},[50,4392,4393,4396,4398,4400,4403,4405],{"class":52,"line":219},[50,4394,4395],{"class":1756},"  layout",[50,4397,1241],{"class":819},[50,4399,391],{"class":390},[50,4401,4402],{"class":60},"no-auth",[50,4404,989],{"class":390},[50,4406,1266],{"class":819},[50,4408,4409,4411],{"class":52,"line":225},[50,4410,2164],{"class":819},[50,4412,838],{"class":799},[50,4414,4415,4417,4419],{"class":52,"line":541},[50,4416,4230],{"class":819},[50,4418,4363],{"class":4193},[50,4420,3545],{"class":819},[1153,4422,4423],{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sbGrh, html code.shiki .sbGrh{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F97583}html pre.shiki code .sZDfs, html code.shiki .sZDfs{--shiki-light:#90A4AE;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJZfL, html code.shiki .sJZfL{--shiki-light:#6182B8;--shiki-default:#56B6C2;--shiki-dark:#79B8FF}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sDKbk, html code.shiki .sDKbk{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .s36IK, html code.shiki .s36IK{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#C678DD;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .suMxZ, html code.shiki .suMxZ{--shiki-light:#6182B8;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .stlKB, html code.shiki .stlKB{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sLHrO, html code.shiki .sLHrO{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#E1E4E8}html pre.shiki code .s0Prt, html code.shiki .s0Prt{--shiki-light:#E53935;--shiki-default:#E06C75;--shiki-dark:#85E89D}html pre.shiki code .sRwpp, html code.shiki .sRwpp{--shiki-light:#39ADB5;--shiki-light-font-style:inherit;--shiki-default:#FFFFFF;--shiki-default-font-style:inherit;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}html pre.shiki code .s4x1N, html code.shiki .s4x1N{--shiki-light:#9C3EDA;--shiki-default:#D19A66;--shiki-dark:#B392F0}html pre.shiki code .sTQd7, html code.shiki .sTQd7{--shiki-light:#E53935;--shiki-default:#E06C75;--shiki-dark:#E1E4E8}",{"title":45,"searchDepth":124,"depth":124,"links":4425},[4426,4427,4428,4429],{"id":3511,"depth":124,"text":3512},{"id":3919,"depth":124,"text":3920},{"id":4030,"depth":124,"text":4031},{"id":4174,"depth":124,"text":4175},"2025-05-23T00:00:00.000Z","Note วิธีการ setup",{},"NuxtJS with Tailwindcss","/blogs/2025-05-23-nuxt-tailwindcss-nuxtui-setup",{"title":3506,"description":4431},{"loc":4434},"blogs/2025-05-23-nuxt-tailwindcss-nuxtui-setup",[1195],"R9fIxzq655lJgo3otne9RiXEDsMi86tRH4PhYutZ9vE",{"id":4441,"title":4442,"body":4443,"date":4840,"description":4841,"draft":1185,"extension":1186,"meta":4842,"navigation":137,"next":1188,"ogTitle":4843,"path":4844,"pin":1185,"prev":1188,"recommends":4845,"seo":4847,"sitemap":4848,"stem":4849,"tags":4850,"__hash__":4851},"content/blogs/2025-08-30-pagecms-opensource.md","จัดการ Content ด้วย pagecms opensource สุดคูล",{"type":7,"value":4444,"toc":4834},[4445,4449,4464,4473,4482,4491,4495,4498,4506,4513,4518,4522,4536,4541,4544,4547,4554,4557,4560,4563,4831],[10,4446,4448],{"id":4447},"introduction","Introduction",[15,4450,4451,4452,4457,4458,4463],{},"เว็บไซต์นี้พัฒนาโดยใช้ ",[23,4453,4456],{"href":4454,"rel":4455},"https://nuxt.com/",[27],"Nuxt"," ร่วมกับ ",[23,4459,4462],{"href":4460,"rel":4461},"https://content.nuxt.com/",[27],"NuxtContent"," ซึ่งการจะเป็นการนำเอา Content ในรูปแบบของ Markdown มาสร้างเป็น Web Application โดยเป็นไปตามที่มีการตั้งค่าเอาไว้ ซึ่งวิธีนี้จะทำให้สามารถ Custom ตัวเว็บไซต์ได้เกือบ 100% เลย",[15,4465,4466,4467,4472],{},"ผมเก็บ source code ของ website ไว้ที่ github และ deploy ไปยัง ",[23,4468,4471],{"href":4469,"rel":4470},"https://pages.cloudflare.com/",[27],"cloudflare page"," โดยใช้ CICD ของ cloudflare page ครับ ซึ่งวิธีการนี้ทำให้มีค่าใช้จ่ายของเว็บไซต์นี้เกือบจะเป็น 0 บาทต่อเดือนเลยครับ เพราะทุกอย่างใช้จบได้ภายใน Free Tier",[15,4474,4475,4476,4481],{},"แต่ความยากอย่างนึงที่ผมเจอก็คือการที่ต้องจัดการ content ซึ่งอยู่ในรูปแบบของ markdown ช่วงแรก ๆ ก็จะใช้งานผ่าน vscode เอาเลย แต่ช่วงหลังก็เปลี่ยนมาใช้ ",[23,4477,4480],{"href":4478,"rel":4479},"https://obsidian.md/",[27],"obsidian"," โดยปรับแต่งให้สามารถจัดการ content ได้ แต่ก็ยังรู้สึกไม่ค่อยสะดวกเท่าไหร่",[15,4483,4484,4485,4490],{},"จนผมมาเจอเครื่องมือ opensource ตัวนึงชื่อว่า ",[23,4486,4489],{"href":4487,"rel":4488},"https://pagescms.org",[27],"pagecms"," ซึ่งสามารถแก้ไขปัญหาตรงนี้ให้ผมได้และสะดวกมากขึ้นเยอะเลยครับ",[10,4492,4494],{"id":4493},"what-is-pagecms","What is pagecms?",[15,4496,4497],{},"pagecms คือ Content Management System สำหรับ Website ที่เป็นประเภท Static Site เช่น Jekyll, Next.js, VuePress, Hugo หรือประเภทใดก็ตามที่มีการเก็บ content ในลักษณะของ File Markdown",[15,4499,4500,4501,4505],{},"ซึ่งตัวเครื่องมือนี้สามารถใช้งานได้แบบง่าย ๆ โดยการเข้าใช้งานที่ ",[23,4502,4503],{"href":4503,"rel":4504},"https://app.pagescms.org/",[27]," จากนั้นทำการเชื่อมต่อกับ Github และเลือก Repo ที่ต้องการได้เลย",[15,4507,4508,4509],{},"สามารถกำหนดการตั้งค่าต่าง ๆ ได้ผ่านตัวเว็บไซต์เลยครับ กำหนด config ให้ตรงกับ project structure โดยดูเพิ่มเติมได้จาก ",[23,4510,4511],{"href":4511,"rel":4512},"https://pagescms.org/docs/configuration/",[27],[15,4514,4515],{},[2610,4516],{"alt":45,"src":4517},"/images/2025-08-30-pagecms-opensource/page-cms-1.png",[10,4519,4521],{"id":4520},"สิ่งที่-pagecms-สามารถทำได้","สิ่งที่ pagecms สามารถทำได้",[1137,4523,4524,4527,4530,4533],{},[1140,4525,4526],{},"เพิ่ม/ลบ/แก้ไข content ของ website ได้ โดยจะเป็นการ commit เพื่อแก้ไข repo บน github โดยตรง",[1140,4528,4529],{},"สามารถเพิ่ม/ลบ จัดการ media ภายใน website หรือ repo ได้",[1140,4531,4532],{},"สลับ branch ในการจัดการได้",[1140,4534,4535],{},"สามารถ invite คนอื่นเข้ามาร่วมแก้ไขได้ด้วย โดยอันนี้จะเป็นการ invite เข้า repo บน github เลยนะครับ",[15,4537,4538],{},[2610,4539],{"alt":45,"src":4540},"/images/2025-08-30-pagecms-opensource/page-cms-2.png",[15,4542,4543],{},"ซึ่งทั้งหมดจะทำงานบน github อีกทีนึง ตัว pagecms จะเป็นแค่หน้ากากทำให้ใช้งานได้ง่ายยิ่งขึ้นครับ",[10,4545,4546],{"id":4546},"คำแนะนำ",[15,4548,4549,4550],{},"จากที่ลองใช้งานมารู้สึกโอเคนะครับ แต่ตอนนี้ project กำลังอยู่ในช่วงพัฒนาคิดว่าจะมีฟีเจอร์มาให้ใช้งานอีกเพียบ สามารถติดตามได้ที่ ",[23,4551,4552],{"href":4552,"rel":4553},"https://github.com/pages-cms/pages-cms",[27],[15,4555,4556],{},"แนะนำให้สร้าง branch แยกกับ branch ที่มีการเปิด CICD เอาไว้นะครับ เพราะว่าทุกครั้งที่มีการ Upload File ในช่อง \"Media\" มันจะเป็นการสร้าง commit ใหม่ ซึ่งจะ trigger CICD เลยครับ แนะนำว่าให้สร้าง branch ใหม่แล้วถ้าต้องการ update ค่อย merge เข้าไปใน branch หลักอีกที",[15,4558,4559],{},"สำหรับผมมองว่าเป็นแค่ Add-on ที่เพิ่มเข้ามา ถ้าวันนึงมันไม่ work แล้วก็สามารถนำออกไปได้เลยครับ",[15,4561,4562],{},"ส่วนอันนี้เป็น config สำหรับ Nuxt Content + Nuxt ที่ผมใช้งานอยู่นะครับ",[40,4564,4568],{"className":4565,"code":4566,"language":4567,"meta":45,"style":45},"language-markdown shiki shiki-themes material-theme-lighter one-dark-pro github-dark","media:\ninput: public/images\noutput: /images\ncontent:\n\n- name: blogs\n  label: Blog Posts\n  type: collection\n  path: 'content/blogs'\n  view:\n  fields: [ title, draft, date, tags ]\n  fields:\n  - name: title\n    label: Title\n    type: string\n  - name: description\n    label: Description\n    type: string\n  - name: date\n    label: Date\n    type: date\n    options:\n    format: yyyy-MM-dd\n  - name: tags\n    label: Tags\n    type: select\n    options:\n    creatable: true\n    multiple: true\n    values: [ Security, Home Lab, N8N, Telegram Bot, Ubuntu, Development, LLM ]\n  - name: draft\n    label: Draft\n    type: boolean\n    default: false\n  - name: image\n    label: Banner Image\n    type: image\n  - name: prev\n    label: Previous Post\n    type: string\n    description: Link to previous post\n  - name: next\n    label: Next Post\n    type: string\n    description: Link to next post\n  - name: recommends\n    label: Recommended Posts\n    type: select\n    options:\n    creatable: true\n    multiple: true\n  - name: body\n    label: Body\n    type: rich-text\n","markdown",[47,4569,4570,4575,4580,4585,4590,4594,4599,4604,4609,4614,4619,4624,4629,4634,4639,4644,4649,4654,4658,4663,4668,4673,4678,4683,4688,4693,4698,4702,4707,4712,4717,4722,4727,4732,4737,4742,4747,4752,4757,4762,4766,4771,4776,4781,4785,4790,4795,4800,4804,4808,4812,4816,4821,4826],{"__ignoreMap":45},[50,4571,4572],{"class":52,"line":53},[50,4573,4574],{},"media:\n",[50,4576,4577],{"class":52,"line":124},[50,4578,4579],{},"input: public/images\n",[50,4581,4582],{"class":52,"line":134},[50,4583,4584],{},"output: /images\n",[50,4586,4587],{"class":52,"line":141},[50,4588,4589],{},"content:\n",[50,4591,4592],{"class":52,"line":147},[50,4593,138],{"emptyLinePlaceholder":137},[50,4595,4596],{"class":52,"line":214},[50,4597,4598],{},"- name: blogs\n",[50,4600,4601],{"class":52,"line":219},[50,4602,4603],{},"  label: Blog Posts\n",[50,4605,4606],{"class":52,"line":225},[50,4607,4608],{},"  type: collection\n",[50,4610,4611],{"class":52,"line":541},[50,4612,4613],{},"  path: 'content/blogs'\n",[50,4615,4616],{"class":52,"line":551},[50,4617,4618],{},"  view:\n",[50,4620,4621],{"class":52,"line":556},[50,4622,4623],{},"  fields: [ title, draft, date, tags ]\n",[50,4625,4626],{"class":52,"line":562},[50,4627,4628],{},"  fields:\n",[50,4630,4631],{"class":52,"line":575},[50,4632,4633],{},"  - name: title\n",[50,4635,4636],{"class":52,"line":580},[50,4637,4638],{},"    label: Title\n",[50,4640,4641],{"class":52,"line":586},[50,4642,4643],{},"    type: string\n",[50,4645,4646],{"class":52,"line":1511},[50,4647,4648],{},"  - name: description\n",[50,4650,4651],{"class":52,"line":1524},[50,4652,4653],{},"    label: Description\n",[50,4655,4656],{"class":52,"line":1535},[50,4657,4643],{},[50,4659,4660],{"class":52,"line":1546},[50,4661,4662],{},"  - name: date\n",[50,4664,4665],{"class":52,"line":1558},[50,4666,4667],{},"    label: Date\n",[50,4669,4670],{"class":52,"line":1564},[50,4671,4672],{},"    type: date\n",[50,4674,4675],{"class":52,"line":1621},[50,4676,4677],{},"    options:\n",[50,4679,4680],{"class":52,"line":1666},[50,4681,4682],{},"    format: yyyy-MM-dd\n",[50,4684,4685],{"class":52,"line":1671},[50,4686,4687],{},"  - name: tags\n",[50,4689,4690],{"class":52,"line":1677},[50,4691,4692],{},"    label: Tags\n",[50,4694,4695],{"class":52,"line":1705},[50,4696,4697],{},"    type: select\n",[50,4699,4700],{"class":52,"line":1710},[50,4701,4677],{},[50,4703,4704],{"class":52,"line":1740},[50,4705,4706],{},"    creatable: true\n",[50,4708,4709],{"class":52,"line":1745},[50,4710,4711],{},"    multiple: true\n",[50,4713,4714],{"class":52,"line":1753},[50,4715,4716],{},"    values: [ Security, Home Lab, N8N, Telegram Bot, Ubuntu, Development, LLM ]\n",[50,4718,4719],{"class":52,"line":1766},[50,4720,4721],{},"  - name: draft\n",[50,4723,4724],{"class":52,"line":1778},[50,4725,4726],{},"    label: Draft\n",[50,4728,4729],{"class":52,"line":1786},[50,4730,4731],{},"    type: boolean\n",[50,4733,4734],{"class":52,"line":1792},[50,4735,4736],{},"    default: false\n",[50,4738,4739],{"class":52,"line":1797},[50,4740,4741],{},"  - name: image\n",[50,4743,4744],{"class":52,"line":1802},[50,4745,4746],{},"    label: Banner Image\n",[50,4748,4749],{"class":52,"line":1819},[50,4750,4751],{},"    type: image\n",[50,4753,4754],{"class":52,"line":1832},[50,4755,4756],{},"  - name: prev\n",[50,4758,4759],{"class":52,"line":1843},[50,4760,4761],{},"    label: Previous Post\n",[50,4763,4764],{"class":52,"line":1854},[50,4765,4643],{},[50,4767,4768],{"class":52,"line":1864},[50,4769,4770],{},"    description: Link to previous post\n",[50,4772,4773],{"class":52,"line":1881},[50,4774,4775],{},"  - name: next\n",[50,4777,4778],{"class":52,"line":1894},[50,4779,4780],{},"    label: Next Post\n",[50,4782,4783],{"class":52,"line":1924},[50,4784,4643],{},[50,4786,4787],{"class":52,"line":1929},[50,4788,4789],{},"    description: Link to next post\n",[50,4791,4792],{"class":52,"line":1947},[50,4793,4794],{},"  - name: recommends\n",[50,4796,4797],{"class":52,"line":1964},[50,4798,4799],{},"    label: Recommended Posts\n",[50,4801,4802],{"class":52,"line":1969},[50,4803,4697],{},[50,4805,4806],{"class":52,"line":1998},[50,4807,4677],{},[50,4809,4810],{"class":52,"line":2022},[50,4811,4706],{},[50,4813,4814],{"class":52,"line":2027},[50,4815,4711],{},[50,4817,4818],{"class":52,"line":2034},[50,4819,4820],{},"  - name: body\n",[50,4822,4823],{"class":52,"line":2042},[50,4824,4825],{},"    label: Body\n",[50,4827,4828],{"class":52,"line":2050},[50,4829,4830],{},"    type: rich-text\n",[1153,4832,4833],{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":45,"searchDepth":124,"depth":124,"links":4835},[4836,4837,4838,4839],{"id":4447,"depth":124,"text":4448},{"id":4493,"depth":124,"text":4494},{"id":4520,"depth":124,"text":4521},{"id":4546,"depth":124,"text":4546},"2025-08-30T00:00:00.000Z","แนะนำเครื่องมือสำหรับการจัดการ content สำหรับเว็บไซต์ประเภท static site",{},"First Time With PageCMS","/blogs/2025-08-30-pagecms-opensource",[4846],"ubuntu-pro",{"title":4442,"description":4841},{"loc":4844},"blogs/2025-08-30-pagecms-opensource",[1195],"MZ4Y8-V6-Fdbgm6vfDn-7b9FA6k4JUtESmz1JaseY8g",{"id":4853,"title":4854,"body":4855,"date":5419,"description":5420,"draft":1185,"extension":1186,"meta":5421,"navigation":137,"next":1188,"ogTitle":5422,"path":5423,"pin":1185,"prev":1188,"recommends":1188,"seo":5424,"sitemap":5425,"stem":5426,"tags":5427,"__hash__":5428},"content/blogs/2025-11-03-dirsearch-uv.md","ติดตั้ง dirsearch ด้วย uv แล้วใช้งานไม่ได้",{"type":7,"value":4856,"toc":5417},[4857,4860,4879,4882,5091,5094,5105,5120,5411,5414],[15,4858,4859],{},"หากทำการติดตั้ง dirsearch ด้วยเครื่องมือ",[40,4861,4863],{"className":42,"code":4862,"language":44,"meta":45,"style":45},"uv tool install dirsearch==0.4.3\n",[47,4864,4865],{"__ignoreMap":45},[50,4866,4867,4869,4871,4873,4876],{"class":52,"line":53},[50,4868,20],{"class":56},[50,4870,260],{"class":60},[50,4872,61],{"class":60},[50,4874,4875],{"class":60}," dirsearch==",[50,4877,4878],{"class":654},"0.4.3\n",[15,4880,4881],{},"จะเจอกับ error",[40,4883,4885],{"className":42,"code":4884,"language":44,"meta":45,"style":45},"PS C:\\Users\\robin> dirsearch --version\nTraceback (most recent call last):\n  File \"\u003Cfrozen runpy>\", line 198, in _run_module_as_main\n  File \"\u003Cfrozen runpy>\", line 88, in _run_code\n  File \"C:\\Users\\robin\\.local\\bin\\dirsearch.exe\\__main__.py\", line 4, in \u003Cmodule>\n    from dirsearch.dirsearch import main\n  File \"C:\\Users\\robin\\AppData\\Roaming\\uv\\tools\\dirsearch\\Lib\\site-packages\\dirsearch\\dirsearch.py\", line 23, in \u003Cmodule>\n    from pkg_resources import DistributionNotFound, VersionConflict\nModuleNotFoundError: No module named 'pkg_resources'\n",[47,4886,4887,4918,4938,4963,4985,5014,5028,5056,5071],{"__ignoreMap":45},[50,4888,4889,4892,4895,4898,4901,4904,4907,4910,4912,4915],{"class":52,"line":53},[50,4890,4891],{"class":56},"PS",[50,4893,4894],{"class":60}," C:",[50,4896,4897],{"class":2531},"\\U",[50,4899,4900],{"class":60},"sers",[50,4902,4903],{"class":2531},"\\r",[50,4905,4906],{"class":60},"obi",[50,4908,4909],{"class":799},"n",[50,4911,1418],{"class":88},[50,4913,4914],{"class":60}," dirsearch",[50,4916,4917],{"class":81}," --version\n",[50,4919,4920,4923,4926,4929,4932,4935],{"class":52,"line":124},[50,4921,4922],{"class":56},"Traceback",[50,4924,4925],{"class":799}," (most ",[50,4927,4928],{"class":60},"recent",[50,4930,4931],{"class":60}," call",[50,4933,4934],{"class":60}," last",[50,4936,4937],{"class":799},"):\n",[50,4939,4940,4943,4945,4948,4950,4952,4955,4958,4960],{"class":52,"line":134},[50,4941,4942],{"class":56},"  File",[50,4944,1258],{"class":390},[50,4946,4947],{"class":60},"\u003Cfrozen runpy>",[50,4949,830],{"class":390},[50,4951,871],{"class":60},[50,4953,4954],{"class":60}," line",[50,4956,4957],{"class":60}," 198,",[50,4959,3750],{"class":60},[50,4961,4962],{"class":60}," _run_module_as_main\n",[50,4964,4965,4967,4969,4971,4973,4975,4977,4980,4982],{"class":52,"line":141},[50,4966,4942],{"class":56},[50,4968,1258],{"class":390},[50,4970,4947],{"class":60},[50,4972,830],{"class":390},[50,4974,871],{"class":60},[50,4976,4954],{"class":60},[50,4978,4979],{"class":60}," 88,",[50,4981,3750],{"class":60},[50,4983,4984],{"class":60}," _run_code\n",[50,4986,4987,4989,4991,4994,4996,4998,5000,5003,5005,5007,5010,5012],{"class":52,"line":147},[50,4988,4942],{"class":56},[50,4990,1258],{"class":390},[50,4992,4993],{"class":60},"C:\\Users\\robin\\.local\\bin\\dirsearch.exe\\__main__.py",[50,4995,830],{"class":390},[50,4997,871],{"class":60},[50,4999,4954],{"class":60},[50,5001,5002],{"class":60}," 4,",[50,5004,3750],{"class":60},[50,5006,1941],{"class":88},[50,5008,5009],{"class":60},"modul",[50,5011,3542],{"class":799},[50,5013,3545],{"class":88},[50,5015,5016,5019,5022,5025],{"class":52,"line":214},[50,5017,5018],{"class":56},"    from",[50,5020,5021],{"class":60}," dirsearch.dirsearch",[50,5023,5024],{"class":60}," import",[50,5026,5027],{"class":60}," main\n",[50,5029,5030,5032,5034,5037,5039,5041,5043,5046,5048,5050,5052,5054],{"class":52,"line":219},[50,5031,4942],{"class":56},[50,5033,1258],{"class":390},[50,5035,5036],{"class":60},"C:\\Users\\robin\\AppData\\Roaming\\uv\\tools\\dirsearch\\Lib\\site-packages\\dirsearch\\dirsearch.py",[50,5038,830],{"class":390},[50,5040,871],{"class":60},[50,5042,4954],{"class":60},[50,5044,5045],{"class":60}," 23,",[50,5047,3750],{"class":60},[50,5049,1941],{"class":88},[50,5051,5009],{"class":60},[50,5053,3542],{"class":799},[50,5055,3545],{"class":88},[50,5057,5058,5060,5063,5065,5068],{"class":52,"line":225},[50,5059,5018],{"class":56},[50,5061,5062],{"class":60}," pkg_resources",[50,5064,5024],{"class":60},[50,5066,5067],{"class":60}," DistributionNotFound,",[50,5069,5070],{"class":60}," VersionConflict\n",[50,5072,5073,5076,5079,5081,5084,5086,5089],{"class":52,"line":541},[50,5074,5075],{"class":56},"ModuleNotFoundError:",[50,5077,5078],{"class":60}," No",[50,5080,3768],{"class":60},[50,5082,5083],{"class":60}," named",[50,5085,391],{"class":390},[50,5087,5088],{"class":60},"pkg_resources",[50,5090,397],{"class":390},[15,5092,5093],{},"สำหรับวิธีการแก้ไข ให้ติดตั้งใหม่ด้วย",[2644,5095,5096],{},[15,5097,5098,5099],{},"จำเป็นต้องมี git cli ด้วยนะครับ (windows: ",[18,5100,5101],{},[5102,5103,5104],"em",{},"winget install --id Git.Git -e --source winget)",[40,5106,5108],{"className":42,"code":5107,"language":44,"meta":45,"style":45},"uv tool install git+https://github.com/maurosoria/dirsearch\n",[47,5109,5110],{"__ignoreMap":45},[50,5111,5112,5114,5116,5118],{"class":52,"line":53},[50,5113,20],{"class":56},[50,5115,260],{"class":60},[50,5117,61],{"class":60},[50,5119,305],{"class":60},[40,5121,5123],{"className":42,"code":5122,"language":44,"meta":45,"style":45},"PS C:\\Users\\robin> uv tool install git+https://github.com/maurosoria/dirsearch\n    Updated https://github.com/maurosoria/dirsearch (70a763556e5dd894e1eeb2e62f77d83cb3fc5603)\nResolved 35 packages in 1.06s\n      Built dirsearch @ git+https://github.com/maurosoria/dirsearch@70a763556e5dd894e1eeb2e62f77d83cb3fc5603\nPrepared 13 packages in 1.95s\nUninstalled 3 packages in 34ms\nInstalled 14 packages in 242ms\n + anyio==4.11.0\n - chardet==5.2.0\n + defusedcsv==3.0.0\n - dirsearch==0.4.3\n + dirsearch==0.4.3 (from git+https://github.com/maurosoria/dirsearch@70a763556e5dd894e1eeb2e62f77d83cb3fc5603)\n + h11==0.16.0\n + httpcore==1.0.9\n + httpx==0.28.1\n + httpx-ntlm==1.4.0\n + mysql-connector-python==9.5.0\n + psycopg==3.2.12\n + psycopg-binary==3.2.12\n - pyparsing==3.2.5\n + requests-toolbelt==1.0.0\n + setuptools==80.9.0\n + sniffio==1.3.1\n + tzdata==2025.2\n",[47,5124,5125,5152,5163,5179,5192,5207,5222,5237,5247,5257,5267,5275,5292,5302,5312,5322,5332,5342,5352,5361,5371,5381,5391,5401],{"__ignoreMap":45},[50,5126,5127,5129,5131,5133,5135,5137,5139,5141,5143,5146,5148,5150],{"class":52,"line":53},[50,5128,4891],{"class":56},[50,5130,4894],{"class":60},[50,5132,4897],{"class":2531},[50,5134,4900],{"class":60},[50,5136,4903],{"class":2531},[50,5138,4906],{"class":60},[50,5140,4909],{"class":799},[50,5142,1418],{"class":88},[50,5144,5145],{"class":60}," uv",[50,5147,260],{"class":60},[50,5149,61],{"class":60},[50,5151,305],{"class":60},[50,5153,5154,5157,5160],{"class":52,"line":124},[50,5155,5156],{"class":56},"    Updated",[50,5158,5159],{"class":60}," https://github.com/maurosoria/dirsearch",[50,5161,5162],{"class":799}," (70a763556e5dd894e1eeb2e62f77d83cb3fc5603)\n",[50,5164,5165,5168,5171,5174,5176],{"class":52,"line":134},[50,5166,5167],{"class":56},"Resolved",[50,5169,5170],{"class":654}," 35",[50,5172,5173],{"class":60}," packages",[50,5175,3750],{"class":60},[50,5177,5178],{"class":60}," 1.06s\n",[50,5180,5181,5184,5186,5189],{"class":52,"line":141},[50,5182,5183],{"class":56},"      Built",[50,5185,4914],{"class":60},[50,5187,5188],{"class":60}," @",[50,5190,5191],{"class":60}," git+https://github.com/maurosoria/dirsearch@70a763556e5dd894e1eeb2e62f77d83cb3fc5603\n",[50,5193,5194,5197,5200,5202,5204],{"class":52,"line":147},[50,5195,5196],{"class":56},"Prepared",[50,5198,5199],{"class":654}," 13",[50,5201,5173],{"class":60},[50,5203,3750],{"class":60},[50,5205,5206],{"class":60}," 1.95s\n",[50,5208,5209,5212,5215,5217,5219],{"class":52,"line":214},[50,5210,5211],{"class":56},"Uninstalled",[50,5213,5214],{"class":654}," 3",[50,5216,5173],{"class":60},[50,5218,3750],{"class":60},[50,5220,5221],{"class":60}," 34ms\n",[50,5223,5224,5227,5230,5232,5234],{"class":52,"line":219},[50,5225,5226],{"class":56},"Installed",[50,5228,5229],{"class":654}," 14",[50,5231,5173],{"class":60},[50,5233,3750],{"class":60},[50,5235,5236],{"class":60}," 242ms\n",[50,5238,5239,5241,5244],{"class":52,"line":225},[50,5240,1986],{"class":56},[50,5242,5243],{"class":60}," anyio==",[50,5245,5246],{"class":654},"4.11.0\n",[50,5248,5249,5251,5254],{"class":52,"line":541},[50,5250,1726],{"class":56},[50,5252,5253],{"class":60}," chardet==",[50,5255,5256],{"class":654},"5.2.0\n",[50,5258,5259,5261,5264],{"class":52,"line":551},[50,5260,1986],{"class":56},[50,5262,5263],{"class":60}," defusedcsv==",[50,5265,5266],{"class":654},"3.0.0\n",[50,5268,5269,5271,5273],{"class":52,"line":556},[50,5270,1726],{"class":56},[50,5272,4875],{"class":60},[50,5274,4878],{"class":654},[50,5276,5277,5279,5281,5284,5287,5290],{"class":52,"line":562},[50,5278,1986],{"class":56},[50,5280,4875],{"class":60},[50,5282,5283],{"class":654},"0.4.3",[50,5285,5286],{"class":799}," (from ",[50,5288,5289],{"class":60},"git+https://github.com/maurosoria/dirsearch@70a763556e5dd894e1eeb2e62f77d83cb3fc5603",[50,5291,838],{"class":799},[50,5293,5294,5296,5299],{"class":52,"line":575},[50,5295,1986],{"class":56},[50,5297,5298],{"class":60}," h11==",[50,5300,5301],{"class":654},"0.16.0\n",[50,5303,5304,5306,5309],{"class":52,"line":580},[50,5305,1986],{"class":56},[50,5307,5308],{"class":60}," httpcore==",[50,5310,5311],{"class":654},"1.0.9\n",[50,5313,5314,5316,5319],{"class":52,"line":586},[50,5315,1986],{"class":56},[50,5317,5318],{"class":60}," httpx==",[50,5320,5321],{"class":654},"0.28.1\n",[50,5323,5324,5326,5329],{"class":52,"line":1511},[50,5325,1986],{"class":56},[50,5327,5328],{"class":60}," httpx-ntlm==",[50,5330,5331],{"class":654},"1.4.0\n",[50,5333,5334,5336,5339],{"class":52,"line":1524},[50,5335,1986],{"class":56},[50,5337,5338],{"class":60}," mysql-connector-python==",[50,5340,5341],{"class":654},"9.5.0\n",[50,5343,5344,5346,5349],{"class":52,"line":1535},[50,5345,1986],{"class":56},[50,5347,5348],{"class":60}," psycopg==",[50,5350,5351],{"class":654},"3.2.12\n",[50,5353,5354,5356,5359],{"class":52,"line":1546},[50,5355,1986],{"class":56},[50,5357,5358],{"class":60}," psycopg-binary==",[50,5360,5351],{"class":654},[50,5362,5363,5365,5368],{"class":52,"line":1558},[50,5364,1726],{"class":56},[50,5366,5367],{"class":60}," pyparsing==",[50,5369,5370],{"class":654},"3.2.5\n",[50,5372,5373,5375,5378],{"class":52,"line":1564},[50,5374,1986],{"class":56},[50,5376,5377],{"class":60}," requests-toolbelt==",[50,5379,5380],{"class":654},"1.0.0\n",[50,5382,5383,5385,5388],{"class":52,"line":1621},[50,5384,1986],{"class":56},[50,5386,5387],{"class":60}," setuptools==",[50,5389,5390],{"class":654},"80.9.0\n",[50,5392,5393,5395,5398],{"class":52,"line":1666},[50,5394,1986],{"class":56},[50,5396,5397],{"class":60}," sniffio==",[50,5399,5400],{"class":654},"1.3.1\n",[50,5402,5403,5405,5408],{"class":52,"line":1671},[50,5404,1986],{"class":56},[50,5406,5407],{"class":60}," tzdata==",[50,5409,5410],{"class":654},"2025.2\n",[15,5412,5413],{},"เพียงเท่านี้ก็จะสามารถใช้งานได้แล้วครับ",[1153,5415,5416],{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .snOyU, html code.shiki .snOyU{--shiki-light:#F76D47;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sicAX, html code.shiki .sicAX{--shiki-light:#90A4AE;--shiki-default:#56B6C2;--shiki-dark:#79B8FF}html pre.shiki code .sZDfs, html code.shiki .sZDfs{--shiki-light:#90A4AE;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sbGrh, html code.shiki .sbGrh{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F97583}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}",{"title":45,"searchDepth":124,"depth":124,"links":5418},[],"2025-11-03T00:00:00.000Z","แก้ปัญหาติดตั้ง dirsearch ด้วย uv แล้วใช้งานไม่ได้",{},"Dirsearch with UV","/blogs/2025-11-03-dirsearch-uv",{"title":4854,"description":5420},{"loc":5423},"blogs/2025-11-03-dirsearch-uv",[1195],"wg9DvOylgKVxZWjmRSV9UK150jcI1OwsrQLf4e4O5b4",{"id":5430,"title":5431,"body":5432,"date":5599,"description":5600,"draft":1185,"extension":1186,"meta":5601,"navigation":137,"next":1188,"ogTitle":5602,"path":5603,"pin":1185,"prev":1188,"recommends":1188,"seo":5604,"sitemap":5605,"stem":5606,"tags":5607,"__hash__":5608},"content/blogs/2025-11-06-environment-mac-keychains.md","วิธีเก็บ Environment บน Mac Keychains แบบปลอดภัยมากขึ้น",{"type":7,"value":5433,"toc":5597},[5434,5437,5440,5476,5481,5484,5487,5517,5520,5562,5573,5576,5594],[15,5435,5436],{},"โดยวิธีการนี้ค่าจะถูกนำไปเก็บเอาไว้ใน keychains ของ macos ซึ่งจะปลอดภัยกว่าการเก็บไว้ใน .zshrc, .bashrc file โดยตรง",[15,5438,5439],{},"วิธีการ",[40,5441,5443],{"className":42,"code":5442,"language":44,"meta":45,"style":45},"security add-generic-password -a \"$USER\" -s 'name_of_your_key' -w\n",[47,5444,5445],{"__ignoreMap":45},[50,5446,5447,5450,5453,5456,5458,5461,5463,5466,5468,5471,5473],{"class":52,"line":53},[50,5448,5449],{"class":56},"security",[50,5451,5452],{"class":60}," add-generic-password",[50,5454,5455],{"class":81}," -a",[50,5457,1258],{"class":390},[50,5459,5460],{"class":1597},"$USER",[50,5462,830],{"class":390},[50,5464,5465],{"class":81}," -s",[50,5467,391],{"class":390},[50,5469,5470],{"class":60},"name_of_your_key",[50,5472,989],{"class":390},[50,5474,5475],{"class":81}," -w\n",[2644,5477,5478],{},[15,5479,5480],{},"name_of_your_key ตั้งเป็น key ตามที่ต้องการจะเก็บ",[15,5482,5483],{},"จากนั้น application จะมีการแสดง Prompt `password data for new item:` โดยให้ใส่ value ของ key ที่ต้องการเก็บได้เลย",[15,5485,5486],{},"และใช้คำสั่งนี้เพื่อดึงค่าจาก keychains ออกมา",[40,5488,5490],{"className":42,"code":5489,"language":44,"meta":45,"style":45},"security find-generic-password -a \"$USER\" -s 'name_of_your_key' -w\n",[47,5491,5492],{"__ignoreMap":45},[50,5493,5494,5496,5499,5501,5503,5505,5507,5509,5511,5513,5515],{"class":52,"line":53},[50,5495,5449],{"class":56},[50,5497,5498],{"class":60}," find-generic-password",[50,5500,5455],{"class":81},[50,5502,1258],{"class":390},[50,5504,5460],{"class":1597},[50,5506,830],{"class":390},[50,5508,5465],{"class":81},[50,5510,391],{"class":390},[50,5512,5470],{"class":60},[50,5514,989],{"class":390},[50,5516,5475],{"class":81},[15,5518,5519],{},"หากต้องการให้ default shell ของเรา load ค่าจาก envronment ดังกล่าวออกมา สามารถนำ",[40,5521,5523],{"className":42,"code":5522,"language":44,"meta":45,"style":45},"export NAME_OF_YOUR_KEY=$(security find-generic-password -a \"$USER\" -s \"name_of_your_key\" -w)\n",[47,5524,5525],{"__ignoreMap":45},[50,5526,5527,5529,5532,5534,5537,5539,5541,5543,5545,5547,5549,5551,5553,5555,5557,5560],{"class":52,"line":53},[50,5528,1498],{"class":1349},[50,5530,5531],{"class":1597}," NAME_OF_YOUR_KEY",[50,5533,813],{"class":812},[50,5535,5536],{"class":819},"$(",[50,5538,5449],{"class":56},[50,5540,5498],{"class":60},[50,5542,5455],{"class":81},[50,5544,1258],{"class":390},[50,5546,5460],{"class":1597},[50,5548,830],{"class":390},[50,5550,5465],{"class":81},[50,5552,1258],{"class":390},[50,5554,5470],{"class":60},[50,5556,830],{"class":390},[50,5558,5559],{"class":81}," -w",[50,5561,838],{"class":819},[15,5563,5564,5565,5568,5569,5572],{},"ไปใส่ใน default shell เช่น ",[47,5566,5567],{},"~/.zshrc",", ",[47,5570,5571],{},"~/.bashrc"," แล้ว reload ได้เลย ค่าดังกล่าวก็จะถูกดึงออกมาโดยอัตโนมัติ",[15,5574,5575],{},"วิธีการตรวจสอบว่าถูก Load เข้าไปไหม",[40,5577,5579],{"className":42,"code":5578,"language":44,"meta":45,"style":45},"printenv NAME_OF_YOUR_KEY\n# ถ้าถูกตรงนี้จะขึ้น Value มา\n",[47,5580,5581,5589],{"__ignoreMap":45},[50,5582,5583,5586],{"class":52,"line":53},[50,5584,5585],{"class":56},"printenv",[50,5587,5588],{"class":60}," NAME_OF_YOUR_KEY\n",[50,5590,5591],{"class":52,"line":124},[50,5592,5593],{"class":120},"# ถ้าถูกตรงนี้จะขึ้น Value มา\n",[1153,5595,5596],{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sLHrO, html code.shiki .sLHrO{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sOHk9, html code.shiki .sOHk9{--shiki-light:#9C3EDA;--shiki-default:#C678DD;--shiki-dark:#F97583}html pre.shiki code .sMTEB, html code.shiki .sMTEB{--shiki-light:#39ADB5;--shiki-default:#56B6C2;--shiki-dark:#F97583}html pre.shiki code .stlKB, html code.shiki .stlKB{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sDKbk, html code.shiki .sDKbk{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}",{"title":45,"searchDepth":124,"depth":124,"links":5598},[],"2025-11-06T00:00:00.000Z","เก็บ sensitive environment บน Mac",{},"MacOS Environment Settings","/blogs/2025-11-06-environment-mac-keychains",{"title":5431,"description":5600},{"loc":5603},"blogs/2025-11-06-environment-mac-keychains",[1195],"-pYnFQz6U4BZUIgFdUKyptfRbSeBLOCv0ndErD0NRkg",{"id":5610,"title":5611,"body":5612,"date":5752,"description":5753,"draft":1185,"extension":1186,"meta":5754,"navigation":137,"next":1188,"ogTitle":5755,"path":5756,"pin":1185,"prev":1188,"recommends":1188,"seo":5757,"sitemap":5758,"stem":5759,"tags":5760,"__hash__":5761},"content/blogs/2025-12-28-powerlevel10k-spaceship.md","ย้ายจาก Powerlevel10k มาใช้ Spaceship",{"type":7,"value":5613,"toc":5749},[5614,5622,5625,5627,5694,5697,5730,5743,5746],[15,5615,5616,5617,5621],{},"ช่วงหลัง ๆ มาผมรู้สึกว่าเริ่มเบื่อกับ Terminal ที่กำลังใช้อยู่ (zsh+oh-my-zsh+powerlevel10k) เลยลองหา ๆ ดูว่ามีทางเลือกอื่นให้ติดตั้งอีกมั้ย แล้วก็ได้มาเจอกับ ",[23,5618,5619],{"href":5619,"rel":5620},"https://spaceship-prompt.sh/",[27]," ซึ่งสามารถลงเป็น add-on บน zsh ได้เลย (แทนที่ powerlevel10k)",[15,5623,5624],{},"จากที่ได้ลองใช้มาสักพักนึงรู้สึกลื่นนนกว่ามาก",[10,5626,2785],{"id":2785},[40,5628,5630],{"className":42,"code":5629,"language":44,"meta":45,"style":45},"# Clone the repo\ngit clone https://github.com/spaceship-prompt/spaceship-prompt.git \"$ZSH_CUSTOM/themes/spaceship-prompt\" --depth=1\n\n# Link the theme\nln -s \"$ZSH_CUSTOM/themes/spaceship-prompt/spaceship.zsh-theme\" \"$ZSH_CUSTOM/themes/spaceship.zsh-theme\"\n",[47,5631,5632,5637,5660,5664,5669],{"__ignoreMap":45},[50,5633,5634],{"class":52,"line":53},[50,5635,5636],{"class":120},"# Clone the repo\n",[50,5638,5639,5641,5644,5647,5649,5652,5655,5657],{"class":52,"line":124},[50,5640,2670],{"class":56},[50,5642,5643],{"class":60}," clone",[50,5645,5646],{"class":60}," https://github.com/spaceship-prompt/spaceship-prompt.git",[50,5648,1258],{"class":390},[50,5650,5651],{"class":1597},"$ZSH_CUSTOM",[50,5653,5654],{"class":60},"/themes/spaceship-prompt",[50,5656,830],{"class":390},[50,5658,5659],{"class":81}," --depth=1\n",[50,5661,5662],{"class":52,"line":134},[50,5663,138],{"emptyLinePlaceholder":137},[50,5665,5666],{"class":52,"line":141},[50,5667,5668],{"class":120},"# Link the theme\n",[50,5670,5671,5674,5676,5678,5680,5683,5685,5687,5689,5692],{"class":52,"line":147},[50,5672,5673],{"class":56},"ln",[50,5675,5465],{"class":81},[50,5677,1258],{"class":390},[50,5679,5651],{"class":1597},[50,5681,5682],{"class":60},"/themes/spaceship-prompt/spaceship.zsh-theme",[50,5684,830],{"class":390},[50,5686,1258],{"class":390},[50,5688,5651],{"class":1597},[50,5690,5691],{"class":60},"/themes/spaceship.zsh-theme",[50,5693,1325],{"class":390},[15,5695,5696],{},"จากนั้นสามารถแก้ไข",[40,5698,5700],{"className":42,"code":5699,"language":44,"meta":45,"style":45},"# .zshrc แก้ไข theme ที่ใช้อยู่\n\n#ZSH_THEME=\"powerlevel10k/powerlevel10k\"\nZSH_THEME=\"spaceship\"\n",[47,5701,5702,5707,5711,5716],{"__ignoreMap":45},[50,5703,5704],{"class":52,"line":53},[50,5705,5706],{"class":120},"# .zshrc แก้ไข theme ที่ใช้อยู่\n",[50,5708,5709],{"class":52,"line":124},[50,5710,138],{"emptyLinePlaceholder":137},[50,5712,5713],{"class":52,"line":134},[50,5714,5715],{"class":120},"#ZSH_THEME=\"powerlevel10k/powerlevel10k\"\n",[50,5717,5718,5721,5723,5725,5728],{"class":52,"line":141},[50,5719,5720],{"class":1597},"ZSH_THEME",[50,5722,813],{"class":812},[50,5724,830],{"class":390},[50,5726,5727],{"class":60},"spaceship",[50,5729,1325],{"class":390},[40,5731,5733],{"className":42,"code":5732,"language":44,"meta":45,"style":45},"source ~/.zshrc\n",[47,5734,5735],{"__ignoreMap":45},[50,5736,5737,5740],{"class":52,"line":53},[50,5738,5739],{"class":457},"source",[50,5741,5742],{"class":60}," ~/.zshrc\n",[15,5744,5745],{},"เรียบร้อยฮะ",[1153,5747,5748],{},"html pre.shiki code .sDKbk, html code.shiki .sDKbk{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sLHrO, html code.shiki .sLHrO{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#E1E4E8}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMTEB, html code.shiki .sMTEB{--shiki-light:#39ADB5;--shiki-default:#56B6C2;--shiki-dark:#F97583}html pre.shiki code .sJZfL, html code.shiki .sJZfL{--shiki-light:#6182B8;--shiki-default:#56B6C2;--shiki-dark:#79B8FF}",{"title":45,"searchDepth":124,"depth":124,"links":5750},[5751],{"id":2785,"depth":124,"text":2785},"2025-12-28T00:00:00.000Z","Note วิธีการติดตั้ง Spaceship บน Macos",{},"Moving from Powerlevel10k to Spaceship","/blogs/2025-12-28-powerlevel10k-spaceship",{"title":5611,"description":5753},{"loc":5756},"blogs/2025-12-28-powerlevel10k-spaceship",[1195],"k3hbYPncsBdblTN3iqrLHAbA6C1dexqidSvDq0LDAKk",{"id":5763,"title":5764,"body":5765,"date":5752,"description":6057,"draft":1185,"extension":1186,"meta":6058,"navigation":137,"next":1188,"ogTitle":6059,"path":6060,"pin":1185,"prev":1188,"recommends":1188,"seo":6061,"sitemap":6062,"stem":6063,"tags":6064,"__hash__":6065},"content/blogs/2025-12-28-zshrc-config-folder.md","ย้าย .zshrc ไปยัง .config folder",{"type":7,"value":5766,"toc":6052},[5767,5770,5773,5823,5826,5862,5865,5869,5872,5900,5903,5907,5910,5917,5931,5934,5980,5983,5995,5998,6004,6043,6049],[35,5768,5769],{"id":5769},"วิธีการตั้งค่า",[15,5771,5772],{},"Note วิธีย้าย .zshrc เข้าไปยัง .config folder บน macos เพื่อให้ง่ายต่อการ backup",[40,5774,5776],{"className":42,"code":5775,"language":44,"meta":45,"style":45},"# Create new folder\nmkdir -p ~/.config/zsh\n\n# Move config\nmv ~/.zshrc ~/.config/zsh/.zshrc\nmv ~/.zsh_history ~/.config/zsh/.zsh_history\n",[47,5777,5778,5783,5793,5797,5802,5813],{"__ignoreMap":45},[50,5779,5780],{"class":52,"line":53},[50,5781,5782],{"class":120},"# Create new folder\n",[50,5784,5785,5788,5790],{"class":52,"line":124},[50,5786,5787],{"class":56},"mkdir",[50,5789,651],{"class":81},[50,5791,5792],{"class":60}," ~/.config/zsh\n",[50,5794,5795],{"class":52,"line":134},[50,5796,138],{"emptyLinePlaceholder":137},[50,5798,5799],{"class":52,"line":141},[50,5800,5801],{"class":120},"# Move config\n",[50,5803,5804,5807,5810],{"class":52,"line":147},[50,5805,5806],{"class":56},"mv",[50,5808,5809],{"class":60}," ~/.zshrc",[50,5811,5812],{"class":60}," ~/.config/zsh/.zshrc\n",[50,5814,5815,5817,5820],{"class":52,"line":214},[50,5816,5806],{"class":56},[50,5818,5819],{"class":60}," ~/.zsh_history",[50,5821,5822],{"class":60}," ~/.config/zsh/.zsh_history\n",[15,5824,5825],{},"จากนั้นแก้ไขไฟล์ .zshenv เพื่อเปลี่ยน working directory",[40,5827,5829],{"className":42,"code":5828,"language":44,"meta":45,"style":45},"nano ~/.zshenv\n\nexport ZDOTDIR=\"$HOME/.config/zsh\"\n",[47,5830,5831,5839,5843],{"__ignoreMap":45},[50,5832,5833,5836],{"class":52,"line":53},[50,5834,5835],{"class":56},"nano",[50,5837,5838],{"class":60}," ~/.zshenv\n",[50,5840,5841],{"class":52,"line":124},[50,5842,138],{"emptyLinePlaceholder":137},[50,5844,5845,5847,5850,5852,5854,5857,5860],{"class":52,"line":134},[50,5846,1498],{"class":1349},[50,5848,5849],{"class":1597}," ZDOTDIR",[50,5851,813],{"class":812},[50,5853,830],{"class":390},[50,5855,5856],{"class":1597},"$HOME",[50,5858,5859],{"class":60},"/.config/zsh",[50,5861,1325],{"class":390},[15,5863,5864],{},"ลองปิดเปิดใหม่เพื่อทดสอบว่า config ถูก load ถูกต้องมั้ย (ปิด terminal ไปเลยนะครับ)",[35,5866,5868],{"id":5867},"ป้องกันไม่ให้เอา-zsh_history-ขึ้น-git","ป้องกันไม่ให้เอา .zsh_history ขึ้น git",[15,5870,5871],{},"แนะนำให้สร้าง .gitignore แล้วเพิ่ม",[40,5873,5875],{"className":42,"code":5874,"language":44,"meta":45,"style":45},"# Ignore everything in zsh...\nzsh/*\n# ...Except .zshrc\n!zsh/.zshrc\n",[47,5876,5877,5882,5887,5892],{"__ignoreMap":45},[50,5878,5879],{"class":52,"line":53},[50,5880,5881],{"class":120},"# Ignore everything in zsh...\n",[50,5883,5884],{"class":52,"line":124},[50,5885,5886],{"class":56},"zsh/*\n",[50,5888,5889],{"class":52,"line":134},[50,5890,5891],{"class":120},"# ...Except .zshrc\n",[50,5893,5894,5897],{"class":52,"line":141},[50,5895,5896],{"class":88},"!",[50,5898,5899],{"class":56},"zsh/.zshrc\n",[15,5901,5902],{},"เพื่อให้ backup เฉพาะส่วนที่เป็น config ไว้เท่านั้นครับ เนื่องจากใน .zsh_history อาจจะมี secret ต่าง ๆ อยู่ได้",[35,5904,5906],{"id":5905},"ใช้งานร่วมกับ-gitleak-pre-commit","ใช้งานร่วมกับ gitleak + pre-commit",[15,5908,5909],{},"เพื่อเพิ่มความปลอดภัยอีกชั้น แนะนำให้ติด pre-commit hook เพื่อดักจับ secret (เช่น API Key, Token ต่าง ๆ) ก่อนที่เราจะเผลอ commit ลงไปใน git ครับ",[15,5911,5912,5913,5916],{},"เริ่มจากติดตั้ง ",[47,5914,5915],{},"pre-commit"," (หากยังไม่มี)",[40,5918,5920],{"className":42,"code":5919,"language":44,"meta":45,"style":45},"brew install pre-commit\n",[47,5921,5922],{"__ignoreMap":45},[50,5923,5924,5926,5928],{"class":52,"line":53},[50,5925,57],{"class":56},[50,5927,61],{"class":60},[50,5929,5930],{"class":60}," pre-commit\n",[15,5932,5933],{},"จากนั้นสร้างไฟล์ .pre-commit-config.yaml ไว้ที่ root directory ของโปรเจกต์ และกำหนด version ของ gitleaks เป็น v8.30.0",[40,5935,5938],{"className":42,"code":5936,"filename":5937,"language":44,"meta":45,"style":45},"repos:\n  - repo: https://github.com/gitleaks/gitleaks\n    rev: v8.30.0\n    hooks:\n      - id: gitleaks\n",".pre-commit-config.yaml",[47,5939,5940,5945,5956,5964,5969],{"__ignoreMap":45},[50,5941,5942],{"class":52,"line":53},[50,5943,5944],{"class":56},"repos:\n",[50,5946,5947,5950,5953],{"class":52,"line":124},[50,5948,5949],{"class":56},"  -",[50,5951,5952],{"class":60}," repo:",[50,5954,5955],{"class":60}," https://github.com/gitleaks/gitleaks\n",[50,5957,5958,5961],{"class":52,"line":134},[50,5959,5960],{"class":56},"    rev:",[50,5962,5963],{"class":60}," v8.30.0\n",[50,5965,5966],{"class":52,"line":141},[50,5967,5968],{"class":56},"    hooks:\n",[50,5970,5971,5974,5977],{"class":52,"line":147},[50,5972,5973],{"class":56},"      -",[50,5975,5976],{"class":60}," id:",[50,5978,5979],{"class":60}," gitleaks\n",[15,5981,5982],{},"สั่ง install hook เข้าไปใน git directory",[40,5984,5986],{"className":42,"code":5985,"language":44,"meta":45,"style":45},"pre-commit install\n",[47,5987,5988],{"__ignoreMap":45},[50,5989,5990,5992],{"class":52,"line":53},[50,5991,5915],{"class":56},[50,5993,5994],{"class":60}," install\n",[15,5996,5997],{},"ผลลัพธ์: หลังจากนี้ทุกครั้งที่เราพิมพ์คำสั่ง git commit ตัว pre-commit จะทำการเรียก Gitleaks มาสแกนไฟล์ที่เรากำลังจะ commit ให้โดยอัตโนมัติ ถ้าเจอ secret มันจะแจ้ง error และหยุดการ commit ให้ทันทีครับ",[15,5999,6000,6003],{},[5102,6001,6002],{},"เพิ่มเติม (Optional)","\nถ้าอยากให้บทความสมบูรณ์ขึ้น อาจจะปิดท้ายด้วยคำสั่งสำหรับ Test ดูครับ ทดสอบการทำงาน ลองสร้างไฟล์ที่มี Mock Secret ดูครับ",[40,6005,6007],{"className":42,"code":6006,"language":44,"meta":45,"style":45},"wget https://raw.githubusercontent.com/trufflesecurity/test_keys/refs/heads/main/keys\ngit add keys\ngit commit -m \"test secret\"\n",[47,6008,6009,6017,6026],{"__ignoreMap":45},[50,6010,6011,6014],{"class":52,"line":53},[50,6012,6013],{"class":56},"wget",[50,6015,6016],{"class":60}," https://raw.githubusercontent.com/trufflesecurity/test_keys/refs/heads/main/keys\n",[50,6018,6019,6021,6023],{"class":52,"line":124},[50,6020,2670],{"class":56},[50,6022,492],{"class":60},[50,6024,6025],{"class":60}," keys\n",[50,6027,6028,6030,6033,6036,6038,6041],{"class":52,"line":134},[50,6029,2670],{"class":56},[50,6031,6032],{"class":60}," commit",[50,6034,6035],{"class":81}," -m",[50,6037,1258],{"class":390},[50,6039,6040],{"class":60},"test secret",[50,6042,1325],{"class":390},[15,6044,6045],{},[2610,6046],{"alt":6047,"src":6048},"ตัวอย่าง","/images/2025-12-28-zshrc-config-folder/gitleak-demo.jpg",[1153,6050,6051],{},"html pre.shiki code .sDKbk, html code.shiki .sDKbk{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sOHk9, html code.shiki .sOHk9{--shiki-light:#9C3EDA;--shiki-default:#C678DD;--shiki-dark:#F97583}html pre.shiki code .sLHrO, html code.shiki .sLHrO{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#E1E4E8}html pre.shiki code .sMTEB, html code.shiki .sMTEB{--shiki-light:#39ADB5;--shiki-default:#56B6C2;--shiki-dark:#F97583}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sbGrh, html code.shiki .sbGrh{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F97583}",{"title":45,"searchDepth":124,"depth":124,"links":6053},[6054,6055,6056],{"id":5769,"depth":134,"text":5769},{"id":5867,"depth":134,"text":5868},{"id":5905,"depth":134,"text":5906},"ย้าย .zshrc เพื่อให้ง่ายต่อการ backup",{},"Moving the .zshrc to .config folder","/blogs/2025-12-28-zshrc-config-folder",{"title":5764,"description":6057},{"loc":6060},"blogs/2025-12-28-zshrc-config-folder",[1195],"iKFZQKdTxZcMKUFq1PPWqyrKypAeRH0qAumAOjH8JEQ",{"id":6067,"title":6068,"body":6069,"date":6227,"description":6228,"draft":1185,"extension":1186,"meta":6229,"navigation":137,"next":1188,"ogTitle":6230,"path":6231,"pin":1185,"prev":1188,"recommends":1188,"seo":6232,"sitemap":6233,"stem":6234,"tags":6235,"__hash__":6236},"content/blogs/2026-01-02-cli-macos-sips.md","ย่อรูปผ่าน CLI บน MacOS ด้วย sips",{"type":7,"value":6070,"toc":6224},[6071,6175,6178,6181,6201,6204,6221],[40,6072,6074],{"className":42,"code":6073,"language":44,"meta":45,"style":45},"sips - scriptable image processing system.\nThis tool is used to query or modify raster image files and ColorSync ICC profiles.\nIts functionality can also be used through the \"Image Events\" AppleScript suite.\n",[47,6075,6076,6095,6138],{"__ignoreMap":45},[50,6077,6078,6081,6083,6086,6089,6092],{"class":52,"line":53},[50,6079,6080],{"class":56},"sips",[50,6082,1726],{"class":60},[50,6084,6085],{"class":60}," scriptable",[50,6087,6088],{"class":60}," image",[50,6090,6091],{"class":60}," processing",[50,6093,6094],{"class":60}," system.\n",[50,6096,6097,6100,6102,6105,6108,6110,6113,6116,6119,6122,6124,6127,6129,6132,6135],{"class":52,"line":124},[50,6098,6099],{"class":56},"This",[50,6101,260],{"class":60},[50,6103,6104],{"class":60}," is",[50,6106,6107],{"class":60}," used",[50,6109,3576],{"class":60},[50,6111,6112],{"class":60}," query",[50,6114,6115],{"class":60}," or",[50,6117,6118],{"class":60}," modify",[50,6120,6121],{"class":60}," raster",[50,6123,6088],{"class":60},[50,6125,6126],{"class":60}," files",[50,6128,3712],{"class":60},[50,6130,6131],{"class":60}," ColorSync",[50,6133,6134],{"class":60}," ICC",[50,6136,6137],{"class":60}," profiles.\n",[50,6139,6140,6143,6146,6149,6152,6155,6157,6160,6162,6164,6167,6169,6172],{"class":52,"line":134},[50,6141,6142],{"class":56},"Its",[50,6144,6145],{"class":60}," functionality",[50,6147,6148],{"class":60}," can",[50,6150,6151],{"class":60}," also",[50,6153,6154],{"class":60}," be",[50,6156,6107],{"class":60},[50,6158,6159],{"class":60}," through",[50,6161,3648],{"class":60},[50,6163,1258],{"class":390},[50,6165,6166],{"class":60},"Image Events",[50,6168,830],{"class":390},[50,6170,6171],{"class":60}," AppleScript",[50,6173,6174],{"class":60}," suite.\n",[10,6176,6177],{"id":6177},"วิธีใช้งาน",[15,6179,6180],{},"To reduce JPEG quality (e.g., to 70%):",[40,6182,6184],{"className":42,"code":6183,"language":44,"meta":45,"style":45},"sips -s formatOptions 70 input.jpg\n",[47,6185,6186],{"__ignoreMap":45},[50,6187,6188,6190,6192,6195,6198],{"class":52,"line":53},[50,6189,6080],{"class":56},[50,6191,5465],{"class":81},[50,6193,6194],{"class":60}," formatOptions",[50,6196,6197],{"class":654}," 70",[50,6199,6200],{"class":60}," input.jpg\n",[15,6202,6203],{},"To resize the image (maintaining aspect ratio, max dimension 1024px):",[40,6205,6207],{"className":42,"code":6206,"language":44,"meta":45,"style":45},"sips -Z 1024 input.jpg\n",[47,6208,6209],{"__ignoreMap":45},[50,6210,6211,6213,6216,6219],{"class":52,"line":53},[50,6212,6080],{"class":56},[50,6214,6215],{"class":81}," -Z",[50,6217,6218],{"class":654}," 1024",[50,6220,6200],{"class":60},[1153,6222,6223],{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .snOyU, html code.shiki .snOyU{--shiki-light:#F76D47;--shiki-default:#D19A66;--shiki-dark:#79B8FF}",{"title":45,"searchDepth":124,"depth":124,"links":6225},[6226],{"id":6177,"depth":124,"text":6177},"2026-01-02T00:00:00.000Z","วิธีการย่อรูปบน macos ด้วย cli แบบไม่ต้องลงโปรแกรมเพิ่ม",{},"sips 101","/blogs/2026-01-02-cli-macos-sips",{"title":6068,"description":6228},{"loc":6231},"blogs/2026-01-02-cli-macos-sips",[1195],"bv5n0pnj1nuhSOs2bL2fDbf3vb3DbAOWNX4hg3vh9Ew",{"id":6238,"title":6239,"body":6240,"date":6345,"description":6346,"draft":1185,"extension":1186,"meta":6347,"navigation":137,"next":1188,"ogTitle":6346,"path":6348,"pin":1185,"prev":1188,"recommends":1188,"seo":6349,"sitemap":6350,"stem":6351,"tags":6352,"__hash__":6353},"content/blogs/2026-01-17-zshhistory.md","วิธีแก้ไข zsh_history เสียหาย",{"type":7,"value":6241,"toc":6341},[6242,6245,6248,6270,6273,6276,6279,6282,6335,6338],[35,6243,6244],{"id":6244},"ปัญหาที่เจอ",[15,6246,6247],{},"สำหรับชาว Dev ที่ใช้ ZSH อาจจะเคยเจอเหตุการณ์เปิด Terminal ขึ้นมาแล้วเจอ Error แจ้งเตือนเกี่ยวกับ History file พังแบบนี้ครับ",[40,6249,6251],{"className":42,"code":6250,"language":44,"meta":45,"style":45},"zsh: corrupt history file /home/pi/.zsh_history\n",[47,6252,6253],{"__ignoreMap":45},[50,6254,6255,6258,6261,6264,6267],{"class":52,"line":53},[50,6256,6257],{"class":56},"zsh:",[50,6259,6260],{"class":60}," corrupt",[50,6262,6263],{"class":60}," history",[50,6265,6266],{"class":60}," file",[50,6268,6269],{"class":60}," /home/pi/.zsh_history\n",[15,6271,6272],{},"ซึ่งปัญหานี้จะทำให้เราไม่สามารถกดลูกศรขึ้น-ลง เพื่อเรียกดูคำสั่งเก่า ๆ ที่เคยพิมพ์ไปได้ ซึ่งสาเหตุมักเกิดจากเครื่องดับไปดื้อ ๆ หรือโปรแกรมปิดไม่สมบูรณ์ครับ",[35,6274,6275],{"id":6275},"วิธีแก้ไข",[15,6277,6278],{},"วิธีแก้นั้นง่ายมากครับ ไม่ต้องลบ History ทิ้งทั้งหมด หลักการคือเราจะย้ายไฟล์ที่เสียไปพักไว้ก่อน แล้วใช้คำสั่ง strings เพื่อดึงเฉพาะข้อความที่อ่านรู้เรื่องกลับมาใส่ไฟล์ใหม่ครับ",[15,6280,6281],{},"พิมพ์ตามนี้ได้เลย หรือจะก๊อปไปวางทีละบรรทัดก็ได้ครับ",[40,6283,6285],{"className":42,"code":6284,"language":44,"meta":45,"style":45},"cd ~\nmv .zsh_history .zsh_history_bad\nstrings .zsh_history_bad > .zsh_history\nfc -R .zsh_history\nrm ~/.zsh_history_bad\n",[47,6286,6287,6294,6304,6317,6327],{"__ignoreMap":45},[50,6288,6289,6291],{"class":52,"line":53},[50,6290,458],{"class":457},[50,6292,6293],{"class":60}," ~\n",[50,6295,6296,6298,6301],{"class":52,"line":124},[50,6297,5806],{"class":56},[50,6299,6300],{"class":60}," .zsh_history",[50,6302,6303],{"class":60}," .zsh_history_bad\n",[50,6305,6306,6309,6312,6314],{"class":52,"line":134},[50,6307,6308],{"class":56},"strings",[50,6310,6311],{"class":60}," .zsh_history_bad",[50,6313,1959],{"class":88},[50,6315,6316],{"class":60}," .zsh_history\n",[50,6318,6319,6322,6325],{"class":52,"line":141},[50,6320,6321],{"class":457},"fc",[50,6323,6324],{"class":81}," -R",[50,6326,6316],{"class":60},[50,6328,6329,6332],{"class":52,"line":147},[50,6330,6331],{"class":56},"rm",[50,6333,6334],{"class":60}," ~/.zsh_history_bad\n",[15,6336,6337],{},"เท่านี้ zsh_history ของเราก็จะกลับมาใช้งานได้ปกติ กดดูคำสั่งย้อนหลังได้เหมือนเดิมแล้วครับ!",[1153,6339,6340],{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJZfL, html code.shiki .sJZfL{--shiki-light:#6182B8;--shiki-default:#56B6C2;--shiki-dark:#79B8FF}html pre.shiki code .sbGrh, html code.shiki .sbGrh{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F97583}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}",{"title":45,"searchDepth":124,"depth":124,"links":6342},[6343,6344],{"id":6244,"depth":134,"text":6244},{"id":6275,"depth":134,"text":6275},"2026-01-17T00:00:00.000Z","How to fix a corrupt zsh history file",{},"/blogs/2026-01-17-zshhistory",{"title":6239,"description":6346},{"loc":6348},"blogs/2026-01-17-zshhistory",[1195],"6qPf4edRLJO7GVqo4AM5yJbKTVrovf45MU2cFmepxbs",1774866660776]