Cách Tự Động Tối Ưu Responsive Image Bằng Gatsby

Tối Ưu Responsive Image Bằng Gatsby
Tối ưu hóa hình ảnh, luôn là một vấn đề hóc búa khi xây dựng trang web có tốc độ nhanh. Việc cân bằng chất lượng hình ảnh và hiệu quả băng thông là không dễ dàng nếu thiếu các công cụ phù hợp. Các công cụ chỉnh sửa ảnh như Photoshop tuy khá phù hợp cho việc cắt xén và thay đổi kích thước hình ảnh bitmap, nhưng lại không được 100% tối ưu hóa cho môi trường web.
May mắn thay, chúng ta có các gói mở rộng có thể tối ưu hóa hình ảnh một cách nhanh chóng:
Tuy nhiên, tối ưu ảnh thôi vẫn chưa đủ. Bạn cần đảm bảo rằng cả website sẽ responsive và nhìn ổn ổn với mọi kích thước màn hình. Bạn có thể dễ dàng làm điều này với CSS, nhưng vấn đề ở đây này:
Bạn nên tối ưu hóa hình ảnh của mình cho màn hình lớn hay màn hình nhỏ?
Nếu đa phần audience của bạn đang dùng thiết bị di động để truy cập site, thì theo logic ta nên tối ưu cho màn hình nhỏ. Tuy nhiên, có khả năng là một nguồn lợi nhuận lớn lại đến từ người dùng có màn hình từ 17" trở lên. Việc "bỏ lơ" những người này là không sáng suố
May thay, vẫn có công nghệ cho phép chúng ta tối ưu responsive image cho các kích thước màn hình khác nhau. Như vậy, chúng ta cần phải tạo nhiều ảnh được tối ưu với những độ phân giải khác nhau, phù hợp với từng kích thước màn hình cụ thể hoặc esponsive breakpoint cụ thể.

Đối với chủ sở hữu trang web WordPress, việc tối ưu hóa hình ảnh kiểu này cần phải dùng đến plugin và dịch vụ của bên thứ ba. Ta không thể tạo responsive image trên máy chủ lưu trữ (vì trang web sẽ chậm rất chậm về phía người dùng), do đó cần có dịch vụ của bên thứ ba.
Nếu bạn đang sử dụng Gatsby cho trang web của mình, thì bạn đã lựa chọn đúng rồi đấy. Tính năng này đã được tích hợp và cấu hình sẵn để responsive image. Bạn chỉ cần thả hình ảnh vào và viết một chút code để liên kết hình responsive image với trang web. Khi bạn chạy lệnh gatsby build, hình ảnh đã được tối ưu hóa rồi. Công cụ sẽ giúp bạn tránh dùng đến dịch vụ của bên thứ ba để tối ưu.

Chuẩn bị

Trước khi bắt đầu, lưu ý rằng hướng dẫn này dành cho các nhà phát triển mới bắt đầu với Gatsby và muốn tìm hiểu cụ thể về cách xử lý hình ảnh. Bài viết sẽ giả định rằng bạn đã có một nền tảng tốt trong các chủ đề sau:
  • React
  • GraphQL

Demo Project Setup

