<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><generator uri="http://jekyllrb.com" version="3.1.6">Jekyll</generator><link href="https://armno.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://armno.github.io/" rel="alternate" type="text/html" /><updated>2016-07-31T15:49:49+00:00</updated><id>https://armno.github.io/</id><title>Armno</title><entry><title>zsh syntax highlighter</title><link href="https://armno.github.io/2016/04/12/zsh-syntax-highlighter" rel="alternate" type="text/html" title="zsh syntax highlighter" /><published>2016-04-12T00:00:00+00:00</published><updated>2016-04-12T00:00:00+00:00</updated><id>https://armno.github.io/2016/04/12/zsh-syntax-highlighter</id><content type="html" xml:base="https://armno.github.io/2016/04/12/zsh-syntax-highlighter">&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;zsh-syntax-highlighting&lt;/code&gt; เป็น plugin ของ zsh ที่จะทำให้ command ที่เราพิมพ์ใน terminal มีสีสันขึ้นมาได้
เช่น จากแบบนี้&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/zsh-syntax-highlighter/before.png&quot; alt=&quot;ก่อน&quot; width=&quot;375&quot; height=&quot;74&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;เป็นแบบนี้&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/zsh-syntax-highlighter/after.png&quot; alt=&quot;หลัง&quot; width=&quot;370&quot; height=&quot;81&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;หรือถ้าพิมพ์ command ไม่ถูก (ไม่มีใน &lt;code class=&quot;highlighter-rouge&quot;&gt;$PATH&lt;/code&gt;) ก็จะเป็นตัวแดงๆ แบบนี้ (จริงๆ จะเป็นสีอะไรนั้นแล้วแต่ theme ของ iTerm อีกที)&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/zsh-syntax-highlighter/invalid-command.png&quot; alt=&quot;เวลาพิมพ์ผิด&quot; width=&quot;304&quot; height=&quot;76&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;ประโยชน์คือนอกจากจะสวยดีแล้ว ยังป้องกันการพิมพ์ command ผิดได้ดีมาก เพราะเราจะเห็นได้ทันทีตอนพิมพ์ถ้าหากเราพิมพ์ผิด จะได้แก้ก่อนกด enter ได้ทัน
ส่วน subcommand จะไม่มี highlight ให้นะครับ&lt;/p&gt;

&lt;h3 id=&quot;oh-my-zsh&quot;&gt;ใช้งานกับ &lt;code class=&quot;highlighter-rouge&quot;&gt;oh-my-zsh&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;zsh-syntax-highlighter&lt;/code&gt; นั้น ผมใช้งานร่วมกับ &lt;a href=&quot;https://armno.github.io/2013/09/11/setting-up-the-terminal&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;oh-my-zsh&lt;/code&gt;&lt;/a&gt; โดยวิธีการติดตั้งนั้นก็ตาม &lt;a href=&quot;https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/INSTALL.md#with-oh-my-zsh&quot;&gt;install.md ใน repo&lt;/a&gt;
ส่วนใครที่ไม่ได้ใช้ &lt;code class=&quot;highlighter-rouge&quot;&gt;oh-my-zsh&lt;/code&gt; ก็ใช้งานได้เหมือนกันจ้า&lt;/p&gt;

&lt;p&gt;ขั้นแรกก็ต้อง clone repo ของ &lt;code class=&quot;highlighter-rouge&quot;&gt;zsh-syntax-highlighting&lt;/code&gt; มาไว้ใน &lt;code class=&quot;highlighter-rouge&quot;&gt;oh-my-zsh&lt;/code&gt; ในเครื่องเราก่อน&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;git clone https://github.com/zsh-users/zsh-syntax-highlighting.git &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ZSH_CUSTOM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;~/.oh-my-zsh/custom&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/plugins/zsh-syntax-highlighting&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;จากนั้นเพิ่มชื่อ &lt;code class=&quot;highlighter-rouge&quot;&gt;zsh-syntax-highlighting&lt;/code&gt; ใน &lt;code class=&quot;highlighter-rouge&quot;&gt;plugins&lt;/code&gt; ในไฟล์ &lt;code class=&quot;highlighter-rouge&quot;&gt;~/.zshrc&lt;/code&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;plugins=(git colorize sublime vi-mode zsh-syntax-highlighting)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;สุดท้ายก็ source ไฟล์ &lt;code class=&quot;highlighter-rouge&quot;&gt;~/.zshrc&lt;/code&gt; ให้ config ใหม่นี้ทำงาน เป็นอันเสร็จพิธี&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt; ~/.zshrc&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Happy Songkran จ้า&lt;/p&gt;</content><category term="terminal" /><category term="zsh" /><category term="oh-my-zsh" /><summary>zsh-syntax-highlighting เป็น plugin ของ zsh ที่จะทำให้ command ที่เราพิมพ์ใน terminal มีสีสันขึ้นมาได้
เช่น จากแบบนี้</summary></entry><entry><title>วิธีการทำงานของ web browser</title><link href="https://armno.github.io/2016/01/28/how-web-browsers-work" rel="alternate" type="text/html" title="วิธีการทำงานของ web browser" /><published>2016-01-28T00:00:00+00:00</published><updated>2016-01-28T00:00:00+00:00</updated><id>https://armno.github.io/2016/01/28/how-web-browsers-work</id><content type="html" xml:base="https://armno.github.io/2016/01/28/how-web-browsers-work">&lt;p&gt;HTML, CSS กับ JavaScript เป็น 3 องค์ประกอบหลักของเว็บไซต์ทั่วๆ ไปที่เราเห็นกันอยู่
ส่วน web browser นั้นก็มีหน้าที่แปลง code ของทั้ง 3 ส่วนประกอบนั้น แสดงผลออกมาเป็นเว็บไซต์ให้เราได้ใช้งาน
ในฐานะคนทำเว็บ การเข้าใจหลักการทำงานของ web browser นั้นช่วยให้เข้าใจถึงที่มาที่ไปของสิ่งที่ปรากฏบนหน้าจอ
รวมถึงจะเป็นประโยชน์ในเรื่องการ optimize performance ของเว็บไซต์ด้วยครับ&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;#nerdalert&lt;/strong&gt; โพสต์นี้มีคำศัพท์เฉพาะ และทับศัพท์ค่อนข้างเยอะ แต่ผมก็จะพยายามทำให้เข้าใจง่ายที่สุดเท่าที่จะทำได้ ถ้าอ่านตรงไหนตรงไหนแล้วงงๆ comment ไว้ได้เลยครับ&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ในโพสต์นี้จะขอข้ามเรื่อง network connection ไป แต่จะเริ่มตั้งแต่การทำงานของ web browser
หลังจากได้รับ response เป็น code จาก server ไปจนถึงขั้นตอนสุดท้ายคือตัวเว็บไปปรากฏบนหน้าจอ
หรือพูดง่ายๆ ก็คือ ตั้งแต่ browser ได้รับ code &lt;code class=&quot;highlighter-rouge&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&lt;/span&gt;...&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/code&gt; จนถึงขั้นตอนการ render เว็บจ้า&lt;/p&gt;

&lt;p&gt;browser แต่ละตัวจะมีส่วนที่ทำหน้าที่แสดงผลเว็บไซต์ ที่เรียกว่า rendering engine หรือ layout engine
เช่น&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.chromium.org/blink&quot;&gt;Blink&lt;/a&gt; (Chrome, Opera)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Gecko&quot;&gt;Gecko&lt;/a&gt; (Firefox)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://webkit.org/&quot;&gt;WebKit&lt;/a&gt; (Safari)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/EdgeHTML&quot;&gt;EdgeHTML&lt;/a&gt; (Edge)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Trident_(layout_engine)&quot;&gt;Trident&lt;/a&gt; (Internet Explorer)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;rendering engine แต่ละตัวก็มีวิธีการแสดงผลที่แตกต่างกันในรายละเอียดเชิงลึก และคำศัพท์เฉพาะที่แต่ละ engine ใช้เรียกแต่ละขั้นตอน
แต่ภาพรวมแล้วขั้นตอนจะคล้ายกัน เป็นไปตาม &lt;a href=&quot;https://www.w3.org/TR/html5/infrastructure.html#infrastructure&quot;&gt;spec ของ W3C&lt;/a&gt; ซึ่งขั้นตอนหลักๆ มีอยู่ ดังนี้&lt;/p&gt;

&lt;h2 id=&quot;dom--cssom&quot;&gt;1. การสร้าง DOM กับ CSSOM&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.w3.org/TR/dom/&quot;&gt;DOM (Document Object Model)&lt;/a&gt; คือตัวแสดงคุณสมบัติและความสัมพันธ์ระหว่างแต่ละ object ในหน้าเว็บ (document)
ซึ่งก็จะประกอบไปด้วย properties กับ methods ของแต่ละ object พร้อมกับความสัมพันธ์กับ object อื่นๆ
เช่น object A เป็น parent ของ object B และขณะเดียวกันก็ทำให้ object B เป็น child ของ object A เช่นกัน&lt;/p&gt;

&lt;p&gt;ส่วน &lt;a href=&quot;https://www.w3.org/TR/cssom/&quot;&gt;CSSOM (CSS Object Model)&lt;/a&gt; นั้นก็เช่นเดียวกับ DOM แต่เป็นการสร้าง object model จาก CSS ของเว็บ
ที่มีทั้ง properties ที่เราคุ้นเคยกันใน CSS พร้อมกับความสัมพันธ์กับ object อื่นๆ ซึ่งก็คือคุณสมบัติ cascading ของ CSS ครับ&lt;/p&gt;

&lt;p&gt;การสร้าง object จาก code ที่ได้รับมาจาก server นั้น จะประกอบด้วย 2 ขั้นตอนย่อยคือ Tokenization กับ Parsing&lt;/p&gt;

&lt;h3 id=&quot;tokenization-lexical-analysis&quot;&gt;Tokenization (Lexical Analysis)&lt;/h3&gt;

&lt;p&gt;Tokenization ในโลก DOM คือกระบวนการที่บอกว่า code แต่ละตัว หรือแต่ละช่วงนั้น มันคือส่วนประกอบใดของ element
ตาม spec ของ W3C ตัวอย่างเช่น เรามี &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;button&amp;gt;Go&amp;lt;/button&amp;gt;&lt;/code&gt; ซึ่งถือเป็น 1 element
กระบวนการ tokenization คือการระบุว่า&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;button&amp;gt;&lt;/code&gt; คือ tag เปิด&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;G&lt;/code&gt; คือ character&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;o&lt;/code&gt; คือ character&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;/button&amp;gt;&lt;/code&gt; คือ tag ปิดของ element นี้&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;นั่นคือการระบุแต่ละส่วนของ code ออกมาเป็น token แยกออกเป็นตามประเภท นั่นเอง&lt;/p&gt;

&lt;h3 id=&quot;parsing-syntactic-analysis&quot;&gt;Parsing (Syntactic Analysis)&lt;/h3&gt;

&lt;p&gt;Parsing คือการนำ token แต่ละส่วนที่ได้จากขั้นตอน tokenization นำมาตรวจสอบกับ HTML syntax ว่ามีความหมายอย่างไร
และต้องเป็น object ชนิดไหน จากนั้นจึงสร้างเป็น object ซึ่งในโลกเว็บก็คือ DOM node กับ CSSOM node นั่นเอง
แต่ละ node ก็ประกอบด้วย property (attribute) กับ method ของ object นั้นๆ และ object ที่ได้เหล่านี้ก็จะถูกนำไปประกอบกับเป็น
tree structure ขึ้นมา&lt;/p&gt;

&lt;h3 id=&quot;dom--cssom-tree-construction&quot;&gt;DOM &amp;amp; CSSOM Tree construction&lt;/h3&gt;

&lt;p&gt;หลังจากที่เราได้ node แล้ว ก็มาถึงขั้นตอนการเชื่อมความสัมพันธ์ระหว่าง node นั่นคือการบอกว่า
node ไหน เป็น parent/child ของ node ไหน ซึ่งพอเราเชื่อมทุก node เข้าด้วยกัน
ก็จะได้โครงสร้างที่เป็น tree ของ node ขึ้นมา เรียกว่า DOM Tree กับ CSSOM Tree ครับ&lt;/p&gt;

&lt;p&gt;สำหรับ DOM นั้นจะค่อนข้างชัดเจน อย่างที่เห็นใน code หรือ element inspector ใน DevTools&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Awesome&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hi&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;DOM tree ก็จะออกมาแบบนี้&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/how-browsers-work/dom-tree.min.svg&quot; alt=&quot;รูป DOM tree&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;แต่ CSSOM นั้น ไม่มีโครงสร้างชัดเจนเหมือน DOM แต่ก็มีโครงสร้างเป็น tree เหมือนกัน
นั่นก็เพราะว่า CSS มีคุณสมบัติ cascading ที่ style ของ element บางส่วนจะ inherit มาจาก parent element
และทุก element ก็จะ inherit style ของ &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;body&amp;gt;&lt;/code&gt; และ &lt;code class=&quot;highlighter-rouge&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;&lt;/code&gt; มาเช่นกัน&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/how-browsers-work/inherited-styles.png&quot; alt=&quot;รูป inherit styles จาก devtools&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;สมมุติว่าเรามี CSS แบบนี้&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-css&quot; data-lang=&quot;css&quot;&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;CSSOM tree ก็จะออกมาประมาณนี้ครับ สังเกตว่าแท็ก &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;p&amp;gt;&lt;/code&gt; ปรากฎอยู่ใน CSSOM tree 2 ที่ด้วยกัน
style ที่แท็ก &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;p&amp;gt;&lt;/code&gt; แต่ละตัวจะได้รับ ก็ต่างกันไปตามโครงสร้างของ CSSOM tree
และจะถูกนำไปใช้ในขั้นตอนการ render ต่อไปครับ&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/how-browsers-work/cssom-tree.min.svg&quot; alt=&quot;รูป CSSOM Tree&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;หลังจากที่ได้ DOM Tree กับ CSSOM Tree แล้ว ก็จะถึงขั้นตอนต่อไปที่การสร้าง Render Tree&lt;/p&gt;

&lt;h2 id=&quot;render-tree&quot;&gt;2. สร้าง Render Tree&lt;/h2&gt;

