Astro.js & Islands Architecture: Giải pháp ‘giảm cân’ cho Website để đạt Lighthouse 100

Development tutorial - IT technology blog
Development tutorial - IT technology blog

Nỗi ám ảnh mang tên JavaScript “phình to”

Cách đây 2 năm, mình từng build một trang tin tức bằng Next.js. Lúc đó mình khá tự tin vì dùng framework xịn nhất thời điểm ấy. Tuy nhiên, khi đo bằng Google PageSpeed Insights, điểm Performance trên di động chỉ lẹt đẹt mức 55.

Trình duyệt phải tải và thực thi hơn 200KB JavaScript chỉ để hiển thị một cái menu dropdown và form đăng ký cuối trang. Việc ép người dùng tải cả một bộ framework nặng nề để đọc vài dòng chữ thực sự là một trải nghiệm tệ. Đây chính là vấn đề mà hầu hết các dự án web hiện đại đang gặp phải.

Hydration: “Kẻ trộm” hiệu suất âm thầm

Tại sao dùng framework xịn mà web vẫn chậm? Thủ phạm chính là Hydration (bù nước). Trong React hay Vue, dù server đã render ra HTML, trình duyệt vẫn phải tải toàn bộ file JS về để chạy lại code và gắn các sự kiện (event listeners).

Quá trình này ngốn CPU và làm tăng chỉ số Total Blocking Time (TBT). Thực tế, khoảng 80% nội dung trên blog hay landing page là tĩnh. Việc bắt trình duyệt xử lý JS cho những phần không cần tương tác là một sự lãng phí tài nguyên cực lớn.

Islands Architecture: Tư duy “chia để trị”

Để thoát khỏi vũng lầy này, Islands Architecture (Kiến trúc Ốc đảo) đã xuất hiện. Thay vì biến cả trang web thành một khối JavaScript khổng lồ, kiến trúc này coi trang web là một đại dương HTML tĩnh.

Trong đại dương đó, các thành phần tương tác như giỏ hàng hay thanh tìm kiếm sẽ là những “hòn đảo” nhỏ chứa JS. Chỉ những hòn đảo này mới cần tải mã nguồn, phần còn lại hoàn toàn là HTML thuần túy. Cách tiếp cận này giúp giảm đáng kể thời gian phản hồi của trang.

Astro.js – Framework tiên phong cho kỷ nguyên Zero-JS

Astro.js hiện là framework áp dụng Islands Architecture hiệu quả nhất. Nó cho phép bạn trộn lẫn React, Vue, Svelte hay Solid trong cùng một dự án. Mặc định, Astro sẽ xuất ra Zero JavaScript cho đến khi bạn yêu cầu ngược lại.

Bước 1: Khởi tạo dự án nhanh chóng

Gõ lệnh này vào terminal để bắt đầu nhé:

npm create astro@latest

Sau khi chọn các tùy chọn mặc định, bạn di chuyển vào thư mục và khởi động môi trường dev:

cd ten-du-an
npm run dev

Bước 2: Tích hợp đa framework

Astro rất linh hoạt. Nếu team bạn có người rành React, người thích Vue, bạn có thể tích hợp cả hai chỉ với một dòng lệnh:

npx astro add react vue

Hệ thống sẽ tự cấu hình file astro.config.mjs. Giờ đây, việc sử dụng song song các component từ các thư viện khác nhau trở nên cực kỳ đơn giản.

Bước 3: Xây dựng các “Ốc đảo” tương tác

Hãy thử tạo một component Counter bằng React và một thông báo bằng Vue để thấy sự khác biệt.

src/components/ReactCounter.jsx

import { useState } from 'react';

export default function ReactCounter() {
  const [count, setCount] = useState(0);
  return (
    <div className="p-4 border rounded">
      <p>React Counter: {count}</p>
      <button onClick={() => setCount(count + 1)} className="bg-blue-500 text-white px-2">
        Tăng số
      </button>
    </div>
  );
}

Bước 4: Kiểm soát JavaScript bằng Directives

Trong file src/pages/index.astro, nếu bạn gọi component theo cách thông thường, Astro sẽ render chúng thành HTML tĩnh. Nút bấm sẽ không có tác dụng vì không có JS đi kèm. Để kích hoạt tính tương tác, chúng ta dùng các client:* directives:

---
import ReactCounter from '../components/ReactCounter';
import VueNotification from '../components/VueNotification.vue';
---

<html lang="vi">
  <body>
    <h1>Astro Islands</h1>
    
    <!-- Island 1: Tải JS ngay khi trang load -->
    <ReactCounter client:load />

    <div style="height: 100vh;"></div>

    <!-- Island 2: Chỉ tải JS khi người dùng cuộn tới -->
    <VueNotification client:visible />
  </body>
</html>

Các chỉ thị này giúp bạn kiểm soát cực kỳ chi tiết:

  • client:visible: Chỉ tải JS khi component lọt vào tầm mắt người dùng. Đây là cách tuyệt vời để tối ưu các thành phần ở chân trang (footer).
  • client:idle: Tải JS khi trình duyệt đã rảnh tay.
  • client:only: Bỏ qua bước render ở server, chỉ chạy ở client.

Kết quả thực tế: Từ 200KB xuống còn 10KB

Mình từng refactor một trang landing page chứa 50 component. Khi dùng Next.js, file JS chính nặng gần 200KB và điểm LCP (Largest Contentful Paint) mất 2.5 giây.

Chuyển sang Astro và sử dụng client:visible cho các phần cần thiết, tổng lượng JS tải ban đầu giảm xuống còn dưới 10KB. Điểm Lighthouse vọt lên 100 tuyệt đối, và thời gian tương tác (TTI) gần như tức thì.

Khi nào bạn nên chọn Astro?

Astro không phải là giải pháp cho mọi bài toán. Nếu bạn xây dựng Dashboard phức tạp như Jira hay Facebook, hãy tiếp tục dùng Next.js hoặc React SPA. Tuy nhiên, Astro là lựa chọn hàng đầu cho:

  • Trang tin tức, Blog hoặc Portfolio cá nhân.
  • Website doanh nghiệp, Landing page bán hàng.
  • Trang tài liệu kỹ thuật (Documentation).
  • E-commerce cần ưu tiên SEO và tốc độ tải trang đầu tiên.

Tận dụng Islands Architecture sẽ giúp bạn vừa giữ được trải nghiệm code hiện đại, vừa mang lại tốc độ tối đa cho người dùng cuối.

Share: