Tutorial

Building Blazing-fast static site with Gatsby

By Arnon Puitrakul - 11 กรกฎาคม 2018

Building Blazing-fast static site with Gatsby

จากตอนที่แล้ว ที่เราได้ลองสร้าง Project และหน้าที่เป็น Counter กันคร่าว ๆ แล้ว วันนี้เราจะมาลองมาตกแต่งหน้ากัน

ถ้าเป็นการทำเว็บทั่ว ๆ ไปเราก็อาจจะใช้สิ่งที่เรียกว่า CSS ในการ Style ตัวหน้าของเราให้ออกมาเป็นแบบที่ต้องการ ถ้าเปรียบ HTML เป็นเหมือนโครงร่างของเว็บ CSS ก็คงเป็นเหมือนสีที่ทำให้เว็บเรามีสีสัน มีชีวิตชีวาขึ้นมา วันนี้เราเลยจะมาลองทำให้เว็บเรามีสีสัน มีชีวิตชีวา ด้วยหลาย ๆ วิธีที่ใช้ในการเขียน CSS ใน React กัน

Inline CSS in JSX

วิธีแรกมันน่าจะดูบาปไปหน่อย (พี่เนยไม่ได้กล่าวไว้) นั่นคือการเขียน Inline ลงไปใน JSX เลย เราสามารถทำได้โดยการ โยน Props ที่ชื่อว่า style ในรูปแบบของ Object ได้เลย ให้ลองย้อนกลับไปดู Code ของหน้า Counter จากคราวก่อนกัน

<Layout>
  <div>
	   <p>{this.state.currentNumber}</p>
	   <button onClick={this.addNumber}>+</button>
	   <button onClick={this.decreaseNumber}>-</button>
     <Link to={"/"}>To Homepage</Link>
  </div>
</Layout>

จากด้านบนคือส่วนที่หน้าที่ชื่อว่า Counter (ที่สร้างไว้ในตอนที่ 1) ทีนี้เราจะมาลองทำให้แต่ละ Element ในหน้าเรียงเป็น 1 Column กันโดยการใช้ Flexbox ใน CSS

<Layout>
  <div style={{display: 'flex', flexDirection: 'column'}}>
	   <p>{this.state.currentNumber}</p>
	   <button onClick={this.addNumber}>+</button>
	   <button onClick={this.decreaseNumber}>-</button>
     <Link to={"/"}>To Homepage</Link>
  </div>
</Layout>

เราจะเห็นว่าผมเพิ่มส่วนของ style แล้วแนบ Object ที่ประกอบด้วย 2 Element ลงไปนั่นคือ display และ flexDirection

Example 1 Gatsby

เราก็จะได้หน้าที่ทุก Element นั่นคือ กล่องข้อความ, ปุ่ม และ Link เรียงกันเป็น 1 Column แล้ว

ในส่วนของ Code ตรง display อาจจะไม่ใช่ปัญหาเท่าไหร่ จุดที่น่าจะสงสัยกันคือ flexDirection มากกว่า จริง ๆ แล้วมันคือ flex-direction ใน CSS ธรรมดานี่ละ สาเหตุที่เราต้องใช้แบบไม่มีขีดแล้วเป็น Camel Case แทน นั่นเป็นเพราะ ถ้าเราใส่ขีดเข้าไปมันจะไปซำ้กับการลบเลข แล้วพอเจอตัวหนังสืออะไรก็ไม่รู้ มั่ว ๆ ไปมาเรียงต่อกัน ลบอะไรกันก็ไม่รู้ สุดท้ายมันก็จะพ่น Error ออกมาในที่สุด เพราะฉะนั้น CSS ตัวไหนที่ปกติเราเขียนแล้วมีขีดอยู่ก็ให้เปลี่ยนเป็น Camel Case ให้หมด

ส่วนที่เหลือถ้าอยากให้สวยขึ้นก็ลองหยุดอ่านแล้วไปลองนั่งเล่นกับมันก่อน แล้วค่อยมาต่อได้ เริ่ม !!

CSS Module

จากวิธีแรกเราจะเห็นว่า ถ้าเราต้องมานั่งใส่ Inline ทุกอันนี่น่าจะสร้างความบรรลัยให้กับ Code ของเราอย่างรุนแรง ไม่งั้นทุกคนก็ใช้ Inline CSS กันหมดแล้วสิ เลยทำให้ผมจะมานำเสนออีกวิธีนึงนั่นคือการใช้ CSS Module

ง่าย ๆ CSS Module คือ CSS File ที่ถูกซอยย่อยเป็นแต่ละ Module เล็ก ๆ โดยเราสามารถดึงมันมาใช้ได้อย่างง่ายดาย

วิธีการสร้างก็แสนง่าย โดย Gatsby มันทำการตั้งค่าอะไรมาให้เราหมดแล้ว เพียงแค่เราสร้างไฟล์ที่มีชื่ออะไรก็ได้ตามใจเรา แล้วลงท้ายด้วย .module.css เท่ากันก็เพียงพอ ตอนนี้ให้เราลองสร้างไฟล์ชื่อ counter.module.css และลองเพิ่ม Code ตามด้านล่างลงไปในไฟล์

.container {
  display: flex;
  flex-direction: column;
}

ลองทำดูก็จะร้อง อ้าว !! นี่มันก็ CSS ธรรมดานิ แล้วมันก็คือ Style ที่เราเขียนเมื่อครู่ด้วย ใช่ครับ เราจะแทนที่ Inline CSS ด้วย CSS Module กัน ทีนี้ ให้เรากลับไปที่ counter.js แล้วเอา style ที่เราเพิ่มตอนแรกออก แล้วสั่ง Import ตรงบรรทัดถัดจาก Import Layout ตามด้านล่างนี้

import counterStyle from './counter.module.css'

จากนั้นให้เราลงมาดูตรงที่ Return แล้วเพิ่ม Code ให้เป็นเหมือนด้านล่างนี้

<Layout>
  <div **className={counterStyle.container}**>
	   <p>{this.state.currentNumber}</p>
	   <button onClick={this.addNumber}>+</button>
	   <button onClick={this.decreaseNumber}>-</button>
     <Link to={"/"}>To Homepage</Link>
  </div>
</Layout>

จะเห็นว่าเราใช้ Keyword คำว่า className ถ้าเราเขียน HTML ธรรมดา มันคือคำว่า class เหมือนกันเลย แต่ถ้าเราใช้คำว่า class ใน JSX เลยมันจะไปซ้ำกับ Reserve Word คำว่า class ที่แปลว่า class ใน OOP แทนซะงั้น เลยต้องใช้เป็นคำว่า className เอง

ส่วนค่าที่เรายัดลงไปใน className คือเราอ้างอิงจาก ชื่อ CSS Module ที่เรา Import เข้ามา แล้วตามด้วยจุดและชื่อของ Class ที่เราเขียนลงไปใน CSS File ที่พึ่งทำไป ซึ่งในตัวอย่างก็คือคำว่า container นั่นเอง

Inline CSS & CSS Module
Inline CSS รูปซ้าย และ CSS Module รูปขวา

ถ้าเราลองทำแล้วเซฟดู เราจะเห็นว่าผลนั้นไม่ต่างจากรอบแรกที่เราทำโดยใช้ Inline CSS เลย แต่เมื่อเราดู Source Code ผ่านหน้าต่าง Inspect ใน Web Browser แล้ว เราจะเห็นว่า Inline CSS จะฝัง Style ลงไปใน Element นั้นเลย เหมือนเราเขียน style แปะลง HTML ธรรมดาเลย (รูปซ้าย) แต่ถ้าเราใช้ CSS Module มันจะใช้ลักษณะของการอ้างอิง Class ใน CSS แทน ที่มันจะสร้าง External CSS File ขึ้นมาแล้ว Reference ไปอีกทอดนึง (รูปขวา) ถ้าเรากดไปที่ Tab Network, Refresh และ Filter เฉพาะ CSS ขึ้นมา เราจะเห็น CSS File ถูกโหลดเข้ามา แต่มันจะเป็นชื่อแปลก ๆ หรือแม้แต่ชื่อ Class ก็ไมได้เป็นชื่อที่เราตั้งไว้ เพราะตัว CSS Module ใน Gatsby มันจัดการให้เราแล้วนั่นเอง

