ตอนที่ 3 - การจัดการ Assets, Metadata และ CSS

Published on

เขียนวันที่ : June 18, 2022

learn-nextjs/03-assets-and-css
Discord

มาต่อกันที่บทที่ 3 ครับ บทนี้ก็ยังใช้ source code ที่ได้จาก create-next-app นะครับ วันนี้ต่อด้วยเรื่องของ Assets และการจัดการ CSS โดย Assets ก็หมายถึงพวก static files ทั้งหลาย เช่น images หรือไฟล์ pdf, .mp4 เป็นต้น การจัดการ Meta tag ต่างๆ พวก SEO tag ต่างๆ

Assets

Next.js นั้นจะมองโฟลเดอร์ public ที่อยู่ในโปรเจ็คของเรา เป็น static assets ครับ เช่นไฟล์ robots.txt ก็คือไฟล์ public ที่ให้ Google bot มาอ่าน

ตัวอย่างเช่น เราจะเก็บรูปที่เราจะใช้ในเว็บ เราก็เก็บไว้ในโฟลเดอร์ public อาจจะแตกโฟลเดอร์ย่อยข้างในก็ได้ เช่น images

สมมติ เรามีไฟล์ public/images/logo.png เวลาเราเรียกใช้ใน Component เราก็จะเรียกใช้งานแบบนี้

<img src="/images/logo.png" alt="My Logo" />

next/image

Next.js นั้นมี next/image ที่มาช่วยจัดการเรื่องของ Image Optimization ให้เราครับ เช่น resize รูป, แปลงรูปเป็น WebP, รองรับขนาดรูปตาม size ของ viewport เป็นต้น

การใช้งาน next/image ก็คล้ายๆกับ <img> ของ HTML ปกติ ต่างกันที่มองเป็น Component และก็มี option คือ props นั่นเอง

วิธีใช้งาน ก็ตามตัวอย่างด้านล่าง การเพิ่มรูป โดยกำหนด ความกว้าง ความยาว = 144px

import Image from 'next/image'

const YourComponent = () => {
  return (
    <Image
      src="/images/logo.png"
      height={144}
      width={144}
      alt="My Logo"
    />
  )
}

ซึ่งสามารถดูโค๊ดไฟล์ pages/index.js ตรงส่วน <footer> ดูได้ครับ จะมีการใช้งาน <Image> โดยเรียกไฟล์ vercel.svg

pages/index.js
<footer className={styles.footer}>
  <a
    href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
    target="_blank"
    rel="noopener noreferrer"
  >
    Powered by{' '}
    <span className={styles.logo}>
      <Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />
    </span>
  </a>
</footer>

อ่านเรื่องของ next/image เพิ่มเติม

Metadata

ปกติ Metadata ในหน้าเว็บ HTML ของเรา เช่น <title> ใน <head> เราสามารถปรับแต่งได้ โดยใช้ next/head นั่นเอง (จริงๆ คือทั้งหมดที่อยู่ในแท็ก <head> เช่นปรับ meta tag เพื่อ SEO ต่างๆ หรือแทรก script ลงไป)

ลองสังเกตที่ไฟล์ pages/index.js ครับ จะเห็นส่วนนี้

export default function Home() {
  return (
    <div className={styles.container}>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      ... ...
    </div>
  );
}

ก็คือเป็นการกำหนด Title ให้หน้า Index นั่นเอง ตัวอย่้างดูได้จาก pages/index.js เช่นเดิม

pages/index.js
<Head>
  <title>Create Next App</title>
  <meta name="description" content="Generated by create next app" />
  <link rel="icon" href="/favicon.ico" />
</Head>

CSS Styling

ในการจัดการ CSS ของ Next.js เราสามารถเลือกเขียน CSS ได้หลากหลายมากครับ ทั้ง css ปกติ, css modules, CSS-in-JS หรือ Sass เป็นต้น

อย่าง CSS-in-JS ตัวที่เป็น built-in ของ Next.js เลย คือใช้ styled-jsx จะคล้ายๆกับ styled-component หรือ emotion

ตัวอย่างการใช้งาน

export default () => (
  <div>
    <p>only this paragraph will get the style :)</p>

    {/* you can include <Component />s here that include
         other <p>s that don't get unexpected styles! */}

    <style jsx>{`
      p {
        color: red;
      }
    `}</style>
  </div>
);

เราจะเห็นว่า <p> ถูกกำหนดให้มี color: red โดยที่มีผลแค่ component นี้ ไม่มีผลกับ <p> ใน component อื่นๆ นั่นเอง

CSS Modules

นอกจากนี้เรื่องการจัดการ CSS แต่ละ component ไม่ให้ selector มันชนกัน ก็คือการใช้ CSS Modules ครับ

สังเกตจากไฟล์ styles/global.css และไฟล์ Home.module.css ที่ถูกสร้างมา default จากตอนเราสร้างโปรเจ็ค naming convention จะเป็น [name].module.css

ส่วนไฟล์ pages/index.js ก็จะมีการ import มาใช้งานอยู่ครับ

pages/about.js
import styles from '../styles/Home.module.css'

export default function Home() {
  return (
    <div className={styles.container}>
    </div>
  )
}

ข้อดีของ CSS Module คือ class จะถูก generate ทำให้ selector ที่เราตั้งไว้ จะไม่โดน override ครับ ลองเปิดหน้าเว็บ แล้ว inspect ดู

Next.js CSS Module Inspect

Sass

ตัว Next.js ก็รองรับการเขียนด้วย Sass ครับ เพียงแค่ตั้งชื่อไฟล์ให้ลงท้ายด้วย .scss และก็ติดตั้ง node-sass ครับ

yarn add sass -D

# หรือ npm install sass --save-dev

Global Styles

นอกจากเราจะใช้ CSS Module เพื่อสำหรับการจัด style แบบ component-level แล้ว เรายังสามารถใช้ CSS แบบ global (พวก common, helper css) ที่ต้องใช้ทุกๆ หน้า ซึ่ง Next.js ก็รองรับ

เงื่อนไข คือไฟล์ _app.js ในโฟลเดอร์ pages มันจะโหลดทุกๆ หน้านั่นเอง เราก็แค่ import global styles ลงไป

ลองดูไฟล์ pages/_app.js ที่ตัว create-next-app มัน generate มาให้ครับ

pages/_app.js
import '../styles/globals.css'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp

ทดลองปรับแก้ เพิ่ม selector ใน globals.css ดูครับ

นอกจากนี้ เรายังสามารถ import CSS จาก node_modules ได้ เช่นกัน เช่น ถ้าเราติดตั้ง bootstrap ไว้ ก็ import ได้เลย

import 'bootstrap/dist/css/bootstrap.css'

global css ไม่สามารถ import ที่อื่นได้ นอกจากไฟล์ pages/_app.js เพื่อให้มันมีผล css กับทุกๆ element ในหน้า page

🎉 จบแล้วครับ สำหรับตอนที่ 3 - ตอนต่อไปจะมาพูดถึงเรื่องของ Pre-rendering กันครับ

แบบฝึกหัด

  • ลองใช้งาน Style Component หรือ Emotion ปรับแต่งหน้าเว็บ
  • ลอง import CSS Framework/Library อื่นๆ มาใช้ เช่น bootstrap, bulma, tailwind
  • ลองใช้ classNames เพื่อจัดการกับ style
Discord