&lt;p&gt;Render tree ถูกสร้างขึ้นมาจาก DOM tree และ CSSOM tree โดยที่ render tree จะประกอบด้วย
DOM element ที่จะถูก render บนหน้าจอ browser เท่านั้น ดังนั้นจะมีบาง element ที่อยู่ใน DOM tree
แต่ไม่อยู่ใน render tree คือ:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;element &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;head&amp;gt;&lt;/code&gt; และ element อื่นๆ ข้างใน&lt;/li&gt;
  &lt;li&gt;element &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;script&amp;gt;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;element ที่มี style &lt;code class=&quot;highlighter-rouge&quot;&gt;display: none&lt;/code&gt; กำหนดไว้อยู่&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;แต่ละ node ใน DOM tree ก็จะได้รับ style ต่างๆ จาก node ใน CSSOM tree ประกอบกันได้ render tree ขึ้นมาครับ&lt;/p&gt;

&lt;h2 id=&quot;layout&quot;&gt;3. Layout&lt;/h2&gt;

&lt;p&gt;Layout หรือ Reflow คือการที่ browser คำนวนหาขนาดและที่อยู่ของ element ใน render tree
ขนาดของ element ประกอบไปด้วย &lt;code class=&quot;highlighter-rouge&quot;&gt;width&lt;/code&gt; กับ &lt;code class=&quot;highlighter-rouge&quot;&gt;height&lt;/code&gt; ส่วนที่อยู่ตำแหน่งของ element นั้น
เป็นระบบ coordinate (x,y) ว่าอยู่ตรงไหนเทียบกับหน้าจอ (viewport) ซึ่งเป็น root element ใน render tree
ในขั้นตอนนี้ style ที่กำหนดตำแหน่งของ element จะถูกแปลงเป็นหน่วย absolute pixel เมื่อเทียบกับ viewport
เช่น “&lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;div id=&quot;logo&quot;&amp;gt;&lt;/code&gt; อยู่ที่ตำแหน่ง 10px จากด้านซ้าย และ 5px ด้านบน เมื่อเทียบกับ viewport” เป็นต้น&lt;/p&gt;

&lt;p&gt;ด้านล่างนี้เป็นวิดีโอจำลองการ reflow ของ Gecko engine ของ Firefox กับเพจ mozilla.org &lt;a href=&quot;https://www.youtube.com/watch?v=ZTnIxIA5KGw&quot;&gt;[ที่มา]&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;text-center video-wrapper&quot;&gt;
  &lt;iframe width=&quot;640&quot; height=&quot;480&quot; src=&quot;https://www.youtube.com/embed/ZTnIxIA5KGw&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id=&quot;paint&quot;&gt;4. Paint&lt;/h2&gt;

&lt;p&gt;Paint คือการ render แต่ละ element ใน render tree ออกมาเป็นแต่ละ pixel ให้ไปปรากฎอยู่บนหน้าจอ browser
ซึ่งขั้นตอนการใส่แต่ละ property ให้แต่ละ element ก็จะประกอบไปด้วยขั้นตอนยิบย่อยที่ browser ต้องทำอีกมากมาย
ส่วนมากมักเป็นการ “วาด” ส่วนประกอบต่างๆ ออกมาบนหน้าจอ
พอ render ครบทุก element ก็จะได้เป็นเว็บออกมาครับ&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/how-browsers-work/paint-profiler.png&quot; alt=&quot;รูป Paint profiler ใน Devtools&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;ขั้นตอนเหล่านี้ไม่เกิดขึ้นเพียงครั้งเดียวแล้วก็จบไป แต่อาจเกิดขึ้นได้หลายๆ ครั้ง เช่น กรณีที่ DOM ถูกอัพเดท
หรือการแก้ไข CSS property บางอย่างของ DOM element ก็ทำให้เกิด Layou/Paint ได้ครับ
ดูเพิ่มได้ที่ &lt;a href=&quot;http://csstriggers.com/&quot;&gt;csstriggers.com&lt;/a&gt; ได้เลยจ้า&lt;/p&gt;

&lt;p&gt;ทั้งหมดนี้ก็เป็นขั้นตอนคร่าวๆ ของวิธีการแสดงผลเว็บไซต์ของ web browser ที่เราใช้กันอยู่ในปัจจุบัน
จะเห็นว่า web browser ที่ทำหน้าที่แสดงผลเว็บไซต์ นั้นจริงๆ แล้วมีขั้นตอนการทำงานที่ค่อนข้างซับซ้อนพอสมควร
แต่การทำความเข้าใจเรื่องเกี่ยวกับ browser ก็ถือเป็นพื้นฐานที่สำคัญที่จะต่อยอดไปเรียนรู้เรื่องอื่นๆ ต่อได้ครับ&lt;/p&gt;

&lt;h3 id=&quot;sources--&quot;&gt;Sources / อ่านเพิ่ม&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/&quot;&gt;How Browsers Work: Behind the scenes of modern web browsers&lt;/a&gt; HTML5Rocks&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://arvindr21.github.io/howBrowserWorks&quot;&gt;How Browser Works&lt;/a&gt; (slides) by Arvind Ravulavaru&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://vimeo.com/32364192&quot;&gt;Life of a Button Element&lt;/a&gt; (video) by Alex Russell&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.perl.com/pub/2012/10/an-overview-of-lexing-and-parsing.html&quot;&gt;An overview of Lexing and Parsing&lt;/a&gt; by Ron Savage&lt;/li&gt;
&lt;/ul&gt;</content><category term="web" /><category term="browser" /><category term="rendering" /><category term="performance" /><summary>HTML, CSS กับ JavaScript เป็น 3 องค์ประกอบหลักของเว็บไซต์ทั่วๆ ไปที่เราเห็นกันอยู่
ส่วน web browser นั้นก็มีหน้าที่แปลง code ของทั้ง 3 ส่วนประกอบนั้น แสดงผลออกมาเป็นเว็บไซต์ให้เราได้ใช้งาน
ในฐานะคนทำเว็บ การเข้าใจหลักการทำงานของ web browser นั้นช่วยให้เข้าใจถึงที่มาที่ไปของสิ่งที่ปรากฏบนหน้าจอ
รวมถึงจะเป็นประโยชน์ในเรื่องการ optimize performance ของเว็บไซต์ด้วยครับ</summary></entry><entry><title>จัดโค้ด JSON ใน Vim</title><link href="https://armno.github.io/2016/01/25/format-json-in-vim" rel="alternate" type="text/html" title="จัดโค้ด JSON ใน Vim" /><published>2016-01-25T00:00:00+00:00</published><updated>2016-01-25T00:00:00+00:00</updated><id>https://armno.github.io/2016/01/25/format-json-in-vim</id><content type="html" xml:base="https://armno.github.io/2016/01/25/format-json-in-vim">&lt;p&gt;การ format file JSON (จัดให้เป็นระเบียบ, uncompressed, prettify) ปกติเป็นงานที่ผมไม่ได้ทำใน Vim
ต้องพึ่ง editor ตัวอื่น (เพราะไม่เคยรู้วิธีการ) แต่ด้วยความสงสัยก็เลยลองค้นหาวิธีในเน็ตดู ก็พบว่ามีหลายทางให้เลือก&lt;/p&gt;

&lt;p&gt;สมมุติว่าผมมีไฟล์ JSON ที่ถูก compressed มาไว้แบบนี้&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;x-e1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;brand&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;fuji&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;mirrorless&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},{&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;d60&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;brand&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nikon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;dslr&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;ต้องการจะ expand/prettify มันออกด้วย Vim จะต้องทำยังไง&lt;/p&gt;

&lt;h2 id=&quot;jsontool--python&quot;&gt;วิธีที่ 1: ใช้ &lt;code class=&quot;highlighter-rouge&quot;&gt;json.tool&lt;/code&gt; ใน Python&lt;/h2&gt;

&lt;p&gt;ในเครื่องถ้าลง Python ไว้ก็จะมี module ที่ชื่อว่า &lt;a href=&quot;https://docs.python.org/2/library/json.html&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;json.tool&lt;/code&gt;&lt;/a&gt; ใช้ format JSON ผ่าน command line ได้&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;python -m json.tool &amp;lt;FILENAME&amp;gt;

&lt;span class=&quot;c&quot;&gt;# หรือ&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;cat &amp;lt;FILENAME&amp;gt; | pythone -m json.tool&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;ซึ่งใน Vim เราสามารถ execute command line ได้จาก Ex mode (กด &lt;code class=&quot;highlighter-rouge&quot;&gt;:&lt;/code&gt; หรือ &lt;code class=&quot;highlighter-rouge&quot;&gt;Q&lt;/code&gt; ใน Normal mode) ดูรายละเอียดของ command นี้ได้ที่ &lt;a href=&quot;https://pascalprecht.github.io/2014/07/10/pretty-print-json-in-vim/&quot;&gt;Pretty printing JSON in Vim&lt;/a&gt; ได้เลยจ้า&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-vim&quot; data-lang=&quot;vim&quot;&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;%&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt;python &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;m&lt;/span&gt; json&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;tool&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;ก็จะได้ JSON ที่ format แล้ว&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;brand&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;fuji&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;x-e1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;mirrorless&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;brand&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nikon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;d60&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;dslr&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;แต่มีข้อสังเกตก็คือ&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;แต่ละ property ของ object ถูกเรียงใหม่ตามตัวอักษร ในไฟล์ตัวอย่างคือ property &lt;code class=&quot;highlighter-rouge&quot;&gt;brand&lt;/code&gt; ถูกเลื่อนขึ้นมาอยู่ก่อน &lt;code class=&quot;highlighter-rouge&quot;&gt;model&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;ไม่สามารถกำหนดจำนวน space ได้ จะเป็น 4 space ตลอด&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ผมก็เลยลองหาวิธีอื่นดู เจอ Node module ที่ชื่อว่า &lt;code class=&quot;highlighter-rouge&quot;&gt;json&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;json-node-module&quot;&gt;วิธีที่ 2: ใช้ &lt;code class=&quot;highlighter-rouge&quot;&gt;json&lt;/code&gt; Node module&lt;/h2&gt;

&lt;p&gt;ขั้นแรกต้องลง &lt;a href=&quot;https://github.com/trentm/json&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;json&lt;/code&gt;&lt;/a&gt; Node module แบบ global ก่อน เพื่อให้เราสามารถใช้ command &lt;code class=&quot;highlighter-rouge&quot;&gt;json&lt;/code&gt; ได้&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;npm install -g json&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;ใช้งานใน Vim จาก Ex mode เหมือนเดิม&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-vim&quot; data-lang=&quot;vim&quot;&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;%&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt;json&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;ก็ได้ JSON ที่ format แล้วแบบนี้&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;x-e1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;brand&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;fuji&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;mirrorless&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;d60&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;brand&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nikon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;dslr&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;สังเกตว่าลำดับของแต่ละ property ยังเหมือนเดิม ส่วนจำนวน space เป็นค่า default คือ 2 space ในการ indent
เราสามารถทำหนดได้ด้วยการส่ง argument ให้ &lt;code class=&quot;highlighter-rouge&quot;&gt;json&lt;/code&gt; command&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-vim&quot; data-lang=&quot;vim&quot;&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;%&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt;json &lt;span class=&quot;m&quot;&gt;-2&lt;/span&gt;         # &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; spaces
&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;%&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt;json &lt;span class=&quot;m&quot;&gt;-4&lt;/span&gt;         # &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; spaces
&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;%&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt;json &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;o&lt;/span&gt; json&lt;span class=&quot;m&quot;&gt;-7&lt;/span&gt;  # &lt;span class=&quot;m&quot;&gt;7&lt;/span&gt; spaces&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; กรณีที่ไม่ใช่ &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; หรือ &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;sourcebeautifyvim&quot;&gt;3. ใช้ &lt;code class=&quot;highlighter-rouge&quot;&gt;sourcebeautify.vim&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/michalliu/sourcebeautify.vim&quot;&gt;sourcebeautify.vim&lt;/a&gt; เป็น plugin ของ Vim ใช้ format code อย่างอื่นนอกจาก JSON ได้ด้วย
(HTML, JavaScript, CSS, JSON, XML, MySQL) แต่ผมยังไม่ได้ใช้เยอะขนาดนั้น เลยยังไม่ได้ลอง
แต่ก็เป็นอีกทางเลือกนึงที่น่าจะใช้ได้ครับ&lt;/p&gt;

&lt;p&gt;ใครมีวิธี format JSON ใน Vim วิธีอื่นๆ แนะนำกันได้นะ&lt;/p&gt;

&lt;h3 id=&quot;sources&quot;&gt;Sources&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://pascalprecht.github.io/2014/07/10/pretty-print-json-in-vim/&quot;&gt;Pretty printing JSON in Vim&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://blog.jpalardy.com/posts/comparing-command-line-json-pretty-printers/&quot;&gt;Comparing Command-Line JSON Pretty Printers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="JSON" /><category term="Vim" /><category term="Editor" /><category term="Code" /><category term="Formatting" /><summary>การ format file JSON (จัดให้เป็นระเบียบ, uncompressed, prettify) ปกติเป็นงานที่ผมไม่ได้ทำใน Vim
ต้องพึ่ง editor ตัวอื่น (เพราะไม่เคยรู้วิธีการ) แต่ด้วยความสงสัยก็เลยลองค้นหาวิธีในเน็ตดู ก็พบว่ามีหลายทางให้เลือก</summary></entry><entry><title>ใช้งาน Atom</title><link href="https://armno.github.io/2015/09/25/setting-up-atom" rel="alternate" type="text/html" title="ใช้งาน Atom" /><published>2015-09-25T00:00:00+00:00</published><updated>2015-09-25T00:00:00+00:00</updated><id>https://armno.github.io/2015/09/25/setting-up-atom</id><content type="html" xml:base="https://armno.github.io/2015/09/25/setting-up-atom">&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/atom/atom-logo-2x.png&quot; alt=&quot;Atom Logo&quot; width=&quot;290&quot; height=&quot;60&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://atom.io/&quot;&gt;Atom&lt;/a&gt; เป็น open source text editor จาก GitHub ที่หน้าตาและการใช้งานคล้ายกับ Sublime Text มาก
เพิ่งจะเปิดตัวเวอร์ชั่น 1.0 ไปเมื่อไม่กี่เดือนก่อน ซึ่งผมเองได้ลองใช้มาตั้งแต่เวอร์ชั่นแรกๆ ตอนนั้นไม่ประทับใจเลย
เพราะรู้สึกว่าช้ากว่า Sublime Text เยอะอยู่พอสมควร แต่ก็ได้แต่แอบส่องเป็นระยะๆ หวังลึกๆ ว่าวันหนึ่งจะมาแทน
Sublime Text ได้&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/atom/atom-editor.png&quot; alt=&quot;Atom Editor&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;ช่วงนี้ได้มาทดลองใช้งานจริงจังอีกครั้ง พบว่าความเร็วนั้นถือว่าใช้งานได้อย่างไม่ติดขัดแล้ว
ผมเลยถือโอกาสทดสอบต่อเลยว่า จะมีฟีเจอร์ที่ต้องการ ใช้งานจริงจังแทน Sublime Text เลยได้หรือไม่&lt;/p&gt;

&lt;h2 id=&quot;section&quot;&gt;1. พื้นฐาน&lt;/h2&gt;

&lt;p&gt;แทบจะไม่ต้องปรับตัวอะไรจาก Sublime Text เลยก็ว่าได้ครับ&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;kbd&gt;⌘&lt;/kbd&gt; + &lt;kbd&gt;p&lt;/kbd&gt; (หรือ &lt;kbd&gt;⌘&lt;/kbd&gt; + &lt;kbd&gt;t&lt;/kbd&gt;) เปิดไฟล์&lt;/li&gt;
  &lt;li&gt;&lt;kbd&gt;⌘&lt;/kbd&gt; + &lt;kbd&gt;Shift&lt;/kbd&gt; + &lt;kbd&gt;p&lt;/kbd&gt; เปิด command palette&lt;/li&gt;
  &lt;li&gt;&lt;kbd&gt;⌘&lt;/kbd&gt; + &lt;kbd&gt;k&lt;/kbd&gt; + &lt;kbd&gt;b&lt;/kbd&gt; (หรือ &lt;kbd&gt;⌘&lt;/kbd&gt; + &lt;kbd&gt;\&lt;/kbd&gt;) เปิด/ปิด sidebar (tree view)&lt;/li&gt;
  &lt;li&gt;มี multiple cursor (&lt;kbd&gt;Ctrl&lt;/kbd&gt; + click)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Atom มาพร้อมกับ &lt;a href=&quot;https://github.com/atom/apm&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;apm&lt;/code&gt;&lt;/a&gt; หรือ Atom Package Manager ลักษณะคล้ายกับ Package Control ใน Sublime Text
แต่ผ่าน command line ครับ (หรือจะใช้ผ่าน UI ตรง settings ก็ได้เหมือนกัน) เอาไว้เพิ่ม/ลบ/อัพเดท package
ได้จากสะดวกเลยทีเดียว&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/atom/apm-command.png&quot; alt=&quot;apm command&quot; width=&quot;798&quot; height=&quot;392&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;เปิด &lt;code class=&quot;highlighter-rouge&quot;&gt;atom&lt;/code&gt; จาก terminal ได้เลย&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/atom/atom-executable.png&quot; alt=&quot;atom command&quot; width=&quot;221&quot; height=&quot;65&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;vim-mode--ex-mode&quot;&gt;2. &lt;code class=&quot;highlighter-rouge&quot;&gt;vim-mode&lt;/code&gt; กับ &lt;code class=&quot;highlighter-rouge&quot;&gt;ex-mode&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://atom.io/packages/vim-mode&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;vim-mode&lt;/code&gt;&lt;/a&gt; เป็น package ของ atom ที่จำลองเอา vim มาใส่ใน atom ซึ่งสำหรับผมถือว่าพอใช้งานได้ (ผมใช้งานเป็นแค่ฟีเจอร์พื้นฐานของ vim) แต่การที่ไม่มี visual block mode (ctrl+v) บางครั้งก็รู้สึกอืดอัดเหมือนกัน
มีคนรู้สึกเหมือนกันเยอะ เลยมีคนทำ &lt;a href=&quot;https://atom.io/packages/vim-mode-visual-block&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;vim-mode-visual-block&lt;/code&gt;&lt;/a&gt; package มา ลงคู่กับ vim-mode ทำให้ใช้ &lt;kbd&gt;Ctrl&lt;/kbd&gt; + &lt;kbd&gt;v&lt;/kbd&gt; ใช้งาน visual block mode ได้ครับ&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/atom/virtual-block-mode.png&quot; alt=&quot;virtual block mode&quot; width=&quot;460&quot; height=&quot;227&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;ส่วน &lt;a href=&quot;https://atom.io/packages/ex-mode&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;ex-mode&lt;/code&gt;&lt;/a&gt; นั้นก็ส่วนเสริมของ vim-mode ที่ทำให้ใช้คีย์ &lt;kbd&gt;:&lt;/kbd&gt; สำหรับ command mode ของ vim ได้&lt;/p&gt;

&lt;h3 id=&quot;keymap-&quot;&gt;ตั้ง keymap เอง&lt;/h3&gt;

&lt;p&gt;จริงๆ ผม map แค่ตัวเดียวคือ &lt;kbd&gt;,&lt;/kbd&gt; + &lt;kbd&gt;e&lt;/kbd&gt; เป็น escape เพื่อออกจาก insert mode ไปหา command mode
วิธีการตั้ง keymap เอง กด &lt;kbd&gt;⌘&lt;/kbd&gt; + &lt;kbd&gt;Shift&lt;/kbd&gt; + &lt;kbd&gt;p&lt;/kbd&gt; แล้วหาคำว่า &lt;code class=&quot;highlighter-rouge&quot;&gt;open your keymap&lt;/code&gt; แล้วก็ใส่แบบนี้&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&#39;body&#39;:
  &#39;, e&#39;: &#39;vim-mode:activate-normal-mode&#39;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;ui-theme--syntax-theme&quot;&gt;3. UI Theme &amp;amp; Syntax Theme&lt;/h2&gt;

&lt;p&gt;ใช้เวลาหาอยู่นาน จนได้คู่ UI Theme ใช้ One Dark (ติดมากับ Atom) ส่วน Syntax Theme ใช้ &lt;a href=&quot;https://atom.io/themes/afterglow-monokai-syntax&quot;&gt;Afterglow Monokai&lt;/a&gt; กับ &lt;a href=&quot;https://atom.io/themes/afterglow-plus&quot;&gt;Afterglow Plus&lt;/a&gt; สลับกันไป
(จริงๆ ชอบ Afterglow Plus มากกว่า แต่เวลาใช้กับ One Dark UI แล้วมันมืดทึมๆ ไปหน่อย)
Atom มันแปลกตรงที่ UI Theme กับ Syntax Theme สวยๆ บางอันก็ไม่ค่อยเข้ากันเท่าไหร่&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Afterglow Monokai&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/atom/syntax-afterglow-monokai.png&quot; alt=&quot;afterglow monokai syntax theme&quot; width=&quot;664&quot; height=&quot;773&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Afterglow-Plus&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/atom/syntax-afterglow-plus.png&quot; alt=&quot;afterglow plus syntax theme&quot; width=&quot;664&quot; height=&quot;773&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;tab-bar&quot;&gt;ซ่อน Tab bar&lt;/h3&gt;

&lt;p&gt;ใน command palette (&lt;kbd&gt;⌘&lt;/kbd&gt; + &lt;kbd&gt;Shift&lt;/kbd&gt; + &lt;kbd&gt;p&lt;/kbd&gt;) ไม่มีคำสั่งสำหรับ toggle tab bar สำหรับซ่อน tab ทั้งหมดที่เปิดอยู่เหมือนใน Sublime Text ปกติผมไม่ได้ใช้งาน tab เลยก็จะปิดไว้
ส่วนใน Atom ต้องไปแก้ใน custom style ด้วย CSS เพื่อซ่อน tab bar เอาครับ&lt;/p&gt;

&lt;p&gt;เปิด command palette แล้วเลือก &lt;code class=&quot;highlighter-rouge&quot;&gt;open your stylesheet&lt;/code&gt; แล้วก็ใส่ CSS ให้ &lt;code class=&quot;highlighter-rouge&quot;&gt;.tab-bar&lt;/code&gt; เป็น &lt;code class=&quot;highlighter-rouge&quot;&gt;display: none&lt;/code&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-css&quot; data-lang=&quot;css&quot;&gt;&lt;span class=&quot;nc&quot;&gt;.tab-bar&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;packages&quot;&gt;4. Packages&lt;/h2&gt;

&lt;p&gt;ผมไม่ได้ลงอะไรเยอะเท่าไหร่ แต่ package ที่จำเป็นสำหรับ Atom ที่สุดสำหรับผมน่าจะเป็น &lt;a href=&quot;https://atom.io/packages/project-manager&quot;&gt;Project Manager&lt;/a&gt; ครับ
ทำให้ save project และสลับไปมาระหว่าง project ได้เหมือน &lt;kbd&gt;Ctrl&lt;/kbd&gt; + &lt;kbd&gt;⌘&lt;/kbd&gt; + &lt;kbd&gt;p&lt;/kbd&gt; ใน Sublime Text&lt;/p&gt;

&lt;p&gt;พวกตระกูล &lt;a href=&quot;https://atom.io/packages/linter&quot;&gt;Atom-linter&lt;/a&gt; ทั้งหลายก็แจ่มเลยทีเดียว แสดง error/warning แบบ inline ได้เลย&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/atom/inline-linting.png&quot; alt=&quot;eslint in atom&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;อื่นๆ ก็ตามนี้จ้า&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;apm list

/Users/armno/.atom/packages &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;17&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
├── afterglow-monokai-syntax@1.3.3
├── afterglow-plus@1.6.0
├── chester-atom-syntax@0.1.1
├── editorconfig@1.2.0
├── emmet@2.3.12
├── ex-mode@0.7.0
├── highlight-line@0.11.0
├── highlight-selected@0.10.1
├── language-javascript-better@1.5.0
├── language-javascript-semantic@0.2.1
├── linter@1.6.0
├── linter-eslint@3.0.2
├── linter-jshint@1.2.0
├── project-manager@2.5.2
├── react@0.12.10
├── vim-mode@0.60.0
└── vim-mode-visual-block@0.2.13&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;ถ้าใครมี package อะไรเจ๋งๆ แนะนำกันหน่อยนะครับ :D&lt;/p&gt;

&lt;h3 id=&quot;section-1&quot;&gt;ภาษาไทย&lt;/h3&gt;

&lt;p&gt;การพิมพ์ภาษาไทยใน Atom นั้นสระไม่ลอยเหมือนใน Sublime Text ครับ เยี่ยมเลย&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;
  &lt;img src=&quot;/img/posts/atom/thai.png&quot; alt=&quot;ภาษาไทยใน Atom&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;section-2&quot;&gt;(ไม่ชอบใจ)&lt;/h3&gt;

&lt;p&gt;การทำงานกับ Atom Linter นั้นยังมีข้อจำกัด (อันใหญ่หลวง) คือไม่สามารถเลือก linter ของแต่ละเฉพาะ project ได้
เช่น project ที่ทำงานผมจะใช้ JSHint ส่วนที่บ้านจะใช้ ESLint แต่ Atom ไม่มีที่สำหรับตั้งค่า linter ของแต่ละ project
นั่นก็คือถ้าลง JSHint มันก็จะใช้ lint กับทุก project หรือ ESLint ก็เช่นกัน (อ้างอิง &lt;a href=&quot;https://github.com/atom-community/linter/issues/744&quot;&gt;linter/744&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;วิธีแก้ของผมก็คือลงไว้ทั้ง 2 ตัว แล้วค่อยไป enable/disable package ใน settings ตอนสลับ project เอา ไม่สะดวกเท่าไหร่ครับ&lt;/p&gt;

&lt;p&gt;อีกเรื่องก็คงเป็น startup time ที่ยังช้ากว่า Sublime Text อยู่พอสมควร ถ้าต้องสลับ project บ่อยๆ ก็ไม่สนุกครับ&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;ตอนนี้ก็พยายามใช้ Atom เป็นหลักอยู่ครับ ผมชอบตรงที่มัน open แล้วก็ release บ่อยดี พัฒนาฟีเจอร์ต่างๆ เร็วดี ส่วนใครมีเทคนิคเจ๋งๆ มาแนะนำกันหน่อยนะ Happy Coding ครับ&lt;/p&gt;</content><category term="coding" /><category term="editor" /><category term="atom" /><summary></summary></entry><entry><title>หูฟัง Audio-Technica ATH-M50x</title><link href="https://armno.github.io/2015/08/04/audio-technica-ath-m50x" rel="alternate" type="text/html" title="หูฟัง Audio-Technica ATH-M50x" /><published>2015-08-04T00:00:00+00:00</published><updated>2015-08-04T00:00:00+00:00</updated><id>https://armno.github.io/2015/08/04/audio-technica-ath-m50x</id><content type="html" xml:base="https://armno.github.io/2015/08/04/audio-technica-ath-m50x">&lt;p&gt;หลังจากใช้งาน &lt;a href=&quot;http://armno.github.io/grado-sr-80-i-headphone/&quot;&gt;Grado SR-80i&lt;/a&gt; มาได้ประมาณ 2 ปี ถึงเวลาที่ต้องเปลี่ยนหูฟังอันใหม่ ที่เปลี่ยนก็เพราะว่าย้ายที่นั่งกันที่ออฟฟิศ
มีเสียงในที่ทำงานเยอะขึ้น แล้ว SR-80i นั้นมีเสียงลอดค่อนข้างมาก (โดยเฉพาะลอดเข้ามาตอนฟังเพลง)
อีกอย่างนึงคือผมยังมีอาการเจ็บหูใบอยู่บ้างตอนใช้ SR-80i ซึ่งเป็นแบบ on ear ทับบนใบหูเป็นเวลานานๆ
จนคิดว่าถึงเวลาต้องเปลี่ยนใหม่แล้วล่ะ&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;ลักษณะการใช้งานของผมคือฟังเพลงเป็นหลัก ฟังเกือบทุกแนวยกเว้นเพลง hip hop, แนวตึ๊บๆ กับลูกทุ่งก็ไม่ได้ฟัง
.. แล้วก็มีใช้ทำเพลงใน Garageband กับอัดเสียงกีต้าร์เล่นๆ ที่บ้านด้วยครับ&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5449/17241404908_40ace05191_c.jpg&quot; alt=&quot;Audio-Technica M50x&quot; /&gt;&lt;/p&gt;

&lt;p&gt;หลังจากหาข้อมูลอยู่พักนึง ก็ได้หูฟัง &lt;a href=&quot;http://www.audio-technica.com/cms/headphones/99aff89488ddd6b1/&quot;&gt;Audio-Technica ATH-M50x&lt;/a&gt; เป็นหูฟังตัวล่าสุดที่ผมเลือกซื้อมาใช้ครับ
ไม่เคยใช้ brand นี้มาก่อน แต่ดูจาก review ใน YouTube แล้วเสียงตอบรับค่อนข้างดี
บางเจ้าถึงกับยกให้เป็นหูฟังที่ดีที่สุดในราคาไม่เกิน $200 (ประมาณ 7 พันบาท) กันเลยทีเดียว
ผมเองก็ได้ไปลองฟังเสียงของ M50 (รุ่นก่อนหน้า) แล้วรู้สึกชอบด้วย ก็เลยเลือกตัวนี้ครับ&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7710/17243021339_2b9e8e4df7_c.jpg&quot; alt=&quot;ATH M50x Headband&quot; /&gt;&lt;/p&gt;

&lt;p&gt;M50x ต่างจาก M50 ที่เห็นได้ชัดคือสายหูฟังให้มา 3 แบบ และถอดเปลี่ยนได้ นอกนั้นก็เป็นรายละเอียดเล็กๆ น้อยๆ&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5323/16806714604_2409b8cf17_c.jpg&quot; alt=&quot;ATH M50x ถอดสายออก&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7721/17429242525_130b218203_c.jpg&quot; alt=&quot;ATH-M50x&quot; /&gt;&lt;/p&gt;

&lt;p&gt;หูฟังตัวนี้ซื้อมาจากร้าน Munkonggadget.com ส่งตรงมาถึงเชียงใหม่ครับ&lt;/p&gt;

&lt;h3 id=&quot;section&quot;&gt;คุณภาพวัสดุ&lt;/h3&gt;

&lt;p&gt;Audio-Technica เป็นบริษัทสัญชาติญี่ปุ่น แต่ M50x นี้ผลิตที่ประเทศไต้หวันครับ
งานประกอบดีมาก เนี้ยบดีตั้งแต่กล่องยันหูฟัง งานประกอบแน่นหนาดีมาก ไม่อยากจะอวยเลย แต่ชอบจริงๆ&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5325/17403165626_4b597f2b23_c.jpg&quot; alt=&quot;closer look ATH-M50x&quot; /&gt;&lt;/p&gt;

&lt;p&gt;ฟองน้ำครอบหูบุหนังดูดีเลยทีเดียว&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7680/17242993859_12cbff4234_c.jpg&quot; alt=&quot;M50x พับเก็บได้&quot; /&gt;&lt;/p&gt;

&lt;p&gt;สายหูฟัง 3 แบบที่ให้มานั้นก็มี&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;สายขด (coiled cable) ยาว 3 เมตร&lt;/li&gt;
  &lt;li&gt;สายตรง (straight cable) ยาว 3 เมตร&lt;/li&gt;
  &lt;li&gt;สายตรง ยาว 1.2 เมตร&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ผมเก็บ coiled cable ไว้ใช้ที่บ้าน สายตรงยาว ไว้ใช้ประจำที่ออฟฟิศ ส่วนสายตรงสั้น เอาติดถุงไว้ เผื่อใช้กับโทรศัพท์หรือ laptop ครับ สายของ M50x มีตัวล็อกเฉพาะของ Audio-Technica เวลาใส่ต้องหมุนนิดนึงเพื่อให้เข้าล็อก
ข้อดีของการหมุนล็อกนี้ก็คือไม่ต้องกลัวหลุดเวลาเสียบฟังอยู่ ส่วนข้อเสียก็คือจะใช้สายของยี่ห้ออื่นไม่ได้ครับ&lt;/p&gt;

&lt;p&gt;ในกล่องมีตัวแปลงแจ็คจาก 3.5mm เป็น 6.3mm มาให้ด้วย ใช้ได้กับเฉพาะสายยาว 3 เมตร ส่วนสาย 1.2 เมตรนั้นใช้ไม่ได้ เพราะไม่มีเกลียวหมุน&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7658/17427209582_0503e64a4f_c.jpg&quot; alt=&quot;ตัวล็อกสายหูฟังของ M50x&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;section-1&quot;&gt;ความสบายตอนสวมใส่&lt;/h3&gt;

&lt;p&gt;เทียบกับ SR-80i แล้วถือว่า M50x หนักกว่าพอสมควร ใส่ตอนแรกๆ ก็รู้สึกว่ามันหนัก ตอนนี้ก็เริ่มชินแล้วครับ
ฟองน้ำบุหนังนั้นก็ถือว่านุ่มเลยทีเดียว ครอบหูได้ทั้งใบ (ส่วนเรื่องเจ็บใบหูนั้นหายไปเลย เพราะไม่กดหูแล้ว)
ด้วยความที่เป็นหูฟังแบบปิด จะมีความร้อนสะสมบ้างเมื่อใส่นานๆ แต่ก็แค่อุ่นๆ ครับ ไม่ถึงกับร้อน พักแป๊ปเดียวก็หาย&lt;/p&gt;

&lt;p&gt;M50x ไม่ใช่หูฟังประเภทตัดเสียงรบกวน (noise cancelling) แต่ก็สามารถป้องกันเสียงรบกวนจากภายนอกได้ค่อนข้างเยอะ
(noise isolation ดีมาก) ถ้าใส่หูฟังเฉยๆ ไม่เปิดเสียงอะไรเลย จะรู้สึกเหมือนหูอื้อ เพราะว่าไม่ค่อยได้ยินเสียงตัวเอง
แต่พอเปิดเพลงแล้วก็แทบจะไม่ได้ยินเสียงรบกวนจากภายนอกเลย ปกติผมก็จะเปิดเพลงไว้ตลอดเวลา ถึงแม้ไม่ได้ฟังก็ตาม
เพราะถึงเวลาอยากปิดสวิตช์ noise รอบตัว ก็แค่หยิบหูฟังมาใส่หูได้เลย&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8748/16806741734_788a274531_c.jpg&quot; alt=&quot;ด้านข้างของ ATH-M50x&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;section-2&quot;&gt;เสียง&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;ตอนที่ซื้อ SR-80i ผม burn ก่อนใช้จริงนานมาก (500+ ชั่วโมง).. ส่วนตัวนี้ผมไม่ได้ burn ก่อนใช้งานเลย
เพราะตอนออกจากล่องมา เสียงมันก็ค่อนข้างดีอยู่แล้ว .. (นี่เหมือนจะอวยอีกแล้วนะ) แกะกล่องออกมา เช็คของ แล้วก็ลองฟังเลย
พบว่าเสียงมันไม่ต่างกับตัว M50 ที่ไปลองที่ร้านมาก ก็เลยไม่ burn ฟังมันทั้งยังงั้นแหละ&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;M50x เป็นหูฟังประเภท Studio Monitor ซึ่งหูฟังประเภทนี้มักใช้กันในห้องอัด หรือกับงานใน studio ที่ต้องการรายละเอียดของเสียง
และความเที่ยงตรงเป็นหลัก ซึ่งผมชอบมากเพราะทำให้ได้ยินรายละเอียดของเครื่องดนตรีที่ไม่เคยได้ยินมาก่อนในเพลงที่ฟังอยู่ทุกวัน
หรือทำให้ได้ยินดนตรีในแบบที่ใกล้เคียงกับที่นักดนตรีทำมาจริงๆ มากขึ้นกว่าเดิม&lt;/p&gt;

&lt;p&gt;แนวเสียงจะเป็นโทนกลางๆ ไม่เน้นไปทางทุ้มหรือแหลม แต่ให้รายละเอียดเสียงดนตรี รวมไปถึงตำแหน่งการวางเครื่องดนตรีในเพลงได้ชัดเจนมาก
ทำได้ดีกว่า SR-80i อยู่เยอะพอสมควร ถ้าใครชอบเสียงแนว Grado อยู่แล้ว ก็น่าจะชอบ M50x เหมือนกันครับ
แต่ถ้าชอบฟังเพลงเฉพาะบางแนวเป็นพิเศษ เน้นเบส หรือเน้นเสียงแหลมอย่างใดอย่างหนึ่ง ก็ไม่แนะนำนะ&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8880/17958204910_2637bfd60c_c.jpg&quot; alt=&quot;M50x&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;section-3&quot;&gt;สรุป&lt;/h3&gt;

&lt;p&gt;ชอบ&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;วัสดุกับงานประกอบดีมาก ดูดี ที่สำคัญ แข็งแรง&lt;/li&gt;
  &lt;li&gt;ให้เสียงดนตรีกว้างอย่างแม่น้ำ amazon รายละเอียดดนตรีในเพลงมาเต็ม 7 ตู้คอนเทนเนอร์&lt;/li&gt;
  &lt;li&gt;ถอดสายได้ พับตัวหูฟังได้ เก็บในถุงง่าย&lt;/li&gt;
  &lt;li&gt;สวมใส่สบาย ใส่นานๆ ได้ ไม่เจ็บหูแล้ว&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;meh:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;หนัก (หนักกว่า SR-80i เยอะพอสมควร)&lt;/li&gt;
  &lt;li&gt;สายหูฟังทั้ง 3 แบบ เส้นเล็กกว่า และไม่ถึกเท่าของ Grado&lt;/li&gt;
  &lt;li&gt;ขั้วล็อกสายกับหูฟังเป็นแบบเฉพาะ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8788/17957972318_d9fb8c8e22_c.jpg&quot; alt=&quot;M50x บนโต๊ะทำงาน&quot; /&gt;&lt;/p&gt;

&lt;p&gt;ปล.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;ใน YouTube มีรีวิว M50x อยู่ค่อนข้างเยอะ แต่&lt;a href=&quot;https://www.youtube.com/watch?v=y5DyEYuvF3o&quot;&gt;รีวิวของ MKBHD&lt;/a&gt; ทำให้ผมตัดสินใจเลือก M50x ครับ&lt;/li&gt;
  &lt;li&gt;M50x มีรุ่น Limited Edition อีก 2 รุ่นคือสีน้ำตาล กับสีเขียวเข้ม สวยดี แต่แพงกว่ารุ่นปกติ&lt;/li&gt;
  &lt;li&gt;ในซีรีส์นี้ยังมีรุ่นอื่นๆ อีกตั้งแต่ M20x, M30x, M40x ไปถึง M70x ที่เพิ่งออกมาใหม่ คุณสมบัติกับราคาก็ไต่ไปตามระดับครับ&lt;/li&gt;
&lt;/ul&gt;</content><category term="headphones" /><category term="music" /><category term="m50x" /><summary>หลังจากใช้งาน Grado SR-80i มาได้ประมาณ 2 ปี ถึงเวลาที่ต้องเปลี่ยนหูฟังอันใหม่ ที่เปลี่ยนก็เพราะว่าย้ายที่นั่งกันที่ออฟฟิศ
มีเสียงในที่ทำงานเยอะขึ้น แล้ว SR-80i นั้นมีเสียงลอดค่อนข้างมาก (โดยเฉพาะลอดเข้ามาตอนฟังเพลง)
อีกอย่างนึงคือผมยังมีอาการเจ็บหูใบอยู่บ้างตอนใช้ SR-80i ซึ่งเป็นแบบ on ear ทับบนใบหูเป็นเวลานานๆ
จนคิดว่าถึงเวลาต้องเปลี่ยนใหม่แล้วล่ะ</summary></entry><entry><title>ใช้ Device Mode ใน Google Chrome ทำงานกับ Mobile Web/Hybrid App</title><link href="https://armno.github.io/2015/07/02/device-mode-in-google-chrome" rel="alternate" type="text/html" title="ใช้ Device Mode ใน Google Chrome ทำงานกับ Mobile Web/Hybrid App" /><published>2015-07-02T00:00:00+00:00</published><updated>2015-07-02T00:00:00+00:00</updated><id>https://armno.github.io/2015/07/02/device-mode-in-google-chrome</id><content type="html" xml:base="https://armno.github.io/2015/07/02/device-mode-in-google-chrome">&lt;p&gt;ใน Chrome Devtools จะมี &lt;a href=&quot;https://developer.chrome.com/devtools/docs/device-mode&quot;&gt;Device Mode&lt;/a&gt; เป็นส่วนหนึ่งที่มีประโยชน์มากกับการทำ responsive website หรือ mobile web app
หรือแม้กระทั่ง hybrid app อย่าง Cordova ก็ด้วยครับ โดยที่ Device Mode ใน Devtools ก็คือการจำลอง Google Chrome
ให้เป็นเหมือน mobile device เครื่องหนึ่ง สิ่งที่จะได้ก็คือ&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;ขนาดหน้าจอ (ขนาด browser) ตาม device ที่เลือก&lt;/li&gt;
  &lt;li&gt;จำลอง device pixel ratio&lt;/li&gt;
  &lt;li&gt;user agent string ก็ตาม device ที่เลือก&lt;/li&gt;
  &lt;li&gt;จำลอง network condition (WiFi, 2G, 3G)&lt;/li&gt;
  &lt;li&gt;ตั้งค่า CSS Media แบบ manual ได้&lt;/li&gt;
  &lt;li&gt;จำลองค่า geolocation หรือ accelerometer ก็ได้&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;เท่าที่ได้ใช้งาน Device Mode มา รู้สึกได้ว่าเป็นอีกฟีเจอร์หนึ่งของ Devtools ที่ถูกให้ความสำคัญพอสมควร ได้เห็นฟีเจอร์ใหม่ของ Device Mode เพิ่มขึ้นมาเรื่อยๆ ครับ&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;ในโพสต์นี้ผมใช้งาน Device Mode บน &lt;a href=&quot;https://www.google.com/Chrome/browser/canary.html&quot;&gt;Chrome Canary&lt;/a&gt; (45.0.2446.0) อาจจะมีหรือยังไม่มีบางฟีเจอร์ใน Chrome Beta หรือ Stable ก็ได้ครับผม&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;device-mode&quot;&gt;เริ่มใช้งาน Device Mode&lt;/h2&gt;

&lt;p&gt;เปิด Devtools ขึ้นมาใน Chrome (&lt;kbd&gt;command&lt;/kbd&gt; + &lt;kbd&gt;shift&lt;/kbd&gt; + &lt;kbd&gt;I&lt;/kbd&gt;) แล้วคลิก icon รูปโทรศัพท์ อยู่ใกล้ๆ รูปแว่นขยาย&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/device-mode/activate-icon.png&quot; alt=&quot;activate Device Mode&quot; /&gt;&lt;/p&gt;

&lt;p&gt;ก็จะได้เจอหน้าจอแบบนี้ครับ&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/device-mode/device-mode-activated.png&quot; alt=&quot;Chrome Device Mode&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;mobile-device&quot;&gt;เลือก mobile device&lt;/h2&gt;

&lt;p&gt;อันดับแรกเลย เราสามารถเลือก device จาก preset ที่มีอยู่แล้วได้ มี mobile device พื้นฐานมาให้ครบๆ ตามแต่ละ OS/platform แต่ละ device ก็จะมีขนาดหน้าจอ, device pixel ratio กับ user agent string ที่ต่างกันออกไป&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/device-mode/device-preset.png&quot; alt=&quot;device presets&quot; /&gt;&lt;/p&gt;

&lt;p&gt;นอกจากนี้เราก็ยังสามารถเพิ่ม device เข้าไปใน list ได้ด้วย โดยไปที่ &lt;em&gt;Settings&lt;/em&gt; ใน Devtools (icon รูปเฟือง) &amp;gt; &lt;em&gt;Devices&lt;/em&gt; &amp;gt; &lt;em&gt;Add custom device …&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/device-mode/add-custom-device.png&quot; alt=&quot;add custom device&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(Canary)&lt;/strong&gt; ถัดมาเป็นส่วน orientation ซึ่งใน canary มีตัวเลือกนี้เพิ่มเข้ามา ทำให้เราสามารถเลือกว่าจะให้ขนาดหน้าจอนั้นเป็นแนวตั้งหรือแนวนอน แถมยังเลือกได้ด้วยว่าจะให้เป็นแบบที่มี navigation bar (UI ของ browser) พร้อมทั้ง keyboard ติดมาด้วยหรือไม่ ทำให้เราเห็นภาพขนาดจริงๆ ของ viewport เวลาเว็บของเราไปอยู่บน browser ได้ด้วย&lt;/p&gt;

&lt;p&gt;อย่างในรูปนี้ ส่วนที่เป็นขอบดำด้านบนและล่าง ก็คือ UI ของ Safari บน iOS เทียบกับ iOS Simulator แล้วถือว่า Devtools ทำได้ใกล้เคียงของจริงมาก&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/device-mode/orientation-options.png&quot; alt=&quot;orientation options&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;network-throttling&quot;&gt;Network Throttling&lt;/h2&gt;

&lt;p&gt;ถือว่าเป็นอีกหนึ่ง killer feature เลยก็ว่าได้ ทำให้เราสามารถจำลองความเร็วอินเตอร์เน็ตหลายๆ แบบได้
มีประโยชน์กับการ optimize performance มากๆ เพราะทำให้ developer เห็นภาพชัดขึ้นว่า
ถ้าเว็บของเราถูกโหลดผ่านความเร็วอินเตอร์เน็ตที่แตกต่างกัน สิ่งที่ user จะเห็นนั้นจะช้าหรือเร็วยังไง&lt;/p&gt;

&lt;p&gt;สิ่งที่ผมชอบก็คือ นอกจากจะจำลองความเร็วเน็ตได้แล้ว ยังจำลอง network latency ให้ด้วย ซึ่งตรงกับสถานการณ์ที่ mobile internet นั้นมี latency สูงกว่าเน็ตธรรมดาอยู่เยอะพอสมควร&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/device-mode/network-options.png&quot; alt=&quot;network options&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;media-queries-indicator&quot;&gt;Media Queries Indicator&lt;/h2&gt;

&lt;p&gt;ถ้าในไฟล์ CSS ของเรามี media queries &lt;code class=&quot;highlighter-rouge&quot;&gt;@media&lt;/code&gt; อยู่ด้วย ก็จะเห็นแถบสีสำหรับแบ่ง breakpoint ใน CSS ตามที่เราเขียนได้ด้วย&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/device-mode/media-queries.png&quot; alt=&quot;media queries&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/device-mode/media-queries-2.png&quot; alt=&quot;media queries&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;media-override&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;@media&lt;/code&gt; override&lt;/h2&gt;

&lt;p&gt;Device Mode ยังมีตัวเลือกอื่นๆ ให้เล่นกันอีก เช่น บางครั้งต้องเขียน CSS ให้ &lt;code class=&quot;highlighter-rouge&quot;&gt;@media print&lt;/code&gt; Devtools ก็มีตัวเลือกให้ Chrome แปลงร่างเป็น printer ได้ CSS ที่มี &lt;code class=&quot;highlighter-rouge&quot;&gt;@media print&lt;/code&gt; กำกับอยู่ก็จะทำงาน (เมื่อก่อนต้องกด print preview แล้วก็เดาเอา)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/device-mode/media-override.png&quot; alt=&quot;media override&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;sensors&quot;&gt;Sensors&lt;/h2&gt;

&lt;p&gt;ใน tab Sensors เราสามารถจำลอง touch event, geolocation กับ accelerometer ได้ ผมเองไม่ค่อยได้ใช้ส่วนนี้มาก แต่คิดว่าถ้าใครได้ทำเว็บที่ใช้ API พวกนี้บ่อยๆ น่าจะมีประโยชน์พอสมควรครับ&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/device-mode/sensors.png&quot; alt=&quot;sensors options&quot; /&gt;&lt;/p&gt;

&lt;p&gt;นั่นแหละครับท่านผู้ชม สำหรับผมแล้ว Device Mode ใน Devtools ถือว่าเป็น tool ที่ช่วยทำ responseive web/hybrid app ได้ง่ายขึ้นอีกเยอะเลย (ลดการยืดๆ หดๆ หน้าจอลงไปได้เยอะ)
แต่ก็ยังมีส่วนที่ขาดหายไปอยู่ เช่น&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;การจำลอง CPU/GPU performance ของ mobile device นั้นยังไม่มี (mobile device นั้นช้ากว่า pc พอสมควร)&lt;/li&gt;
  &lt;li&gt;การ render font นั้นก็จะต่างจาก mobile browser อยู่แบบพอสังเกตได้ ดังนั้นจะ test แบบ pixel perfect ใน Chrome ก็คงจะไม่ได้นะ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ลองไปเล่นกันดูครับผม ใครเจอเทคนิคอะไรใน Devtools แวะมาบอกด้วยนะ&lt;/p&gt;</content><category term="chrome" /><category term="devtools" /><category term="mobileweb" /><summary>ใน Chrome Devtools จะมี Device Mode เป็นส่วนหนึ่งที่มีประโยชน์มากกับการทำ responsive website หรือ mobile web app
หรือแม้กระทั่ง hybrid app อย่าง Cordova ก็ด้วยครับ โดยที่ Device Mode ใน Devtools ก็คือการจำลอง Google Chrome
ให้เป็นเหมือน mobile device เครื่องหนึ่ง สิ่งที่จะได้ก็คือ</summary></entry><entry><title>Case study: เปลี่ยนวิธีโหลด CSS เพื่อให้เว็บ render ไวขึ้น</title><link href="https://armno.github.io/2015/05/04/use-loadcss-to-improve-rendering-performance" rel="alternate" type="text/html" title="Case study: เปลี่ยนวิธีโหลด CSS เพื่อให้เว็บ render ไวขึ้น" /><published>2015-05-04T00:00:00+00:00</published><updated>2015-05-04T00:00:00+00:00</updated><id>https://armno.github.io/2015/05/04/use-loadcss-to-improve-rendering-performance</id><content type="html" xml:base="https://armno.github.io/2015/05/04/use-loadcss-to-improve-rendering-performance">&lt;p&gt;ผมเพิ่งเปลี่ยนธีมของ blog จาก &lt;a href=&quot;http://hyde.getpoole.com/&quot; title=&quot;Hyde&quot;&gt;Hyde&lt;/a&gt; มาเป็น &lt;a href=&quot;https://rohanchandra.github.io/project/type/&quot;&gt;Type&lt;/a&gt; (บังเอิญชื่อคล้ายกันด้วย) หลังจากปรับแต่งเก็บรายละเอียดแล้ว
ก็ลองเช็ค performance ของ blog ดูผ่าน &lt;a href=&quot;https://developers.google.com/speed/pagespeed/insights/?url=https%3A%2F%2Farmno.github.io%2F&quot;&gt;PageSpeed Insights&lt;/a&gt; ก่อน optimize score จะอยู่ที่ 73 ในหน้าแรก&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/loadcss/before-optimize.png&quot; alt=&quot;PageSpeed score ก่อน optimize&quot; /&gt;&lt;/p&gt;

&lt;p&gt;ส่วนผลจาก &lt;a href=&quot;http://www.webpagetest.org/&quot;&gt;webpagetest.org&lt;/a&gt; สังเกตตรง first byte อยู่ที่ 0.8 วินาที และ start render ที่ประมาณ 2 วินาที&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/loadcss/webpagetest-before.png&quot; alt=&quot;ทดสอบกับ webpagetest.org ก่อน optimize&quot; /&gt;&lt;/p&gt;

&lt;p&gt;ซึ่งยังมีส่วนให้ปรับปรุงได้อยู่ ก็เลยจับมาเป็นหนูทดลองซะเลย&lt;/p&gt;

&lt;p&gt;สิ่งที่ PageSpeed แนะนำว่าควรปรับปรุงก็คือ มี render-blocking resources อยู่ 3 ไฟล์ ที่ถูกโหลดใน &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;head&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;ฟอนต์ Source Sans Pro จาก Google Fonts (ผ่าน tag &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;link&amp;gt;&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;FontAwesome จาก MaxCDN เพื่อใช้งาน icon font&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;main.css&lt;/code&gt; CSS หลักของธีม&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;render-blocking-resources&quot;&gt;Render-blocking resources?&lt;/h2&gt;

&lt;p&gt;Render-block resources คือไฟล์ JavaScript หรือ CSS ที่ browser จะต้องรอให้โหลดเสร็จก่อน
ถึงจะเริ่ม render ได้ ที่เป็นแบบนี้ก็เพราะว่า ก่อนที่ browser จะสามารถ render หน้าเพจได้นั้น
ก็ต่อเมื่อมันรู้ว่า&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;ในหน้าเพจประกอบด้วย element อะไรบ้าง (HTML, DOM construction)&lt;/li&gt;
  &lt;li&gt;และแต่ละ element มีลักษณะหน้าตายังไง วางอยู่ตรงไหนของหน้าเพจ (CSS, CSSOM construction)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;อ่านเรื่อง &lt;a href=&quot;https://armno.github.io/2016/01/28/how-web-browsers-work&quot;&gt;“วิธีการทำงานของ browser”&lt;/a&gt; ได้จ้า&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;browser ทำทั้ง 2 ขั้นตอนไปพร้อมๆ กัน แต่ทั้ง 2 ขั้นตอนต้องเสร็จสมบูรณ์ก่อน ถึงจะเริ่ม render เพจได้
นั่นหมายความว่า ยิ่ง HTML หรือ CSS มีความซับซ้อนมากขึ้นเท่าไหร่ (หรือมีขนาดใหญ่ขึ้น)
ก็จะทำให้เริ่ม render ได้ช้าลงไปตามนั้น&lt;/p&gt;

&lt;h3 id=&quot;render-&quot;&gt;ทำไมต้องเริ่ม render เร็วๆ?&lt;/h3&gt;

&lt;p&gt;การเริ่ม render หมายถึงการที่ user เริ่มเห็นอะไรบนหน้าเพจหลังจากหน้าจอขาวๆ ธรรมดา
user เห็น content ได้เร็วขึ้น ซึ่งอาจจะไม่สมบูรณ์ก็ตาม แต่อย่างน้อยการได้เห็น “อะไรบางอย่าง”
บนหน้าเพจ ย่อมทำให้ user รู้สึกดีกว่าการเห็นหน้าจอขาวๆ โล่งๆ .. ไม่มีใครชอบเว็บที่โหลดช้าๆ จริงไหม&lt;/p&gt;

&lt;p&gt;Render-blocking resource ในเคสของผมก็คือ ไฟล์ CSS ทั้ง 3 ไฟล์นั้น (ไม่มี JavaScript เพราะ
ใน tag &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;head&amp;gt;&lt;/code&gt; ไม่มี tag &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;script&amp;gt;&lt;/code&gt; อยู่เลย)&lt;/p&gt;

&lt;h2 id=&quot;fontawesome&quot;&gt;1. จัดการ FontAwesome&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://fontawesome.io/&quot;&gt;FontAwesome&lt;/a&gt; เป็นชุด icon font ที่มี icon เยอะมากๆ (ณ ตอนที่เขียนนี้มี 519 icon) ธีม Type นี้ดึง
FontAwesome มาจาก CDN ทั้ง set ทำให้ไฟล์มีขนาดใหญ่เกินตัว (6.5KB CSS + 55KB font) ซึ่งจริงๆ แล้ว
ผมใช้แค่ประมาณ 10 icon เอง ดังนั้นผมเลยเลือกใช้ custom icon font แทนชุดเต็ม&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://icomoon.io/&quot;&gt;IcoMoon&lt;/a&gt; เป็นเว็บแอพที่ทำให้เราสามารถ generate custom icon font ได้ ด้วยการเลือกเฉพาะ icon ที่
ต้องการ แล้วมันจะสร้าง font ที่มีเฉพาะ icon ที่เราต้องการ ทำให้ font ที่ได้มีขนาดเล็กลงมากครับ
ที่สำคัญ เรายังสามารถเลือกสร้าง font จากชุด icon หลายๆ ชุดมาปนๆ กันได้ เจ๋งดี&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/loadcss/icomoon-app.png&quot; alt=&quot;icomoon app&quot; /&gt;&lt;/p&gt;

&lt;p&gt;ซึ่งแทนที่จะโหลดไฟล์ CSS ของ FontAwesome ผ่าน CDN ก็เปลี่ยนเป็นรวมไฟล์ CSS ของ icon font
ไว้ในไฟล์ &lt;code class=&quot;highlighter-rouge&quot;&gt;main.css&lt;/code&gt; ได้เลย (เปลี่ยนไฟล์ &lt;code class=&quot;highlighter-rouge&quot;&gt;.css&lt;/code&gt; เป็น &lt;code class=&quot;highlighter-rouge&quot;&gt;.scss&lt;/code&gt; แล้วไป &lt;code class=&quot;highlighter-rouge&quot;&gt;import&lt;/code&gt; ในไฟล์ &lt;code class=&quot;highlighter-rouge&quot;&gt;main.scss&lt;/code&gt;
ของธีม)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/loadcss/include-icon-font-css.png&quot; alt=&quot;รวม CSS ของ icon font ในไฟล์ main.css&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;☺ จำนวน http request ลดลง 1 request&lt;/li&gt;
  &lt;li&gt;☺ ขนาดไฟล์ของ icon font ลดลงจาก 55KB เหลือ 4.2KB (woff)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;google-fonts--asynchronous&quot;&gt;2. โหลด Google Fonts แบบ asynchronous&lt;/h2&gt;

&lt;p&gt;แทนที่การใช้ tag &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;link&amp;gt;&lt;/code&gt; เพื่อโหลดไฟล์ CSS จาก Google Fonts ด้วยการใช้ &lt;a href=&quot;https://github.com/typekit/webfontloader&quot;&gt;Web Font Loader&lt;/a&gt;
ซึ่งใช้ JavaScript แทน ข้อดีก็คือไฟล์จะถูกโหลดเข้ามาแบบ asynchronous ทำให้ไม่ไป block การ
render ของเพจ (non-blocking) ส่วนข้อเสียก็คือ ต้องมี request &lt;code class=&quot;highlighter-rouge&quot;&gt;webfont.js&lt;/code&gt; เพิ่มเข้ามา
อีกประมาณ 6.3KB ครับ&lt;/p&gt;

&lt;p&gt;แทนที่ (ใน tag &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;head&amp;gt;&lt;/code&gt;)&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#39;http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic&#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#39;stylesheet&#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#39;text/css&#39;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;ด้วย&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;WebFontConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;google&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;families&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&#39;Source+Sans+Pro:400,700,400italic,700italic:latin&#39;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;wf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;script&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;wf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;https:&#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;protocol&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;https&#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;http&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;&#39;://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;wf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;text/javascript&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;wf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;true&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;script&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parentNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;insertBefore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;wf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})();&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;(ในหน้า quick use ของ Google Fonts มี code ข้างบนให้ครับ)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;☺ CSS ของ web font ถูกโหลดเข้ามาแบบ non-blocking&lt;/li&gt;
  &lt;li&gt;☹ ต้องใช้ JavaScript&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;loadcss--css--asynchronous&quot;&gt;3. ใช้ &lt;code class=&quot;highlighter-rouge&quot;&gt;loadCss&lt;/code&gt; เพื่อโหลด CSS แบบ asynchronous&lt;/h2&gt;

&lt;p&gt;หลักการเดียวกันกับ web font load คือใช้ JavaScript เพื่อดึงไฟล์ CSS เข้ามาในเพจแทนการใช้
tag &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;link&amp;gt;&lt;/code&gt; ด้วยการใช้ &lt;a href=&quot;https://github.com/filamentgroup/loadCSS&quot;&gt;loadCss&lt;/a&gt; ซึ่งเป็น function ในการโหลดไฟล์ CSS แบบ asynchronous ครับ&lt;/p&gt;

&lt;p&gt;วิธีการใช้งานก็แค่ copy &amp;amp; paste function loadCss ไว้ใน tag &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;head&amp;gt;&lt;/code&gt; ของเราเลย
ขนาดของ function loadCss เล็กมากจนใส่แบบ inline ไปในเพจเลยก็ยังได้ (minify แล้วเหลือประมาณ 0.5KB)&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- ใน &amp;lt;head&amp;gt; --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;loadCSS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;use strict&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;script&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;styleSheets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;only x&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onload&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parentNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;insertBefore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onloadcssdefined&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=!&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onloadcssdefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)})},&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onloadcssdefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;all&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;แล้วเรียก function loadCss กับไฟล์ CSS ของเรา ซึ่งก็ควรมี tag &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; เป็น fallback สำหรับ
user ที่ไม่มี JavaScript (หรือปิดไว้) เพื่อโหลดไฟล์ CSS ด้วย tag &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;link&amp;gt;&lt;/code&gt; ตามปกติครับ&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- ใน &amp;lt;head&amp;gt; --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;loadCSS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;/css/main.css&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;noscript&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/css/main.css&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;media=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;all&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/noscript&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;☺ CSS ถูกโหลดเข้ามาแบบ non-blocking (asynchronous)&lt;/li&gt;
  &lt;li&gt;☹ ต้องใช้ JavaScript&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;เท่ากับว่า ถึงตอนนี้ในเพจไม่มี render-block resource เหลืออยู่เลย เพราะทุกอย่างถูกโหลดแบบ