Styled-Components

มาถึงวิธีสุดท้ายนั่นคือการใช้ styled-components กัน วิธีนี้เป็นวิธีที่ผมชอบมาก เพราะความง่ายของมัน

styled-components เป็น Library ตัวนึงช่วยสร้าง Component ให้เราจาก Basic HTML Element ต่าง ๆ เช่น div และ a เป็นต้น โดยเราสามารถสร้างออกมาเป็น Component แล้วเอาไปใช้ได้เหมือน Component ปกติได้เลย อาจจะ งง เดี๋ยวเราลองมาเริ่มใช้กันดีกว่า

ต่างจาก CSS Module ที่ Gatsby มีมาให้แล้ว การจะใช้ styled-components เราจะต้องทำการติดตั้ง Plugin กันก่อน ให้รันคำสั่งตามด้านล่างนี้เลย

yarn add gatsby-plugin-styled-components styled-components babel-plugin-styled-components

หรือถ้าใครใคร่อยากใช้ NPM ก็เอาที่สบายใจ

npm install --save gatsby-plugin-styled-components styled-components babel-plugin-styled-components

หลังจากนั้นให้เราเปิดไฟล์ gatsby-config.js ขึ้นมา เราก็จะได้หน้าตาประมาณนี้

module.exports = {
  siteMetadata: {
    title: 'Gatsby Default Starter',
  },
  plugins: ['gatsby-plugin-react-helmet'],
}

จากนั้นให้เราเพิ่ม Plugin ลงไป โดยการแก้ใน List ของ Plugin เป็นตามด้านล่างนี้

module.exports = {
  siteMetadata: {
    title: 'Gatsby Default Starter',
  },
  plugins: [
    'gatsby-plugin-react-helmet',
    'gatsby-plugin-styled-components'
  ],
}

จาก Code ด้านบน เราก็ได้เพิ่ม Plugin ที่เราพึ่ง Install ลงไปผ่านคำสั่งเมื่อครู่ นั่นก็คือ gatsby-plugin-styled-components นั่นเอง แล้วเราก็สั่ง yarn develop ใหม่

ทีนี้เราจะมาสร้าง Component โดยการใช้ styled-components กัน โดยให้เรากลับไปที่ไฟล์ counter.js แล้วลองเติม Code ชุดนี้ลงไปใน counter.js ตรง แถว ๆ Import ดู

import styled from 'styled-components'

const Container = styled.div`
  display: flex;
  flex-direction: column;
`

จาก Code เราก็ทำการ Import styled-components เข้ามา แล้วสร้าง Component จาก styled-components ที่เป็น div แล้ว ใส่ Style ลงไปเหมือนกับที่เราเขียนกันก่อนหน้านี้ แล้วตรง div ที่เป็น container เราก็เปลี่ยนจากคำว่า div เป็นคำว่า Container แทน ฉะนั้น JSX ของเราก็จะเป็นแบบด้านล่างนี้

<Layout>
   <Container>
     <p>{this.state.currentNumber}</p>
     <button onClick={this.addNumber}>+</button>
     <button onClick={this.decreaseNumber}>-</button>
     <Link to={"/"}>To Homepage</Link>
   </Container>
</Layout>

หลังจากที่เราสร้าง Component จาก styled-components ที่ชื่อว่า Container ไปแล้ว ในส่วนของ Code ด้านบนก็จะเป็นการเรียกใช้ Component ที่พึ่งสร้างไป โดยการเรียกผ่าน Tag ได้เลย อย่าตกใจไปว่ามันเป็น Tag อะไร เพราะตอนนี้เราไม่ได้เขียน HTML แต่เราเขียน JSX อยู่ เพราะฉะนั้นเราก็สร้างเหมือนกับสร้าง Tag ใช้เองได้