Giả sử bạn đã cài đặt phiên bản Node.js mới nhất trên hệ thống của mình, hãy nhanh chóng thiết lập dự án khởi động Gatsby:
npm install -g gatsby-cli
gatsby new gatsby-image-demo
cd new gatsby-image-demo
npm start
Dự án khởi động này bao gồm các dependencies và cấu hình cần thiết cần thiết để tạo và hiển thị responsive được tối ưu hóa. Nếu bạn đã sử dụng một dự án khởi động khác hoặc bạn thích bắt đầu từ một dự án hoàn toàn mới, đây là điều bạn sẽ cần làm:
npm install gatsby-image gatsby-transformer-sharp gatsby-plugin-sharp gatsby-source-filesystem
Tiếp theo, bạn sẽ cần phải định cấu hình các dêpndencies như sau trong gatsby-config.js:
plugins:[
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/src/images`,
        name: 'images'
      }
    },
    'gatsby-transformer-sharp',
    'gatsby-plugin-sharp',
]
Nếu mở http://localhost:8000/, bạn sẽ có trang Gatsby Default Starter với hình ảnh PNG của một phi hành gia đã được tối ưu hóa. Hãy xem qua mã dự án để xem hình ảnh được tải và hiển thị như thế nào.

Trông khá phức tạp phải không? Chà, trong phần tiếp theo, chúng tôi sẽ xem xét từng phần một nhé.

Cách Gatsby Tối Ưu Hình Ảnh

Kết xuất responsive image được tối ưu hóa trên trang web được thực hiện bằng Gatsby Image (React component). Nó trông như thế này:
import Image from 'gatsby-image';

<!--  Fixed Image Example -->
<Image fixed={fixed} />

<!--  Fluid Image Example -->
<Image fluid={fluid} />
Như đã thấy trong các mẫu mã ở trên, có hai loại hình ảnh mà thành phần gatsby-image được thiết kế để xử lý:
  • Fixed: hình ảnh với độ cao và rộng cố định
  • Fluid: hình ảnh với động rộng (và có thể là độ cao) tối đa
Fixed sẽ phù hợp nếu bạn muốn hiển thị retina image. Lưu ý rằng các thanh cuộn sẽ xuất hiện nếu cửa sổ trình duyệt được thay đổi kích thước nhỏ hơn chiều rộng hình ảnh. Đối với chất Fluid, hình ảnh sẽ tự động thay đổi kích thước dựa trên kích thước cửa sổ trình duyệt. Hình ảnh nhỏ hơn hoặc lớn hơn sẽ được hoán đổi tự động để phù hợp với chế độ xem được thiết đặt.
Nhân chủ đề về render, làm sao ta có thể cung cấp dữ liệu hình ảnh cho một gatsby-image?

Chúng ta sẽ sử dụng GraphQL để tải hình ảnh cần dùng trên trang web. Ngôn ngữ truy vấn này cho phép chúng ta truy cập hình ảnh từ filesystem cục bộ (trang web WordPress hoặc API tùy chỉnh). Bạn sẽ cần một plugin đặc biệt để truy cập một kiểu vị trí cụ thể:
GraphQL không chỉ truy xuất asset mà còn có thể xử lý trước khi trả kết quả về cho function. Trong trường hợp tối ưu ảnh, chúng ta sẽ làm việc chủ yếu với các plugin sau:
Gatsby Plugin Sharp là một plugin trợ giúp cấp thấp thực hiện nhiệm vụ giảm kích thước hình ảnh mà hạn chế tối đa việc giảm chất lượng ảnh. Nó sử dụng thư viện xử lý ảnh Sharp để thực hiện tác vụ này. Đối với JPEG, công cụ tạo ra các hình ảnh lũy tiến với mức chất lượng mặc định là 50. Đối với PNG, công cụ sử dụng thư viện pngquant với cài đặt chất lượng 50-75.
Plugin Gatsby Transformer Sharp chịu trách nhiệm tạo responsive image. Nói cách khác, công cụ thực hiện thay đổi kích thước và cắt xén hình ảnh để tạo ra nhiều phiên bản có độ phân giải khác nhau để hiển thị tối ưu trên cả thiết bị di động, máy tính bảng và màn hình lớn.
Trong phần tiếp theo, chúng ta sẽ xét đến khả năng sử dụng thực tế của các kỹ thuật trên.

Tối Ưu Hình Ảnh Trên Web Page

Hãy bắt đầu bằng việc thả một vài hình ảnh vào thư mục src/images:
01-source-images
Kế tiếp, cùng xem thử ta sẽ dùng query GraphQL nào để truy vấn hình ảnh responsive đã tối ưu. Mở http://localhost:8000/___graphql trong tình duyệt để khởi chạy GraphQL Explorer và giao diện Query. Ở Explorer panel, hãy lưu ý tất cả node khả dụng. Trong trường hợp này, chúng ta sẽ quan tâm đến node file và childImageSharp. Bên dưới là một query mẫu đơn giản.
02-graphql-explorer
Chúng ta vừa xác định một query GraphQL, hãy cùng tạo page mới, như grado.js.
Khi đã xác định query cho GraphQL, hãy tạo page mới, như grado.js. Trong code ví dụ kế tiếp, chúng ta sẽ render cả hình ảnh fixed và fluid. Tuy nhiên, với phần query, chúng ta sẽ dùng fragment GatsbyImageSharpFluid và GatsbyImageSharpFluid thay vì phải list tất cả node con cần thiết (i.e. srcsizessrcSet etc).  Chú ý rằng query fragments vẫn chưa được hỗ trợ trong GraphQL Query Explorer.
import React from "react"
import Image from 'gatsby-image';
import { graphql } from "gatsby"

import Layout from "../components/layout"
import SEO from "../components/seo"

const GradoPage = ({data}) => (
  <Layout>
    <SEO title="Grado" />
    <h1>Grado Headphones ShowCase</h1>
    <h3>Fluid</h3>
    <Image fluid={data.gradoFluidImage.childImageSharp.fluid} />
    <br/>
    <h3>Fixed</h3>
    <Image fixed={data.gradoFixedImage.childImageSharp.fixed} />  
    <p>Grado Rs2e</p>
  </Layout>
)

export default GradoPage

export const pageQuery = graphql`
  query {
    gradoFluidImage: file(relativePath: { eq: "grado-rs2e.jpg" }) {
      childImageSharp {
        fluid(maxWidth: 1000) {
          ...GatsbyImageSharpFluid
        }
      }
    }
    gradoFixedImage: file(relativePath: { eq: "grado-rs2e.jpg" }) {
      childImageSharp {
        fixed(width: 600, height: 401) {
          ...GatsbyImageSharpFixed
        }
      }
    }
  }
`
Giả sử Gatsby vẫn đang chạy, hãy điều hướng đến localhost:8000/grado:
03-fixed-vs-fluid
Ví dụ trên đây cho thấy sự khác nhau trong hình ảnh giữa ảnh linh động (fluid) và ảnh cố định (static). Hình ảnh linh động sẽ luôn thay đổi phù hợp với động rộng của container, trong khi đó hình ảnh cố định sẽ giữ nguyên bất kể viewport size.
Trong đoạn code tiếp theo, chúng ta sẽ tìm cách hiển thị nhiều hình fluid trên cùng một trang:
const GradoPage = ({data}) => (
  <Layout>
    <SEO title="Grado" />
    <h1>Grado Headphones ShowCase</h1>
    <h3>Grado</h3>
    <Image fluid={data.grado.childImageSharp.fluid} />
    <br/>
    <h3>Grado Boxed</h3>
    <Image fluid={data.gradoBox.childImageSharp.fluid} />
    <br/>
    <h3>Grado Mounted</h3>
    <Image fluid={data.gradoMounted.childImageSharp.fluid} />
  </Layout>
)

export default GradoPage

export const pageQuery = graphql`
  query {
    grado: file(relativePath: { eq: "grado-rs2e.jpg" }) {
      childImageSharp {
        fluid(maxWidth: 1000) {
          ...GatsbyImageSharpFluid
        }
      }
    }

    gradoBox: file(relativePath: { eq: "grado-rs2e-box.jpg" }) {
      childImageSharp {
        fluid(maxWidth: 1000) {
          ...GatsbyImageSharpFluid
        }
      }
    }

    gradoMounted: file(relativePath: { eq: "grado-rs2e-mounted.jpg" }) {
      childImageSharp {
        fluid(maxWidth: 1000) {
          ...GatsbyImageSharpFluid
        }
      }
    }
  }
`
Trang /grado sẽ tự động refresh. Bạn lúc này có thể thấy toàn bộ hình ảnh hiển thị trên trang. Nếu bạn tải một trong những hình ảnh đó ngay từ trình duyệt, bạn sẽ thấy kích thước ảnh đã được giảm. Trong trường hợp của bài viết, khi trình duyệt được thu nhỏ nhất, hình ‘Grado Box’ sẽ được giảm còn 19.5 KB. Khi phóng to trình trên 1920×1080, kích thước hình ảnh sẽ tăng đến 60.1 KB.
Bạn chắc đã nhận thấy rằng query khá dư thừa. Chúng ta có thể chỉ việc tạo query fragment riêng như sau:
export const fluidImage = graphql`
  fragment fluidImage on File {
    childImageSharp {
      fluid(maxWidth: 1000) {
        ...GatsbyImageSharpFluid
      }
    }
  }
`;

export const pageQuery = graphql`
  query {
    grado: file(relativePath: { eq: "grado-rs2e.jpg" }) {
       ...fluidImage
    }

    gradoBox: file(relativePath: { eq: "grado-rs2e-box.jpg" }) {
       ...fluidImage
    }

    gradoMounted: file(relativePath: { eq: "grado-rs2e-mounted.jpg" }) {
       ...fluidImage
    }
  }
`

Tối ưu hình ảnh trong Markdown Post & Page

Có hai cách tối ưu hình ảnh trong Markdown post & page:

1. Featured Images

Featured image thường được đặt trong phần metadata. Bạn chỉ việc chỉ định một trường tên featuredImage, như sau:
---
title: First Post
featuredImage: ./first-post-image.png
---

Place content here
Tiếp đến, ta sẽ xử lý featuredImage trong file Markdown template, như sau:
//src/templates/blog-post.js
---
export const query = graphql`
  query PostQuery($slug: String!) {
    markdownRemark(fields: { slug: { eq: $slug } }) {
      html
      frontmatter {
        title
        featuredImage {
          childImageSharp {
            fluid(maxWidth: 800) {
              ...GatsbyImageSharpFluid
            }
          }
        }
      }
    }
  }
`
Ta cũng cần phải import package gatsby-image để render responsive image đã tối ưu:
//src/templates/blog-post.js

import Img from "gatsby-image"

export default({data}) {
  let post = data.markdownRemark
    let featuredImgFluid = post.frontmatter.featuredImage.childImageSharp.fluid
    return(
        <Layout>
          <div>
            <h1>{post.frontmatter.title}</h1>
            <Img fluid={featuredImgFluid} />
            <div dangerouslySetInnerHTML={{ __html: post.html }} />
          </div>
        </Layout>
    )
}
Vậy là xong rồi. Giờ đây tất cả các post Markdown sẽ có trường featuredImage tối ưu responsive cho các kích thước màn hình khác nhau.

2. Inline Images

Đối với hình ảnh inline dùng cho các post và page Markdown, bạn chỉ việc cài đặt plugin sau:
npm install gatsby-remark-images
Cả gatsby-plugin-sharp và gatsby-source-filesystem cũng phải được cài đặt. Kế tiếp, ta sẽ tùy chỉnh gatsby-remark-images trong gatsby-config.js như sau:
module.exports = {
  plugins: [
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-mdx`,
      options: {
        gatsbyRemarkPlugins: [
          {
            resolve: `gatsby-remark-images`,
            options: {
              maxWidth: 1200,
            },
          },
        ],
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/src/pages`,
      },
    },
  ],
}
Trong hình ảnh và post Markdown của mình, các bạn có thể sử dụng cú pháp mặc định để render hình ảnh. Việc tối ưu sẽ được thực hiện tự động
![Post image](./my-first-post-image.png)

Lời kết

Hy vọng thông qua bài viết các bạn đã biết các tối ưu hình ảnh tùy biến cho các trang Gatsby. Cùng chia sẻ và đón chờ những bài viết tiếp theo nhé.

Nhận xét

Bài đăng phổ biến