asynchronous ซะหมด&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;แต่เดี๋ยวก่อน!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;เนื่องจากไฟล์ &lt;code class=&quot;highlighter-rouge&quot;&gt;main.css&lt;/code&gt; ถูกโหลดเข้ามาด้วย JavaScript ดังนั้นจะมีเวลาเสี้ยววินาทีที่ function loadCss ยัง
ไม่ทำงาน แต่ browser เริ่ม render ไปแล้ว ทำให้เพจดูเละๆ (เพราะ ณ ตอนนั้นยังไม่มี CSS เลย)
เพียงชั่วครู่ ก่อนจะถูก paint ทับด้วย CSS เมื่อ loadCss ทำงานเสร็จ เรียกเหตุการณ์นี้ว่า FOUC
หรือ Flash of Unstyled Content แม้จะเพียงเสี้ยววินาที แต่ก็สังเกตเห็นได้ และดูไม่ค่อยดีต่อ user ครับ&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/loadcss/unstyled-content.png&quot; alt=&quot;fouc&quot; /&gt;&lt;/p&gt;

&lt;p&gt;แก้ไขได้โดยการแยกเอา CSS เฉพาะส่วนที่จำเป็นจริงๆ กับการ render ออกจากไฟล์ CSS หลัก
แล้ว inline เข้าไปในเพจครับ ซึ่ง CSS ส่วนนี้เราเรียกว่าเป็น CSS ใน Critical Rendering Path จ้า&lt;/p&gt;