โดยหลัก ๆ แล้ว ผมจะแนะนำให้ใช้ styled-components เพราะรู้สึกว่า เวลาใช้มันค่อนข้างที่จะใช้ง่าย และยังรองรับการ extends อะไรพวกนั้นได้ มันทำให้ชีวิตง่ายขึ้นเยอะมาก แนะนำให้ลองไปเปิด Document ของ styled-component อ่านดูแล้วจะรู้ว่ามัน Powerful ขนาดไหน

Bonus : Typography Style ด้วย Typography.js

ทุก ๆ เว็บก็ต้องมีการใช้งานพวกตัวหนังสือแน่นอน ไม่งั้นทั้งเว็บมันก็จะมีแต่รูปภาพ และแน่นอนอีกว่า ถ้าเรามีตัวหนังสือ เราก็ต้องเขียน CSS มาควบคุมพวก รูปแบบ, ขนาดและสีของ Font ในเว็บเราอย่างแน่นอน เพื่อความสะดวก Typography.js จึงเกิดขึ้นมาเพื่อช่วยให้เราไม่ต้องมานั่งเขียน CSS ที่ใช้จัดการพวก Font เองทั้งหมดนั่นเอง โดยผ่านแค่การเขียน Object ใน JS ตามแบบที่เขากำหนดไว้ก็เรียบร้อยแล้ว

เริ่มจากการ Install Plugin กันก่อนเลย โดยใช้คำสั่งตามด้านล่างนี้

yarn add typography react-typography gatsby-plugin-typography

หรือถ้าใครใคร่อยากใช้ NPM ก็เอาที่สบายใจ

npm install --save typography react-typography gatsby-plugin-typography

หลังจากนั้นเราก็สร้าง File ตัวนึงชื่อ typography.js ไว้ใน src/utils แล้วลองแปะ Code นี้ลงไป

import Typography from "typography"

const typography = new Typography({
  baseFontSize: "18px",
  baseLineHeight: 1.45,
  headerFontFamily: [
    "Avenir Next",
    "Helvetica Neue",
    "Segoe UI",
    "Helvetica",
    "Arial",
    "sans-serif",
  ],
  bodyFontFamily: ["Georgia", "serif"],
})

export default typography

ถ้าเราเข้าไปดูใน Config ที่เราใส่เข้าไป มันจะแบ่ง 4 เรื่องนั่นคือ baseFontSize นั่นก็คือขนาดของ Font ทั่วไป ถ้าเทียบก็คือมันจะอยู่ใน Paragraph Tag

baseLineHeight คือความสูงของบรรทัด เหมือนที่เราเซ็ต line-height ใน CSS เลย ส่วนอีก 2 อันสุดท้ายเป็นการเซ็ต Font Family ของ Header (พวก Tag H1, H2 และ H อื่น ๆ) และของตัว Body เอง ถ้าเราเข้าไปดูใน Documentation เพิ่มเติมเราจะเห็นว่ามันยังมีอีกหลาย ๆ Config มากมาย อันนี้คือเอามาเพื่อให้เห็นภาพ แต่ก็ลองไปอ่านแล้วเล่นดูได้

แต่หลังจากที่เรา Install Plugin ไปแล้ว มันก็ยังใช้ไม่ได้แน่ ๆ เราก็ต้องไปเพิ่ม Plugin ใน List ของ Plugin ใน gatsby-config.js

plugins: [
    'gatsby-plugin-react-helmet',
    'gatsby-plugin-styled-components',
    {
      resolve: 'gatsby-plugin-typography',
      options: {
        pathToConfigModule: `src/utils/typography.js`
      }
    },
  ]

จุดที่เพิ่มคือตั้งแต่บรรทัดที่เขียนว่า resolve: 'gatsby-plugin-typography' นอกจากนั้น เราก็เติม Option ลงไป ซึ่งเราสามารถดูได้จาก Documentation ของ Gatsby ได้เลย ซึ่งสิ่งที่ต้องเพิ่มคือ pathToConfigModule นั่นคือยิงไปที่ Config ที่เราเขียนไว้ก่อนหน้านั้น หลังจากนั้นพอเราเซฟอะไรเรียบร้อยแล้ว เราก็จะเห็นว่า Font ของเราเปลี่ยนไป ในทุก ๆ หน้าเลย โดยที่เราไม่ต้อง Import อะไรเพิ่มเลย