&lt;h2 id=&quot;critical-rendering-path-&quot;&gt;Critical Rendering Path ?&lt;/h2&gt;

&lt;p&gt;โดยปกติแล้ว content ส่วนแรกที่ user จะมองเห็นเป็นสิ่งแรกก็คือ content ที่อยู่เหนือขอบล่างของ browser
เป็น content ที่มองเห็นได้โดยไม่ต้อง scroll ลงมา เราเรียก content ส่วนนี้ว่า initial view หรือ
above the fold content ครับ หรือพูดง่ายๆ ก็คือ content ที่อยู่ใน viewport แรกนั่นเอง&lt;/p&gt;

&lt;p&gt;Critial Rendering Path ตามความหมายแล้วคือ ส่วนประกอบต่างๆ ที่จำเป็นที่สุดสำหรับการ render initial view&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;ถ้าเป็น HTML ก็นับเฉพาะ element ที่อยู่ใน initial view&lt;/li&gt;
  &lt;li&gt;ถ้าเป็น CSS ก็นับเฉพาะ property ของ element ที่อยู่ใน initial view&lt;/li&gt;
  &lt;li&gt;ส่วน JavaScript ก็เหมือนกัน เฉพาะที่เกี่ยวข้องกับ content ใน initial view&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ขนาดของ initial view นั้นก็แปรไปตามขนาดของ browser หรือ viewport ดังนั้น critical rendering path
ของแต่ละ browser/viewport/device ก็ต่างกันออกไปครับ&lt;/p&gt;

&lt;p&gt;แล้วเราจะรู้ได้ยังไงว่า CSS ส่วนไหนบ้างที่จำเป็นสำหรับ render initial view? คำตอบก็คือ ใช้ tool ช่วย
generate critical CSS ออกมาจากไฟล์ CSS เต็มครับ มีตัวเลือกมากมายหลายตัวเลย&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pocketjoso/penthouse&quot;&gt;Penthouse&lt;/a&gt; ใช้ง่านผ่าน node module/Grunt/Gulp สามารถระบุขนาดของ viewport ที่ต้องการเอา Critical CSS ออกมาได้&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/PaulKinlan/6284142&quot;&gt;Devtools Snippet&lt;/a&gt; รันใน Chrome Devtools ระบุขนาด viewport ไม่ได้ จะใช้ขนาด viewport ปัจจุบัน&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://jonassebastianohlsson.com/criticalpathcssgenerator/&quot;&gt;Critical Path CSS Generator&lt;/a&gt; ใช้บนเว็บได้เลย ผมเลือกใช้ตัวนี้เพราะง่ายที่สุดครับ แต่ก็ระบุขนาด viewport ไม่ได้นะ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;วิธีการใช้งานก็ตามที่บอกในเว็บเลย ใส่ URL ของหน้าเพจที่ต้องการ generate critical CSS พร้อมกับใส่
content ของ CSS ฉบับเต็มๆ ลงไป เจ้าเว็บนั้นก็จะดึงเอามาเฉพาะ critical CSS ให้ครับ (อย่าง CSS ของผม 9KB generate critical CSS แล้วได้ออกมา 3KB)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/loadcss/generated-critical-css.png&quot; alt=&quot;generated css&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Critical CSS ที่ได้ออกมานั้น ก็จับใส่ tag &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;style&amp;gt;&lt;/code&gt; ใส่ไว้ใน &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;head&amp;gt;&lt;/code&gt; ของเพจเลยครับ นั่นหมายความว่า &lt;strong&gt;ไฟล์ HTML จะมีขนาดใหญ่ขึ้น
และ CSS ที่เราใส่ไว้ใน &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;head&amp;gt;&lt;/code&gt; ก็จะไม่ถูก cache ไว้โดย browser&lt;/strong&gt; เพราะฉะนั้นต้องระวังไม่ให้ critical CSS มีขนาดใหญ่เกินไปด้วยครับ&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;ไม่มี tool ตัวไหนที่แม่นยำ 100% ต้องลองดูหลายตัว/หลายครั้ง แล้วเปรียบเทียบผลลัพธ์ดูครับ&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;section&quot;&gt;ผลลัพธ์&lt;/h2&gt;

&lt;p&gt;PageSpeed score เพิ่มขึ้นมาจาก 73 เป็น 94&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/loadcss/pagespeed-after-optimize.png&quot; alt=&quot;PageSpeed score หลัง optimize&quot; /&gt;&lt;/p&gt;

&lt;p&gt;ทดสอบกับ webpagetest.org: ถึงแม้เวลา first byte จะช้ากว่า (1 วินาที) แต่เวลาที่ start render นั้นไวกว่าก่อน optimize อยู่ที่ประมาณ 1.5 วินาที&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/loadcss/webpagetest-results.png&quot; alt=&quot;ผลทดสอบกับ webpagetest.org&quot; /&gt;&lt;/p&gt;

&lt;p&gt;ทดสอบกับ YSlow&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/loadcss/yslow-results.png&quot; alt=&quot;ผลทดสอบกับ YSlow&quot; /&gt;&lt;/p&gt;

&lt;p&gt;ที่สำคัญคือลองโหลดเพจแล้วรู้สึกว่าเร็วขึ้นอย่างสัมผัสได้! (ถ้าไม่ได้คิดไปเองนะ) .. ถ้าใช้งานกับเว็บที่ scale ใหญ่กว่านี้ น่าจะเห็นความแตกต่างได้มากกว่านี้ด้วยครับ ลองเล่นกันดูได้ ทำง่ายๆ ได้ที่บ้าน ไม่เสียเวลาเยอะอย่างที่คิด :P&lt;/p&gt;

&lt;h4 id=&quot;section-1&quot;&gt;อ่านเพิ่มเติม&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/critical-rendering-path/?hl=en&quot;&gt;Critical Rendering Path: Google Developers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.feedthebot.com/pagespeed/critical-render-path.html&quot;&gt;Critical Rendering Path: feedthebot.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.udacity.com/course/website-performance-optimization--ud884&quot;&gt;Website Performance Optimization: The Critical Rendering Path (Udacity)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="css" /><category term="rendering" /><category term="performance" /><category term="loadcss" /><summary>ผมเพิ่งเปลี่ยนธีมของ blog จาก Hyde มาเป็น Type (บังเอิญชื่อคล้ายกันด้วย) หลังจากปรับแต่งเก็บรายละเอียดแล้ว
ก็ลองเช็ค performance ของ blog ดูผ่าน PageSpeed Insights ก่อน optimize score จะอยู่ที่ 73 ในหน้าแรก</summary></entry><entry><title>ลองใช้ Prezto กับ zsh</title><link href="https://armno.github.io/2015/03/24/oh-my-zsh-to-prezto" rel="alternate" type="text/html" title="ลองใช้ Prezto กับ zsh" /><published>2015-03-24T00:00:00+00:00</published><updated>2015-03-24T00:00:00+00:00</updated><id>https://armno.github.io/2015/03/24/oh-my-zsh-to-prezto</id><content type="html" xml:base="https://armno.github.io/2015/03/24/oh-my-zsh-to-prezto">&lt;p&gt;สวัสดีชาวเนิร์ด&lt;/p&gt;

&lt;p&gt;ปกติผมใช้ &lt;a href=&quot;https://armno.github.io/2013/09/11/setting-up-the-terminal/&quot;&gt;zsh คู่กับ oh-my-zsh&lt;/a&gt; เพื่อสร้างความบันเทิงในการใช้งาน terminal ก็ใช้งานได้ดีปกติ ไม่มีปัญหาอะไร
แต่แล้ววันหนึ่งอากาศแจ่มใส ไม่รู้มีอะไรดลให้ &lt;a href=&quot;https://github.com/sorin-ionescu/prezto&quot;&gt;Prezto&lt;/a&gt; ผ่านมาให้พบเจอ&lt;/p&gt;