สรุป

ในตอนนี้ เราก็ได้มารู้จักกับการสร้างสีสันให้กับ Component ของเราโดยการใช้ Inline-CSS, CSS Module และการติดตั้งและใช้ styled-component ใน Gatsby.js Project ของเรา (จริง ๆ มันสามารถใช้ CSS-in-JS ตัวอื่นก็ได้นะ แต่ไม่ได้ยกมาเขียนทั้งหมด อันนี้คือยกมาเฉพาะที่ผมใช้) จะเห็นว่ามันก็มีหลายวิธี ทั้งยากและง่าย แต่ละวิธีมันก็จะมีทั้งข้อดีและข้อเสียกันไป แนะนำให้ลองไปดูตัวที่เป็น Inline-CSS และ styled-components ดู มันจะ Powerful มากเมื่อมันถูกใช้ด้วยกัน ส่วนตอนหน้าจะเป็นเรื่องอะไรก็มาลองดูกัน ~

Read Next...

จัดการ Docker Container ง่าย ๆ ด้วย Portainer

จัดการ Docker Container ง่าย ๆ ด้วย Portainer

การใช้ Docker CLI ในการจัดการ Container เป็นท่าที่เราใช้งานกันทั่วไป มันมีความยุ่งยาก และผิดพลาดได้ง่ายยังไม่นับว่ามี Instance หลายตัว ทำให้เราต้องค่อย ๆ SSH เข้าไปทำทีละตัว มันจะดีกว่ามั้ย หากเรามี Centralised Container Managment ที่มี Web GUI ให้เราด้วย วันนี้เราจะพาไปทำความรู้จักกับ Portainer กัน...

Host Website จากบ้านด้วย Cloudflare Tunnel ใน 10 นาที

Host Website จากบ้านด้วย Cloudflare Tunnel ใน 10 นาที

ปกติหากเราต้องการจะเปิดเว็บสักเว็บ เราจำเป็นต้องมี Web Server ตั้งอยู่ที่ไหนสักที่หนึ่ง ต้องใช้ค่าใช้จ่าย พร้อมกับต้องจัดการเรื่องความปลอดภัยอีก วันนี้เราจะมาแนะนำวิธีการที่ง่ายแสนง่าย ปลอดภัย และฟรี กับ Cloudflare Tunnel ให้อ่านกัน...

จัดการข้อมูลบน Pandas ยังไงให้เร็ว 1000x ด้วย Vectorisation

จัดการข้อมูลบน Pandas ยังไงให้เร็ว 1000x ด้วย Vectorisation

เวลาเราทำงานกับข้อมูลอย่าง Pandas DataFrame หนึ่งในงานที่เราเขียนลงไปให้มันทำคือ การ Apply Function เข้าไป ถ้าข้อมูลมีขนาดเล็ก มันไม่มีปัญหาเท่าไหร่ แต่ถ้าข้อมูลของเราใหญ่ มันอีกเรื่องเลย ถ้าเราจะเขียนให้เร็วที่สุด เราจะทำได้โดยวิธีใดบ้าง วันนี้เรามาดูกัน...

ปั่นความเร็ว Python Script เกือบ 700 เท่าด้วย JIT บน Numba

ปั่นความเร็ว Python Script เกือบ 700 เท่าด้วย JIT บน Numba

Python เป็นภาษาที่เราใช้งานกันเยอะมาก ๆ เพราะความยืดหยุ่นของมัน แต่ปัญหาของมันก็เกิดจากข้อดีของมันนี่แหละ ทำให้เมื่อเราต้องการ Performance แต่ถ้าเราจะบอกว่า เราสามารถทำได้ดีทั้งคู่เลยละ จะเป็นยังไง เราขอแนะนำ Numba ที่ใช้งาน JIT บอกเลยว่า เร็วขึ้นแบบ 700 เท่าตอนที่ทดลองกันเลย...