&lt;p&gt;เลยต้องลองเสียหน่อย&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/sorin-ionescu/prezto&quot;&gt;Prezto&lt;/a&gt; เป็น configuration framework ของ zsh เช่นเดียวกับ
&lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh&quot;&gt;oh-my-zsh&lt;/a&gt; ครับ ทำให้เราเพิ่มความสามารถ/ลูกเล่นให้กับ zsh ได้มาก
ไม่ว่าจะเป็น theme ของ prompt หรือ plugin (ใน Prezto จะเรียกว่า module) ซึ่งดูแล้วมากจะเป็นพวก alias มากกว่า
แรกเริ่มเดิมทีนั้น Prezto นั้นเป็น fork ของ oh-my-zsh แต่เนื่องจากแนวคิดไปคนละทางกับ oh-my-zsh เลยถูก rewrite ใหม่ซะเลย
(อ่านเรื่องต้นทางได้ที่ &lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/issues/377&quot;&gt;oh-my-zsh#377&lt;/a&gt; ยาวมาก)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/prezto/prezto-original-pr.png&quot; alt=&quot;Pull Request ต้นกำเนิด Prezto&quot; /&gt;&lt;/p&gt;

&lt;p&gt;พอสรุปได้ว่า oh-my-zsh นั้นเน้นที่ความง่ายในการใช้งาน ไม่ต้อง config มากมาย เซ็ตมาให้ก่อนแล้ว
ส่วน Prezto มีฟีเจอร์คล้ายๆ กับ oh-my-zsh แต่ส่วนมากจะถูก disable ไว้แล้วให้ user ไป enable เอาเองตามที่ต้องการ
เรื่องความเร็วผมรู้สึกว่า Prezto เร็วกว่านิดหน่อย ทั้งตอน startup และตอนที่ autocomplete ขึ้นมาจากการกด tab&lt;/p&gt;

&lt;h2 id=&quot;oh-my-zsh--prezto&quot;&gt;เปลี่ยนจาก oh-my-zsh ไปหา Prezto&lt;/h2&gt;

&lt;p&gt;Jerome Dalbert เขียนโพสต์ &lt;a href=&quot;http://jeromedalbert.com/migrate-from-oh-my-zsh-to-prezto/&quot;&gt;Migrate From Oh-my-zsh to Prezto&lt;/a&gt;
ลองตามไปอ่านกันได้ครับ สำหรับผมต้องลบไฟล์ &lt;code class=&quot;highlighter-rouge&quot;&gt;~/.zshrc&lt;/code&gt; ก่อนลง Prezto ด้วย ไม่งั้น Prezto ไม่ยอมทำ symlink ให้ครับ
ส่วนใครที่ยังไม่เคยลง oh-my-zsh ก็ข้ามไปลง Prezto ได้เลยครับ &lt;a href=&quot;https://github.com/sorin-ionescu/prezto#installation&quot;&gt;Installation Guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ในขั้นตอนการลบ oh-my-zsh ออกนั้น ไม่มีอะไรพังเลย (แปลกใจอยู่เหมือนกัน) แต่ทางที่ดี backup ไว้ก่อนดีกว่าครับ
(อุตส่าห์ทำใจไว้แล้วเชียวว่ามันต้องมีอะไรสักอย่างพัง และต้องซ่อมแน่ๆ แต่ไม่มีเลย)&lt;/p&gt;

&lt;h2 id=&quot;prezto&quot;&gt;เกี่ยวกับ Prezto&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;มีโครงสร้างและหลักการทำงานคล้ายๆ oh-my-zsh คือมี theme/module เก็บไว้ที่ directory &lt;code class=&quot;highlighter-rouge&quot;&gt;~/.zprezto&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;ไฟล์ config หลักของ Prezto คือ &lt;code class=&quot;highlighter-rouge&quot;&gt;~/.zpreztorc&lt;/code&gt; ลองเปิดอ่านดูได้ครับ มี comment กำกับไว้ค่อนข้างดี&lt;/li&gt;
  &lt;li&gt;Prezto ตัวมันเองก็ถูกเรียกผ่าน &lt;code class=&quot;highlighter-rouge&quot;&gt;~/.zshrc&lt;/code&gt; อีกที ในไฟล์ &lt;code class=&quot;highlighter-rouge&quot;&gt;~/.zshrc&lt;/code&gt; ก็จะเจอ code ประมาณนี้&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Source Prezto.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; -s &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ZDOTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/.zprezto/init.zsh&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ZDOTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/.zprezto/init.zsh&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/prezto/prezto-files.png&quot; alt=&quot;file ต่างๆ ของ Prezto&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;thememodule&quot;&gt;theme/module&lt;/h2&gt;

&lt;p&gt;เราสามารถใช้ command &lt;code class=&quot;highlighter-rouge&quot;&gt;$ prompt -l&lt;/code&gt; เพื่อดูรายชื่อ shell theme ทั้งหมดที่ Prezto มีอยู่ได้&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/prezto/prompt-l.png&quot; alt=&quot;output จาก prompt -l&quot; /&gt;&lt;/p&gt;

&lt;p&gt;และยัง preview ก่อนได้ด้วย &lt;code class=&quot;highlighter-rouge&quot;&gt;$ promt -p &amp;lt;theme name&amp;gt;&lt;/code&gt; ตรงนี้เจ๋งดี&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/prezto/prompt-paradox.png&quot; alt=&quot;preview theme paradox&quot; /&gt;&lt;/p&gt;

&lt;p&gt;เมื่อเลือก theme ได้แล้ว ก็ไปเซ็ตที่ไฟล์ &lt;code class=&quot;highlighter-rouge&quot;&gt;~/.zpreztorc&lt;/code&gt; หาคำว่า theme แล้วใส่ชื่อ theme ที่จะใช้ลงไป&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Set the prompt theme to load.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Setting it to &#39;random&#39; loads a random theme.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Auto set to &#39;off&#39; on dumb terminals.&lt;/span&gt;
zstyle &lt;span class=&quot;s1&quot;&gt;&#39;:prezto:module:prompt&#39;&lt;/span&gt; theme &lt;span class=&quot;s1&quot;&gt;&#39;cloud&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;ส่วน module (plugin) นั้น มี default มาให้บ้างแล้ว (ในไฟล์ &lt;code class=&quot;highlighter-rouge&quot;&gt;~/.zpreztorc&lt;/code&gt; อีกเช่นกัน)
ซึ่งลำดับในการเรียก module นั้นสำคัญ ถ้าเรียงผิด module นั้นก็อาจจะไม่ทำงานได้
module ที่ผมเพิ่มเข้าไปมีอีก 2 อันคือ &lt;code class=&quot;highlighter-rouge&quot;&gt;syntax-highlighting&lt;/code&gt; กับ &lt;code class=&quot;highlighter-rouge&quot;&gt;history-substring-search&lt;/code&gt;&lt;/p&gt;

&lt;h3 id=&quot;syntax-highlighting&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;syntax-highlighting&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;ตามภาพเลยครับ ทำให้มี shell command เป็นสีๆ คล้าย fish shell&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/prezto/syntax-highlight-disabled.png&quot; alt=&quot;ปิด module syntax highlighting&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/prezto/syntax-highlight-enabled.png&quot; alt=&quot;เปิด module syntax highlighting&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;history-substring-search&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;history-substring-search&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;ใน terminal เราใช้ลูกศรขึ้น-ลงเพื่อเลื่อนหา command ใน history ที่เคยพิมพ์ไว้ได้
แต่ module ตัวนี้ทำให้ scope ของ history ของ command เหลือเฉพาะ keyword ที่เราพิมพ์ได้&lt;/p&gt;

&lt;p&gt;อย่างเช่น ผมพิมพ์ &lt;code class=&quot;highlighter-rouge&quot;&gt;vi&lt;/code&gt; แล้วกด ขึ้น ไปเรื่อยๆ ก็จะมี history ขึ้นมาเฉพาะ command ที่มี &lt;code class=&quot;highlighter-rouge&quot;&gt;vi&lt;/code&gt; อยู่ข้างใน
พร้อมกับ highlight ให้ด้วย ดีครับดี&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/prezto/substring-search.png&quot; alt=&quot;substring history search ใน Prezto&quot; /&gt;&lt;/p&gt;

&lt;p&gt;จากที่ใช้ Prezto แทน oh-my-zsh มา ก็ยังไม่พบปัญหาอะไร และก็คงจะใช้เรื่อยๆ ไปก่อน ลองเล่นกันดูได้ครับ&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ปล. zsh framework อีกตัวนึงที่น่าสนใจคือ &lt;a href=&quot;https://github.com/zsh-users/antigen&quot;&gt;Antigen&lt;/a&gt; ครับผม&lt;/em&gt;&lt;/p&gt;</content><category term="zsh" /><category term="prezto" /><category term="terminal" /><category term="nerd" /><summary>สวัสดีชาวเนิร์ด</summary></entry><entry><title>Setting up Vim : Part II</title><link href="https://armno.github.io/2015/02/26/setting-up-vim-part-2" rel="alternate" type="text/html" title="Setting up Vim : Part II" /><published>2015-02-26T00:00:00+00:00</published><updated>2015-02-26T00:00:00+00:00</updated><id>https://armno.github.io/2015/02/26/setting-up-vim-part-2</id><content type="html" xml:base="https://armno.github.io/2015/02/26/setting-up-vim-part-2">&lt;p&gt;เคยเขียน &lt;a href=&quot;https://armno.github.io/2013/09/05/setting-up-vim/&quot; title=&quot;Setting up Vim part I&quot;&gt;Setting up Vim&lt;/a&gt; ตอนแรกไปแล้ว พอใช้งานไปเรื่อยๆ ผมว่ามีอะไรหลายๆ อย่างที่ปรับเปลี่ยนไปตามการใช้งาน
เลยขอรวมรวม plugin/setup ที่เปลี่ยนไปจากตอนแรกมาดูครับ&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;ใช้งานบน OSX 10.10 เป็นหลัก เวอร์ชั่นอื่นอาจทำงานได้เหมือนกัน แต่ไม่รับประกันนะ&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;pathogen--vundle&quot;&gt;Pathogen → Vundle&lt;/h2&gt;

&lt;p&gt;ก่อนหน้านี้ผมใช้ &lt;a href=&quot;https://github.com/tpope/vim-pathogen&quot; title=&quot;Pathogen.vim&quot;&gt;Pathogen&lt;/a&gt; เป็นตัวจัดการ plugin ของ Vim ซึ่งปัญหาที่ผมตามมาก็คือ ตอนย้ายเครื่องไปทำงานที่เครื่องอื่น
ย้าย plugin ที่ติดตั้งผ่าน Pathogen ไปด้วยยาก (Pathogen ใช้ git submodules ซึ่งไม่ค่อยสะดวกเท่าไหร่)
(ความจริงคือผมไม่ค่อยเข้าใจ git submodule) ส่วนการจะ update plugin ก็ต้อง update
ผ่าน submodules เช่นกัน .. เอาเป็นว่าผมแพ้ git submodules&lt;/p&gt;

&lt;p&gt;เลยลองเปลี่ยนมาใช้ &lt;a href=&quot;https://github.com/gmarik/Vundle.vim&quot; title=&quot;Vundle.vim&quot;&gt;Vundle&lt;/a&gt; แทน Vundle ทำให้สามารถเก็บรายชื่อ plugin ไว้ในไฟล์ &lt;code class=&quot;highlighter-rouge&quot;&gt;.vimrc&lt;/code&gt; ได้เลย
จะเพิ่ม/ลบ/update plugin นั้นจะง่ายกว่า Pathogen มาก ทำได้ใน vim เลย&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;:PluginInstall
:PluginUpdate
:PluginClean&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;วิธีติดตั้งแบบละเอียด ดูได้จาก &lt;a href=&quot;https://github.com/gmarik/Vundle.vim#quick-start&quot;&gt;Quick start guide&lt;/a&gt; ของ Vundle ได้เลยครับ&lt;/p&gt;

&lt;h2 id=&quot;link-vim-config--dotfiles&quot;&gt;link Vim config กับ dotfiles&lt;/h2&gt;

&lt;p&gt;ผมมี repo &lt;a href=&quot;https://github.com/armno/dotfiles&quot;&gt;dotfiles&lt;/a&gt; ไว้เก็บ configuration ของโปรแกรมต่างๆ รวมถึง Vim ด้วย มีไฟล์ &lt;code class=&quot;highlighter-rouge&quot;&gt;.vimrc&lt;/code&gt; กับโฟลเดอร์ &lt;code class=&quot;highlighter-rouge&quot;&gt;.vim&lt;/code&gt; ทำให้แชร์ config ของ Vim ได้จากการทำ symlink มาที่ repo dotfiles&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;git clone https://github.com/armno/dotfiles.git ~/dotfiles
&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;ln -s ~/dotfiles/.vimrc ~/.vimrc
&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;ln -s ~/dotfiles/.vim ~/.vim&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;เวลาอัพเดท config ใน &lt;code class=&quot;highlighter-rouge&quot;&gt;.vimrc&lt;/code&gt; ก็สามารถ push ไปที่ repo dotfiles เพื่ออัพเดท vim config ในเครื่องอื่นๆ ได้ด้วย&lt;/p&gt;

&lt;h2 id=&quot;ctrlp--the-silver-searcher&quot;&gt;CtrlP + The Silver Searcher&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/kien/ctrlp.vim&quot;&gt;CtrlP&lt;/a&gt; เป็น plugin ของ vim ที่ทำงานได้คล้ายกับ &lt;code class=&quot;highlighter-rouge&quot;&gt;cmd+p&lt;/code&gt; (หรือ &lt;code class=&quot;highlighter-rouge&quot;&gt;cmd+t&lt;/code&gt;) ใน Sublime Text ใช้เพื่อเปิดไฟล์ในโปรเจ็ค หรือจาก buffer ที่กำลังใช้อยู่ ผ่าน fuzzy search จาก path ได้ (พิมพ์แค่บางส่วนของ path) ใช้ CtrlP นั้นทำให้หา และเปิดไฟล์ได้เร็วกว่า file explorer (NERDTree) ได้เยอะเลย&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/vim-ctrlp.png&quot; alt=&quot;vim ctrlp&quot; /&gt;&lt;/p&gt;

&lt;p&gt;แต่ fuzzy search ที่ติดมากับ CtrlP นั้น บางทีก็ช้าอยู่บ้างกับโปรเจ็คใหญ่ๆ โชคดีที่ CtrlP เราสามารถใช้ “custom command” ในการ search หาไฟล์ได้ ผมใช้ &lt;a href=&quot;https://github.com/ggreer/the_silver_searcher&quot;&gt;The Silver Searcher&lt;/a&gt; ซึ่งเร็วกว่าพอสมควร&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-vim&quot; data-lang=&quot;vim&quot;&gt;# ในไฟล์ &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;vimrc
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;g:ctrlp_user_command&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;ag %s -l --nocolor -g &quot;&quot;&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;powerline--vim-airline&quot;&gt;แทนที่ Powerline ด้วย Vim-airline&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/bling/vim-airline&quot;&gt;vim-airline&lt;/a&gt; เป็น plugin ที่เราเซ็ต status bar แบบฉูดฉาดเหมือน powerline ได้ แต่โหลดเร็วกว่า (และไม่ต้องลง python ด้วย) แถมยังทำงานร่วมกับ plugin ตัวอื่นๆ ของ vim ได้ดีอีกด้วย&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/vim-airline.png&quot; alt=&quot;vim airline&quot; /&gt;&lt;/p&gt;

&lt;p&gt;นอกจากนี้ก็เป็น plugin อื่นๆ ที่เกี่ยวกับแต่ละภาษาที่เขียน list เต็มๆ ของผมอยู่ในไฟล์ &lt;a href=&quot;https://github.com/armno/dotfiles/blob/master/.vimrc#L33-L59&quot;&gt;.vimrc&lt;/a&gt; ครับ&lt;/p&gt;

&lt;p&gt;ปล. ทุกวันนี้ก็ยังใช้ vim กับ sublime text สลับกันไปมา แล้วแต่ลักษณะงานครับ&lt;/p&gt;</content><category term="vim" /><category term="terminal" /><category term="vundle" /><summary>เคยเขียน Setting up Vim ตอนแรกไปแล้ว พอใช้งานไปเรื่อยๆ ผมว่ามีอะไรหลายๆ อย่างที่ปรับเปลี่ยนไปตามการใช้งาน
เลยขอรวมรวม plugin/setup ที่เปลี่ยนไปจากตอนแรกมาดูครับ</summary></entry><entry><title>git stash &amp;amp; git patched commit</title><link href="https://armno.github.io/2014/10/14/git-stash-patched-commit" rel="alternate" type="text/html" title="git stash &amp; git patched commit" /><published>2014-10-14T00:00:00+00:00</published><updated>2014-10-14T00:00:00+00:00</updated><id>https://armno.github.io/2014/10/14/git-stash-patched-commit</id><content type="html" xml:base="https://armno.github.io/2014/10/14/git-stash-patched-commit">&lt;p&gt;(สถานการณ์จำลอง)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A: (coding อย่างขะมักเขม้น)&lt;/li&gt;
  &lt;li&gt;B: “แก้ bug ตรงนี้ให้หน่อย แป๊ปเดียว” / “เพิ่ม feature นี้หน่อย ลูกค้าอยากได้”&lt;/li&gt;
  &lt;li&gt;B: &lt;strong&gt;เอาตอนนี้เลย&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;A: …&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(สถานการณ์จำลอง 2)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A: (coding อย่างขะมักเขม้น)&lt;/li&gt;
  &lt;li&gt;C: (เป็น dev ด้วยกัน) “pull branch X ไป review code/run หน่อย เพิ่ง push ไป”&lt;/li&gt;
  &lt;li&gt;A: …&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;การมี &lt;code class=&quot;highlighter-rouge&quot;&gt;git&lt;/code&gt; นั้นทำให้เราสามารถทำ snapshot ของงานส่วนที่เรากำลังทำอยู่ได้ โดยไม่ไปทำของคนอื่นพัง และงานเราไม่หายด้วย ปกติผมจะใช้ 2 command นี้ครับ&lt;/p&gt;

&lt;h2 id=&quot;git-stash&quot;&gt;1. &lt;code class=&quot;highlighter-rouge&quot;&gt;git stash&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;git stash&lt;/code&gt; ถ้าแปลตรงตัวก็แปลว่า “ซ่อน” code ของเราไว้ก่อน โดย code ที่เราซ่อนไว้จะถูกเก็บใน stash stack และทำให้ repo ของเรา clean เมื่อ stash ไว้แล้วครับ&lt;/p&gt;

&lt;p&gt;ตัวอย่างเช่น ใน repo ของเรามี dirty file จาก &lt;code class=&quot;highlighter-rouge&quot;&gt;git status&lt;/code&gt; (ข้างขวาเป็น output ของ &lt;code class=&quot;highlighter-rouge&quot;&gt;git diff&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3949/15347262219_9c6e4a783c_c.jpg&quot; alt=&quot;a dirty repo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;เราอยากซ่อน changes ของทั้ง 2 file นี้ไว้ ก็ใช้คำสั่ง &lt;code class=&quot;highlighter-rouge&quot;&gt;git stash&lt;/code&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;git stash&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;repo ของเราก็จะกลับมา clean เหมือนเดิม โดยคำสั่ง stash จะบอก HEAD commit hash ว่า repo ของเราถูก revert ไปที่ commit ใด (ปกติก็เป็น commit ล่าสุดก่อนที่มันจะ dirty แหละ)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5604/15353372667_1f43fdb4d7_z.jpg&quot; alt=&quot;git stashed&quot; /&gt;&lt;/p&gt;

&lt;p&gt;ถ้าเราแก้ code ไปแล้ว อยาก stash อีก ก็ทำได้ โดยที่ stash ครั้งต่อๆ ไปจะถูกเก็บใน stack เรียกดูได้จาก command &lt;code class=&quot;highlighter-rouge&quot;&gt;git stash list&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3935/15539461345_34e1283e54_o.png&quot; alt=&quot;git 2nd stash&quot; /&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;git stash list&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3931/15353821700_3073afaee2.jpg&quot; alt=&quot;git stash list&quot; /&gt;&lt;/p&gt;

&lt;p&gt;เอา code ที่ stash ไว้ ออกมาจาก stack เพื่อทำงานต่อ ใช้ command &lt;code class=&quot;highlighter-rouge&quot;&gt;git stash pop&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3933/15353530378_5c268ab9d8_o.png&quot; alt=&quot;git stash pop&quot; /&gt;&lt;/p&gt;

&lt;p&gt;และเนื่องจากมันเป็น stack เวลา pop มันเลยเอา stash ล่าสุดออกมาก่อน ซึ่งพอ pop ออกมาแล้ว stash นั้นก็จะหายไปจาก list ครับ (ถ้าอยาก pop แบบไม่ให้มันหาย ใช้ command &lt;code class=&quot;highlighter-rouge&quot;&gt;git stash apply&lt;/code&gt; แทน)&lt;/p&gt;

&lt;h3 id=&quot;git-stash--untracked-file&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;git stash&lt;/code&gt; กับ untracked file&lt;/h3&gt;

&lt;p&gt;ปกติแล้ว &lt;code class=&quot;highlighter-rouge&quot;&gt;git stash&lt;/code&gt; จะไม่เก็บไฟล์ที่ untracked ไปด้วย (ไฟล์ที่ยังไม่ได้ add ใน git)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5615/15353029939_f6996515ee_z.jpg&quot; alt=&quot;git stash ไม่เก็บไฟล์ untracked&quot; /&gt;&lt;/p&gt;

&lt;p&gt;ต้องเพิ่ม parameter &lt;code class=&quot;highlighter-rouge&quot;&gt;-u&lt;/code&gt; เข้าไปด้วย ให้มัน stash ไฟล์ที่ untracked ไปด้วยครับ&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5614/15354024460_6985843d64_z.jpg&quot; alt=&quot;git stash with -u&quot; /&gt;&lt;/p&gt;

&lt;p&gt;พอ pop ออกมา ไฟล์ที่เป็น untracked file ก็ยังอยู่ครบเหมือนเดิม&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3942/15353147449_159851951c_z.jpg&quot; alt=&quot;git stash pop with untracked file&quot; /&gt;&lt;/p&gt;

&lt;p&gt;workflow คร่าวๆ ก็คือ stash งานของเราไว้ก่อน &amp;gt; ทำส่วนอื่นให้เสร็จ &amp;gt; push งานใหม่ไป &amp;gt; pop stash ออกมาทำต่อ ประมาณนี้ครับ&lt;/p&gt;

&lt;h2 id=&quot;git-addcommit--p&quot;&gt;2. &lt;code class=&quot;highlighter-rouge&quot;&gt;git add/commit -p&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;--patch&lt;/code&gt; หรือ &lt;code class=&quot;highlighter-rouge&quot;&gt;-p&lt;/code&gt; เป็น parameter ของ command &lt;code class=&quot;highlighter-rouge&quot;&gt;git add&lt;/code&gt; และ &lt;code class=&quot;highlighter-rouge&quot;&gt;git commit&lt;/code&gt; ทำให้เราสามารถเลือก add หรือ commit เฉพาะบางส่วนของ code ที่เราแก้ไขไปแล้ว โดย code ส่วนที่เหลือ ก็ยังคงเป็นสถานะ modified (unstaged) อยู่&lt;/p&gt;

&lt;p&gt;ตัวอย่างเช่น ผมมีไฟล์ &lt;code class=&quot;highlighter-rouge&quot;&gt;index.html&lt;/code&gt; ที่อัพเดท code ไปบางส่วนแล้ว รัน &lt;code class=&quot;highlighter-rouge&quot;&gt;git diff&lt;/code&gt; แล้วได้ออกมาแบบนี้&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3956/14921984934_f13f0300b9_c.jpg&quot; alt=&quot;modified code&quot; /&gt;&lt;/p&gt;

&lt;p&gt;รัน &lt;code class=&quot;highlighter-rouge&quot;&gt;git add -p index.html&lt;/code&gt; git จะแบ่ง code ออกเป็นส่วนย่อยๆ (hunks) แล้วให้เรารีวิวว่า จะเลือกทำอะไรกับ hunk นั้นๆ รูปข้างล่างนี้จะเห็นว่ามี prompt ให้มาให้เราเลือก ซึ่งตัวเลือกก็มี &lt;code class=&quot;highlighter-rouge&quot;&gt;y&lt;/code&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;n&lt;/code&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;q&lt;/code&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;a&lt;/code&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;d&lt;/code&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;/&lt;/code&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;j&lt;/code&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;J&lt;/code&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;g&lt;/code&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;e&lt;/code&gt; และก็ &lt;code class=&quot;highlighter-rouge&quot;&gt;?&lt;/code&gt; ซึ่งเราสามารถเลือก &lt;code class=&quot;highlighter-rouge&quot;&gt;?&lt;/code&gt; แล้วกด enter เพื่อดูความหมายของแต่ละตัวเลือกได้ (ผมเองก็ไม่เคยจะจำได้เหมือนกัน)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5608/15356163429_da0aa59b9e_z.jpg&quot; alt=&quot;interactive add&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3946/15356691278_05f7357447_z.jpg&quot; alt=&quot;available options&quot; /&gt;&lt;/p&gt;

&lt;p&gt;ที่ผมใช้บ่อยๆ ก็จะมี&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;y&lt;/code&gt; หรือ yes เพื่อ add hunk นี้เข้า staged zone&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;n&lt;/code&gt; หรือ no ยังไม่ add hunk นี้&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;q&lt;/code&gt; หรือ quit ออกจาก interactive mode (หยุดการทำงานของ &lt;code class=&quot;highlighter-rouge&quot;&gt;git add -p&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;s&lt;/code&gt; หรือ split ซอย hunk นี้ให้เล็กลงกว่าเดิม&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวเลือก &lt;code class=&quot;highlighter-rouge&quot;&gt;s&lt;/code&gt; นั้นมีประโยชน์มาก เนื่องจากปกติแล้ว git จะแบ่ง code ออกเป็น hunk ให้เอง โดยที่ code ที่อยู่ใกล้ๆ กันรวมเป็น hunk เดียวกัน ซึ่งจริงๆ แล้ว code ที่อยู่ใกล้กันนั้นอาจจะเป็นคนละส่วนกันก็ได้ &lt;em&gt;(จริงๆ แล้ววิธีการแบ่ง hunk ของ git นั้นมีหลักเกณฑ์มากกว่านี้ แต่ขอข้ามไปละกันครับ ผมเองไม่ได้เข้าใจทั้งหมดเหมือนกัน)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;อย่างตอนนี้ผม add เฉพาะ hunk แรก พอรัน &lt;code class=&quot;highlighter-rouge&quot;&gt;git status&lt;/code&gt; ก็จะเห็นสถานะทั้ง staged และ modified (unstaged) จากไฟล์เดียวกัน&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3954/15540282891_0b83fa8a31.jpg&quot; alt=&quot;added patch&quot; /&gt;&lt;/p&gt;

&lt;p&gt;ซึ่งพอ commit ไปแล้ว code ส่วนยังเหลือ ก็ยังอยู่ในสถานะ modified (unstaged) เหมือนเดิม&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3930/15357360570_8d37b5040c_z.jpg&quot; alt=&quot;remaining code&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;section&quot;&gt;สรุป&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;git stash&lt;/code&gt; เอาไว้ซ่อน modified code และทำให้ repo ของเรากลับมา clean เทียบจาก commit ล่าสุด&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;git stash pop&lt;/code&gt; เรียก code ที่ stash ไว้ล่าสุดออกมา&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;git add(commit) -p&lt;/code&gt; add หรือ commit ทีละส่วนของ code แบบ interactive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ในชีวิตประจำวัน ผมจะใช้ &lt;code class=&quot;highlighter-rouge&quot;&gt;git add -p&lt;/code&gt; เกือบทุกครั้ง หลักๆ เพื่อเลือก add/commit เฉพาะเท่าที่จำเป็น กรองเอา code ขยะออก และได้โบนัสเป็นการ review code ที่ตัวเองเขียนไปในตัวด้วย ส่วน &lt;code class=&quot;highlighter-rouge&quot;&gt;git stash&lt;/code&gt; นั้น นานๆ จะได้ใช้ทีนึงครับ&lt;/p&gt;</content><category term="git" /><category term="terminal" /><summary>(สถานการณ์จำลอง)</summary></entry></feed>
