<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Việt Anh Trần Hữu</title>
    <description>The latest articles on DEV Community by Việt Anh Trần Hữu (@va2212).</description>
    <link>https://dev.to/va2212</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2603891%2F860e9003-4719-44b2-a5ea-0ac3fe7a3f1a.png</url>
      <title>DEV Community: Việt Anh Trần Hữu</title>
      <link>https://dev.to/va2212</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/va2212"/>
    <language>en</language>
    <item>
      <title>Một số tối ưu SEO cho Website (1)</title>
      <dc:creator>Việt Anh Trần Hữu</dc:creator>
      <pubDate>Mon, 31 Mar 2025 10:14:12 +0000</pubDate>
      <link>https://dev.to/va2212/mot-so-toi-uu-seo-cho-website-1-3dlk</link>
      <guid>https://dev.to/va2212/mot-so-toi-uu-seo-cho-website-1-3dlk</guid>
      <description>&lt;p&gt;Hello mọi người lại là Slao đây,&lt;br&gt;
Bài viết này sẽ chủ yếu tâp trung vào phần technical của website nhé&lt;/p&gt;
&lt;h1&gt;
  
  
  🛠️ Hướng Dẫn Tối Ưu SEO Website Về Mặt Technical
&lt;/h1&gt;

&lt;p&gt;SEO (&lt;strong&gt;Search Engine Optimization&lt;/strong&gt;) không chỉ đơn giản là viết nội dung chất lượng hay xây dựng backlink, mà còn bao gồm việc tối ưu kỹ thuật (&lt;strong&gt;Technical SEO&lt;/strong&gt;). Nếu website của bạn có cấu trúc kém hoặc gặp lỗi về hiệu suất, các công cụ tìm kiếm như Google sẽ khó có thể thu thập và hiểu nội dung của bạn. Trong bài viết này, mình sẽ hướng dẫn bạn các bước quan trọng để tối ưu &lt;strong&gt;Technical SEO&lt;/strong&gt; giúp website của bạn thân thiện với các công cụ tìm kiếm và cải thiện thứ hạng.&lt;/p&gt;
&lt;h2&gt;
  
  
  ✅ 1. Tối Ưu Crawlability và Indexability
&lt;/h2&gt;
&lt;h3&gt;
  
  
  🔎 Kiểm Tra Tệp Robots.txt
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Robots.txt&lt;/strong&gt; giúp kiểm soát những phần nào của website mà các công cụ tìm kiếm có thể hoặc không thể thu thập thông tin. Đảm bảo tệp &lt;code&gt;robots.txt&lt;/code&gt; không vô tình chặn các trang quan trọng.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User-agent: *
Disallow: /admin/
Allow: /
Sitemap: https://www.example.com/sitemap.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📦 Tạo và Gửi Sitemap XML
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Sitemap.xml&lt;/strong&gt; giúp Google hiểu cấu trúc website và thu thập thông tin hiệu quả hơn.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;urlset&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.sitemaps.org/schemas/sitemap/0.9"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;loc&amp;gt;&lt;/span&gt;https://www.example.com/&lt;span class="nt"&gt;&amp;lt;/loc&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;lastmod&amp;gt;&lt;/span&gt;2024-03-30&lt;span class="nt"&gt;&amp;lt;/lastmod&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;priority&amp;gt;&lt;/span&gt;1.0&lt;span class="nt"&gt;&amp;lt;/priority&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/urlset&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ✅ 2. Tối Ưu Hiệu Suất Website
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🚀 Cải Thiện Tốc Độ Load Trang
&lt;/h3&gt;

&lt;p&gt;Sử dụng công cụ như &lt;strong&gt;PageSpeed Insights&lt;/strong&gt; hoặc &lt;strong&gt;GTmetrix&lt;/strong&gt; để kiểm tra hiệu suất. Một số cách tối ưu:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Giảm kích thước ảnh bằng &lt;strong&gt;WebP&lt;/strong&gt; hoặc &lt;strong&gt;AVIF&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Sử dụng CDN để phân phối nội dung nhanh hơn.&lt;/li&gt;
&lt;li&gt;Kích hoạt &lt;strong&gt;caching&lt;/strong&gt; bằng cách sử dụng &lt;code&gt;Cache-Control&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cache-Control: public, max-age=31536000
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🧹 Giảm Lượng Code Không Cần Thiết
&lt;/h3&gt;

&lt;p&gt;Minify HTML, CSS, JS bằng các công cụ như &lt;strong&gt;Terser&lt;/strong&gt; (JS) hoặc &lt;strong&gt;CSSNano&lt;/strong&gt; (CSS). Loại bỏ các thư viện không cần thiết hoặc sử dụng các thư viện nhẹ hơn.&lt;/p&gt;

&lt;h3&gt;
  
  
  🖼 Tối Ưu Hình Ảnh
&lt;/h3&gt;

&lt;p&gt;Dùng các định dạng ảnh nhẹ như &lt;strong&gt;WebP&lt;/strong&gt; thay vì PNG hoặc JPEG. Sử dụng &lt;strong&gt;Lazy Loading&lt;/strong&gt; để trì hoãn tải hình ảnh không cần thiết.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"image.webp"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Ảnh minh họa"&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ✅ 3. Tối Ưu Cấu Trúc Website
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🛣 Cấu Trúc URL Thân Thiện
&lt;/h3&gt;

&lt;p&gt;URL nên ngắn gọn, dễ đọc và chứa từ khóa liên quan.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ &lt;code&gt;/product?id=1234&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;✅ &lt;code&gt;/product/balo-du-lich&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔗 Tối Ưu Internal Link
&lt;/h3&gt;

&lt;p&gt;Xây dựng liên kết nội bộ để tăng khả năng thu thập dữ liệu của Google. Dùng &lt;strong&gt;anchor text&lt;/strong&gt; tự nhiên, có chứa từ khóa liên quan.&lt;/p&gt;

&lt;h3&gt;
  
  
  🗺 Breadcrumbs
&lt;/h3&gt;

&lt;p&gt;Sử dụng Breadcrumbs giúp người dùng và Google dễ dàng điều hướng.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BreadcrumbList"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"itemListElement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ListItem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Trang chủ"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"item"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ListItem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sản phẩm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"item"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/san-pham"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ✅ 4. Mobile-First Optimization
&lt;/h2&gt;

&lt;p&gt;Google ưu tiên đánh giá phiên bản mobile của website (&lt;strong&gt;Mobile-First Indexing&lt;/strong&gt;). Đảm bảo website &lt;strong&gt;responsive&lt;/strong&gt; và tối ưu cho các thiết bị di động.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;768px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;14px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ✅ 5. HTTPS và Bảo Mật Website
&lt;/h2&gt;

&lt;p&gt;Cài đặt chứng chỉ SSL để đảm bảo website sử dụng &lt;strong&gt;HTTPS&lt;/strong&gt;. Kiểm tra website bằng cách truy cập &lt;code&gt;https://yourwebsite.com&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ✅ 6. Kiểm Tra Và Theo Dõi
&lt;/h2&gt;

&lt;p&gt;Sử dụng &lt;strong&gt;Google Search Console&lt;/strong&gt; để theo dõi hiệu suất tìm kiếm và lỗi thu thập dữ liệu. Sử dụng &lt;strong&gt;Google Analytics&lt;/strong&gt; để theo dõi hành vi người dùng. Cài đặt công cụ như &lt;strong&gt;Screaming Frog SEO Spider&lt;/strong&gt; để quét và phân tích website.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Kết Luận
&lt;/h2&gt;

&lt;p&gt;Tối ưu Technical SEO là một phần quan trọng trong chiến lược SEO tổng thể. Bằng cách:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cải thiện &lt;strong&gt;crawlability&lt;/strong&gt; và &lt;strong&gt;indexability&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Tăng tốc độ tải trang.&lt;/li&gt;
&lt;li&gt;Tối ưu cấu trúc website.&lt;/li&gt;
&lt;li&gt;Đảm bảo trải nghiệm tốt trên thiết bị di động.&lt;/li&gt;
&lt;li&gt;Bảo vệ website bằng HTTPS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bạn sẽ giúp website của mình có thứ hạng cao hơn trên Google và mang lại trải nghiệm tốt hơn cho người dùng.&lt;/p&gt;

&lt;p&gt;Chúc bạn thành công trong hành trình tối ưu SEO! 🚀&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Partial Prerendering in Next.js</title>
      <dc:creator>Việt Anh Trần Hữu</dc:creator>
      <pubDate>Mon, 31 Mar 2025 10:07:43 +0000</pubDate>
      <link>https://dev.to/va2212/partial-prerendering-in-nextjs-2je8</link>
      <guid>https://dev.to/va2212/partial-prerendering-in-nextjs-2je8</guid>
      <description>&lt;h1&gt;
  
  
  🚀 Xin chào mọi người, lại là Slao đây!
&lt;/h1&gt;

&lt;p&gt;Hôm nay, mình sẽ giới thiệu về một chiến lược mới mang tên &lt;strong&gt;PPR&lt;/strong&gt; (&lt;strong&gt;Partial Prerendering&lt;/strong&gt;) vừa được ra mắt của &lt;strong&gt;Next.js&lt;/strong&gt;. Cùng tìm hiểu xem nó hoạt động như thế nào nhé!&lt;/p&gt;




&lt;h2&gt;
  
  
  🔎 &lt;strong&gt;Vấn Đề Của Next.js Hiện Tại&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Trong Next.js, mỗi tuyến đường có thể là:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hoàn toàn tĩnh (Static)&lt;/strong&gt;: Tải nhanh do HTML được tạo sẵn khi build.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hoàn toàn động (Dynamic)&lt;/strong&gt;: Chậm hơn do cần fetch dữ liệu từ server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;strong&gt;Vấn đề xảy ra&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Nếu chỉ có &lt;strong&gt;một thành phần động&lt;/strong&gt; (ví dụ như giỏ hàng), toàn bộ trang sẽ bị đánh dấu là &lt;strong&gt;động&lt;/strong&gt;. Điều này khiến thời gian tải trang lâu hơn, dù phần lớn nội dung là tĩnh.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧱 &lt;strong&gt;Giải Pháp: Partial Prerendering (PPR)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;PPR&lt;/strong&gt; giải quyết vấn đề này bằng cách:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cho phép bạn &lt;strong&gt;kết hợp các phần tĩnh và động&lt;/strong&gt; trong cùng một tuyến đường.&lt;/li&gt;
&lt;li&gt;Tại thời điểm &lt;strong&gt;build&lt;/strong&gt;, Next.js sẽ tạo &lt;strong&gt;HTML tĩnh&lt;/strong&gt; cho các phần tĩnh.&lt;/li&gt;
&lt;li&gt;Các phần động được bao bọc trong ranh giới &lt;strong&gt;React Suspense&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nội dung tĩnh&lt;/strong&gt; hiển thị ngay lập tức, trong khi các phần động được tải nền.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛒 &lt;strong&gt;Ví Dụ Thực Tế&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Hãy tưởng tượng một trang sản phẩm thương mại điện tử:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phần Tĩnh&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Điều hướng&lt;/li&gt;
&lt;li&gt;Hình ảnh sản phẩm&lt;/li&gt;
&lt;li&gt;Mô tả sản phẩm&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Phần Động&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Giỏ hàng&lt;/li&gt;
&lt;li&gt;Đề xuất sản phẩm được cá nhân hóa&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  ❗ &lt;strong&gt;Không Có PPR&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Mọi thứ đều chờ dữ liệu động tải xong.&lt;/li&gt;
&lt;li&gt;Người dùng thấy trang trống trong thời gian dài.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ✅ &lt;strong&gt;Với PPR&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nội dung tĩnh xuất hiện ngay lập tức.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Giỏ hàng và đề xuất&lt;/strong&gt; được tải nền và hiển thị khi sẵn sàng.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trải nghiệm người dùng tốt hơn.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🌟 &lt;strong&gt;Lợi Ích Của PPR&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🚀 &lt;strong&gt;Tải trang nhanh hơn:&lt;/strong&gt; Phần tĩnh được hiển thị ngay lập tức.&lt;/li&gt;
&lt;li&gt;😊 &lt;strong&gt;Trải nghiệm tốt hơn:&lt;/strong&gt; Người dùng không phải chờ đợi dữ liệu động.&lt;/li&gt;
&lt;li&gt;⚡ &lt;strong&gt;Tăng hiệu suất:&lt;/strong&gt; Không có thác nước, các phần động tải song song.&lt;/li&gt;
&lt;li&gt;🌍 &lt;strong&gt;Tối ưu CDN:&lt;/strong&gt; Phần tĩnh được lưu trên CDN, giảm thời gian tải trang.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧑‍💻 &lt;strong&gt;Phân Tích Phần Tĩnh Và Động&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Phần Tĩnh&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Được lưu trữ hoàn toàn trên &lt;strong&gt;CDN&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Phân phối toàn cầu, không cần gọi đến máy chủ.&lt;/li&gt;
&lt;li&gt;Hiển thị &lt;strong&gt;ngay lập tức&lt;/strong&gt; cho người dùng.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Phần Động&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Không thể lưu trữ đệm vì cần dữ liệu mới.&lt;/li&gt;
&lt;li&gt;Phải được &lt;strong&gt;render trên máy chủ&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Được truyền phát sau khi phần tĩnh đã hiển thị.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠 &lt;strong&gt;Cách Hoạt Động Của PPR&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Người dùng yêu cầu trang.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CDN&lt;/strong&gt; ngay lập tức gửi shell tĩnh (bao gồm thanh điều hướng, bố cục, thông tin sản phẩm).&lt;/li&gt;
&lt;li&gt;Song song, &lt;strong&gt;máy chủ bắt đầu tạo nội dung động.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nội dung động&lt;/strong&gt; được truyền phát và hiển thị mà không chặn các phần tĩnh.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🧑‍💻 &lt;strong&gt;Cách sử dụng&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Follow &lt;a href="https://nextjs.org/docs/app/building-your-application/rendering/partial-prerendering" rel="noopener noreferrer"&gt;Rendering: Partial Prerendering | Next.js&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Install Next.js canary version&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable in config&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// next.config.js
{
  experimental: {
    ppr: "incremental";
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Đánh dấu các components động với Suspense&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Suspense fallback={&amp;lt;LoadingCart /&amp;gt;}&amp;gt;
  &amp;lt;ShoppingCart /&amp;gt; {/* Dynamic component */}
&amp;lt;/Suspense&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🚀 &lt;strong&gt;Tóm Lại&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Partial Prerendering (PPR)&lt;/strong&gt; là một giải pháp tối ưu giúp kết hợp giữa nội dung tĩnh và động.
&lt;/li&gt;
&lt;li&gt;Nó giúp &lt;strong&gt;giảm thời gian tải trang&lt;/strong&gt; và &lt;strong&gt;cải thiện trải nghiệm người dùng&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;PPR cũng tối ưu việc sử dụng &lt;strong&gt;CDN&lt;/strong&gt; và tăng hiệu suất tổng thể.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nếu bạn đang xây dựng một trang web có cả nội dung tĩnh và động, &lt;strong&gt;PPR trong Next.js&lt;/strong&gt; chắc chắn sẽ là một công cụ hữu ích!&lt;/p&gt;

&lt;p&gt;Chúc bạn thành công! 🚀&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Cải Thiện Hiệu Suất Trong Next.js [2]</title>
      <dc:creator>Việt Anh Trần Hữu</dc:creator>
      <pubDate>Fri, 28 Mar 2025 10:06:32 +0000</pubDate>
      <link>https://dev.to/va2212/cai-thien-hieu-suat-trong-nextjs-2-5gc1</link>
      <guid>https://dev.to/va2212/cai-thien-hieu-suat-trong-nextjs-2-5gc1</guid>
      <description>&lt;h1&gt;
  
  
  🚀 Cách Làm Cho App/Website Trở Nên Nhanh Và Mượt Mà Hơn
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Hello mọi người lại là Slao đây!&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Phần tiếp theo này chúng ta sẽ đến với cách làm cho chương trình của chúng ta có thể chạy nhanh hơn nhé.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧑‍💻 &lt;strong&gt;1. Di Chuyển Code Tới Server Components&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Nếu có thể, hãy &lt;strong&gt;di chuyển code&lt;/strong&gt; đến &lt;strong&gt;Server Components&lt;/strong&gt; để giảm tải công việc trên client.&lt;br&gt;&lt;br&gt;
Việc xử lý trên server giúp giảm lượng JavaScript tải xuống trình duyệt.&lt;/p&gt;


&lt;h2&gt;
  
  
  ✂️ &lt;strong&gt;2. Chia Tách (Split) Code&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Nếu không thể di chuyển code đến server component, bạn vẫn có thể linh hoạt trong việc &lt;strong&gt;load code trên client&lt;/strong&gt; bằng &lt;strong&gt;Code Splitting&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Next.js có &lt;strong&gt;built-in code splitting&lt;/strong&gt;. Mỗi trang đều nhận được một đoạn mã chunk riêng và có thể chia sẻ các phần code chung.&lt;/p&gt;
&lt;h3&gt;
  
  
  🔎 &lt;strong&gt;Ví Dụ - Dynamic Import&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Modal = dynamic(() =&amp;gt; import("./Modal"), {
  // Loading state to show while the code is loading
  // This is optional
  // If something takes a while, this is good to have!
  loading: () =&amp;gt; &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;,
});

export default function Page() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    &amp;lt;&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setIsOpen(true)}&amp;gt;Open Modal&amp;lt;/button&amp;gt;
      {isOpen &amp;amp;&amp;amp; &amp;lt;Modal /&amp;gt;}
    &amp;lt;/&amp;gt;
  );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Giờ đây mã chỉ được tải khi mà người dùng nhấp vào nút, đấy gọi là Dynamic import&lt;br&gt;
Đôi khi component sử dụng browser API như window hoặc document. Trong trường hợp này bạn có thể set skip server rendering&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const BrowserOnlyComponent = dynamic(() =&amp;gt; import("./Heavy"), {
  ssr: false,
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thành phần này sẽ chỉ tải và kết xuất trên client&lt;/p&gt;

&lt;h1&gt;
  
  
  🛠️ Giảm Dung Lượng Phụ Thuộc Các Dependencies
&lt;/h1&gt;

&lt;h2&gt;
  
  
  🌿 &lt;strong&gt;Tree Shaking&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Cho phép bạn chỉ nhập những gì bạn cần. Ví dụ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Bad: Imports everything
import * as Icons from '@react-icons/all-files'

// Good: Only imports what you use
import { FaGithub } from '@react-icons/all-files/fa/FaGithub'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Một số thư viện như Lodash yêu cầu những cách tiếp cận khác nhau bạn cần nhập trực tiếp từ những đường dẫn cụ thể&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// With lodash, use direct paths
import map from 'lodash/map'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🌿 &lt;strong&gt;Loading on demand&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Bạn chỉ cần tải thư viện khi bạn cần nó&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Instead of importing at the top
import fuse from "fuse.js";
import imageCompression from "browser-image-compression";

// Load libraries when needed
// Example 1
async function handleSearch(query) {
  const Fuse = (await import("fuse.js")).default;
  const fuse = new Fuse(items);
  return fuse.search(query);
}

// Example 2
async function handleImageUpload(file) {
  // Only load compression library when user uploads an image
  const imageCompression = (await import("browser-image-compression")).default;
  const compressedFile = await imageCompression(file, {
    maxSizeMB: 1,
    maxWidthOrHeight: 1920,
  });
  // Upload compressedFile
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🌿 &lt;strong&gt;Finding alternatives&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Đôi khi có những gói, thư viện nhỏ hơn mà làm được điều tương tự:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;moment.js (71KB)&lt;/strong&gt; → &lt;strong&gt;date-fns (12KB)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;lodash (71KB)&lt;/strong&gt; → &lt;strong&gt;Chỉ import các hàm cần thiết&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thư viện biểu đồ nặng&lt;/strong&gt; → &lt;strong&gt;Lựa chọn các thư viện nhẹ hơn&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📚&lt;strong&gt;Tham Khảo Thêm&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;optimizePackageImports&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Lựa chọn các chiến lược hợp lý như:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Streaming and Partial Rendering&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client-Side Rendering (CSR)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental Static Regeneration (ISR)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static Site Generation (SSG)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server-Side Rendering (SSR)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Cải Thiện Hiệu Suất Trong Next.js [1]</title>
      <dc:creator>Việt Anh Trần Hữu</dc:creator>
      <pubDate>Fri, 28 Mar 2025 08:50:41 +0000</pubDate>
      <link>https://dev.to/va2212/cai-thien-hieu-suat-trong-nextjs-1-356p</link>
      <guid>https://dev.to/va2212/cai-thien-hieu-suat-trong-nextjs-1-356p</guid>
      <description>&lt;p&gt;Hello mọi người lại là Slao đây!&lt;/p&gt;

&lt;h1&gt;
  
  
  🌿 &lt;strong&gt;Cải Thiện Hiệu Suất Trong Next.js&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Khi nói về &lt;strong&gt;cải thiện hiệu suất&lt;/strong&gt;, chúng ta thường xét đến &lt;strong&gt;2 khía cạnh chính&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Perceived Performance&lt;/strong&gt; &lt;em&gt;(Hiệu Suất Cảm Nhận)&lt;/em&gt;:&lt;br&gt;&lt;br&gt;
Cảm giác trải nghiệm ứng dụng của người dùng. Điều này bị ảnh hưởng bởi các yếu tố như thời gian tải trang, animation, và trải nghiệm tổng thể.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Actual Performance&lt;/strong&gt; &lt;em&gt;(Hiệu Suất Thực Tế)&lt;/em&gt;:&lt;br&gt;&lt;br&gt;
Tốc độ mà ứng dụng thực sự hoạt động. Để cải thiện phần này, chúng ta cần giảm tải công việc không cần thiết cho ứng dụng.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 &lt;strong&gt;Hiểu Rõ Next.js Bundles Hoạt Động Như Thế Nào&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Khi bạn build một ứng dụng Next.js, nó sẽ tạo ra:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server Bundle&lt;/strong&gt;: Chạy trên server để render các trang (SSR).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client Bundle&lt;/strong&gt;: Là JavaScript cần thiết để chạy trên trình duyệt của người dùng.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📦 &lt;strong&gt;Client Bundle&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chia nhỏ thành các khối (Chunks)&lt;/strong&gt;:
Next.js tự động phân tách code thành các khối nhỏ để tối ưu tải trang.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mỗi trang có một khối riêng&lt;/strong&gt;:
Code chỉ được tải xuống nếu cần thiết.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared Code (Code Dùng Chung)&lt;/strong&gt;:
Nếu nhiều trang dùng chung code, Next.js sẽ tạo các khối riêng để tái sử dụng.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third-party Libraries&lt;/strong&gt;:
Các thư viện bên thứ 3 cũng được tạo thành các khối riêng.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6gs04edd6bfqvaiehmj.png" alt="Bundle Image" width="800" height="982"&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚡ &lt;strong&gt;JavaScript Ảnh Hưởng Tới Hiệu Suất Như Thế Nào?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Khi JavaScript được tải về trình duyệt, nó trải qua 3 bước chính:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tải Xuống (Download)&lt;/strong&gt;:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JS được nén để giảm kích thước.&lt;/li&gt;
&lt;li&gt;Browser sẽ giải nén trước khi sử dụng.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phân Tích Cú Pháp (Parse)&lt;/strong&gt;:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trình duyệt phân tích code để hiểu và thực thi.&lt;/li&gt;
&lt;li&gt;Quá trình này có thể chậm trên các thiết bị yếu.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thực Thi (Execute)&lt;/strong&gt;:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JS thực sự được chạy và thực hiện công việc của nó.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;⛔ Vấn Đề Chính:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Toàn bộ quá trình này diễn ra trên &lt;strong&gt;Main Thread&lt;/strong&gt;. Khi Main Thread bận xử lý JS, các tác vụ như cập nhật UI và xử lý tương tác người dùng có thể bị chậm hoặc giật lag.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Giải Pháp:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Giảm lượng JavaScript tải xuống.&lt;/li&gt;
&lt;li&gt;Tối ưu hóa quá trình phân tích và thực thi code.&lt;/li&gt;
&lt;li&gt;Tải JS hiệu quả bằng lazy loading hoặc dynamic import.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔎 &lt;strong&gt;Cách Tìm Kiếm Vấn Đề Về Hiệu Suất&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Sử Dụng PageSpeed Insights (Lighthouse)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Lighthouse cung cấp các chỉ số quan trọng như:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance Score&lt;/strong&gt;: Điểm hiệu suất, nên đạt &lt;strong&gt;trên 80&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Total Blocking Time (TBT)&lt;/strong&gt;: Tổng thời gian Main Thread bị chặn, nên dưới &lt;strong&gt;300ms&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript Execution Time&lt;/strong&gt;: Thời gian thực thi JS, nên dưới &lt;strong&gt;2.5s&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unused JavaScript&lt;/strong&gt;: Loại bỏ code không sử dụng để tối ưu kích thước.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Một điều thường thấy trong Next.js apps là mọi người thường đơn giản sử dụng Image Component dựa vào Lazy Loading và Async Decoding mọi lúc. Điều quan trọng là phải xem nơi hình ảnh của bạn có đang được sử dụng và liệu nó có nằm trong Viewport hay không&lt;br&gt;
👉 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkoz0fkmc1kx07jrqxpy9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkoz0fkmc1kx07jrqxpy9.png" alt="PageSpeed Insights" width="800" height="747"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fle72ygaly7l1q1fc44h1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fle72ygaly7l1q1fc44h1.png" alt="PageSpeed Insights" width="800" height="827"&gt;&lt;/a&gt;&lt;br&gt;
👉 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0gv6o6khjkpgjesoltar.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0gv6o6khjkpgjesoltar.png" alt="PageSpeed Insights" width="800" height="626"&gt;&lt;/a&gt;&lt;br&gt;
👉 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5u94x7p07o6l0yfts8py.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5u94x7p07o6l0yfts8py.png" alt="PageSpeed Insights" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  2. &lt;strong&gt;Tối Ưu Hình Ảnh&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js Image Component&lt;/strong&gt;:
Sử dụng &lt;code&gt;&amp;lt;Image /&amp;gt;&lt;/code&gt; với Lazy Loading và Async Decoding.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kiểm Tra Viewport&lt;/strong&gt;:
Chỉ tải hình ảnh nếu nó nằm trong &lt;strong&gt;Viewport&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive Images&lt;/strong&gt;:
Sử dụng các kích thước ảnh phù hợp với từng thiết bị.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. &lt;strong&gt;Chrome DevTools&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance Tab&lt;/strong&gt;:
Giúp bạn phân tích thời gian thực thi JS. Mục tiêu là giữ thời gian thực thi dưới &lt;strong&gt;500ms&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcppfnfc0fwk01p9ohx0k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcppfnfc0fwk01p9ohx0k.png" alt="Pertab" width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coverage Tab&lt;/strong&gt;:
Xem phần trăm code không sử dụng trong các chunks.
Nếu hơn &lt;strong&gt;30%&lt;/strong&gt; code không được sử dụng, xem xét tối ưu.
👉 &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp6tz072occkw92al53s9.png" alt="Cotab" width="800" height="446"&gt;
---&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Sử Dụng Bundle Analyzer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Next.js cung cấp &lt;strong&gt;Bundle Analyzer&lt;/strong&gt; để kiểm tra kích thước bundle.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flp74tizh5ga450vh4jlx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flp74tizh5ga450vh4jlx.png" alt="analyzer" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kích thước càng to thì càng chiếm nhiều dung lượng&lt;/p&gt;

&lt;p&gt;Dưới đây là những mục mà bạn có thể phát hiện ra nếu code mình bị chậm, hãy cùng đón xem phần 2 nhé&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Cài Đặt&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
bash
npm install @next/bundle-analyzer


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
    </item>
    <item>
      <title>SEO And SiteMap in NextJs</title>
      <dc:creator>Việt Anh Trần Hữu</dc:creator>
      <pubDate>Fri, 28 Feb 2025 15:13:14 +0000</pubDate>
      <link>https://dev.to/va2212/seo-and-sitemap-in-nextjs-2p29</link>
      <guid>https://dev.to/va2212/seo-and-sitemap-in-nextjs-2p29</guid>
      <description>&lt;h1&gt;
  
  
  Tại sao SiteMap lại quan trọng?
&lt;/h1&gt;

&lt;p&gt;Các công cụ tìm kiếm sử dụng trình thu thập dữ liệu web, còn gọi là bot hoặc spiders, để tìm và lập chỉ mục các trang web. Các trình thu thập dữ liệu này theo các liên kết từ trang này sang trang khác để khám phá nội dung mới. Nếu không có sơ đồ trang web, trình thu thập dữ liệu chỉ phải dựa vào việc tìm liên kết đến các trang mới hoặc đã cập nhật thông qua các liên kết hiện có trên trang web.&lt;/p&gt;

&lt;p&gt;Điều này có thể gây ra vấn đề vì một số lý do:&lt;/p&gt;

&lt;h3&gt;
  
  
  Orphaned Page
&lt;/h3&gt;

&lt;p&gt;Các trang không được liên kết từ các trang khác trên trang web (Orphaned Page) có thể không bao giờ được trình thu thập dữ liệu tìm thấy nếu không có liên kết trực tiếp đến chúng.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deep Hierarchies
&lt;/h3&gt;

&lt;p&gt;Trong các trang web có phân cấp sâu, các trang quan trọng có thể bị chôn vùi ở nhiều cấp độ sâu, khiến trình thu thập dữ liệu khó có thể tiếp cận chúng một cách nhanh chóng.&lt;/p&gt;

&lt;h3&gt;
  
  
  Complex Navigation
&lt;/h3&gt;

&lt;p&gt;Các trang web có cấu trúc điều hướng phức tạp có thể khiến trình thu thập dữ liệu khó tìm thấy tất cả các trang một cách hiệu quả, đặc biệt là nếu liên kết nội bộ không được tối ưu hóa tốt.&lt;/p&gt;

&lt;p&gt;Sitemap cung cấp cho công cụ tìm kiếm danh sách URL trực tiếp, đảm bảo tất cả các trang, ngay cả những trang khó tìm thấy thông qua quá trình thu thập dữ liệu thông thường, đều được phát hiện và lập chỉ mục nhanh hơn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ví dụ về điều hướng phức tạp
&lt;/h2&gt;

&lt;p&gt;Một trang web thương mại điện tử có Deep Hierarchies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Homepage&lt;/strong&gt;: Điểm khởi đầu.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Main Categories&lt;/strong&gt;: Electronics, Clothing, Home &amp;amp; Garden.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subcategories&lt;/strong&gt;: Trong mục Electronics, bạn có Phones, Laptops, Accessories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Product Pages&lt;/strong&gt;: Mỗi danh mục phụ chứa nhiều trang sản phẩm.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Trong ví dụ này, trang sản phẩm cho một mẫu điện thoại cụ thể có thể có nhiều cấp độ sâu (&lt;em&gt;Trang chủ &amp;gt; Điện tử &amp;gt; Điện thoại &amp;gt; Mẫu điện thoại cụ thể&lt;/em&gt;). Nếu không có sơ đồ trang web, công cụ tìm kiếm có thể mất nhiều thời gian hơn để tìm và lập chỉ mục các trang sâu này. Sơ đồ trang web đảm bảo rằng ngay cả những trang sâu nhất cũng được liệt kê và có thể được công cụ tìm kiếm tìm thấy nhanh chóng.&lt;/p&gt;




&lt;h1&gt;
  
  
  Site Map trong Next.js
&lt;/h1&gt;

&lt;p&gt;Next.js có hỗ trợ tích hợp để tạo sơ đồ trang web bằng quy ước tệp &lt;code&gt;sitemap.(js|ts)&lt;/code&gt;. Tạo một tệp trong thư mục ứng dụng và xuất một hàm mặc định trả về một mảng URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { MetadataRoute } from "next";

export default function sitemap(): MetadataRoute.Sitemap {
  return [
    {
      url: "https://acme.com",
      lastModified: new Date(),
      changeFrequency: "yearly",
      priority: 1,
    },
    {
      url: "https://acme.com/about",
      lastModified: new Date(),
      changeFrequency: "monthly",
      priority: 0.8,
    },
    {
      url: "https://acme.com/blog",
      lastModified: new Date(),
      changeFrequency: "weekly",
      priority: 0.5,
    },
  ];
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Có hai thuộc tính chính cần lưu ý: &lt;code&gt;priority&lt;/code&gt; và &lt;code&gt;changeFrequency&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Priority
&lt;/h2&gt;

&lt;p&gt;Thuộc tính &lt;strong&gt;ưu tiên&lt;/strong&gt; trong sơ đồ trang web cho biết mức độ quan trọng của một trang so với các trang khác trên cùng một trang web. Thuộc tính này dao động từ &lt;strong&gt;0.0 đến 1.0&lt;/strong&gt;, trong đó &lt;strong&gt;1.0 là quan trọng nhất&lt;/strong&gt;. Điều này giúp các công cụ tìm kiếm biết được chủ sở hữu trang web cho rằng những trang nào là quan trọng nhất.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ưu tiên cao (0.8 - 1.0)&lt;/strong&gt;: Trang chủ, các trang danh mục chính, các trang đích chính.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ưu tiên trung bình (0.4 - 0.7)&lt;/strong&gt;: Các bài đăng blog thường xuyên, các trang danh mục phụ.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ưu tiên thấp (0.0 - 0.3)&lt;/strong&gt;: Các bài viết tin tức cũ, các trang tiện ích ít quan trọng hơn.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Change Frequency
&lt;/h2&gt;

&lt;p&gt;Thuộc tính &lt;code&gt;changeFrequency&lt;/code&gt; cho biết tần suất nội dung của một trang có khả năng thay đổi. Các giá trị có thể có: &lt;code&gt;"always"&lt;/code&gt;, &lt;code&gt;"hourly"&lt;/code&gt;, &lt;code&gt;"daily"&lt;/code&gt;, &lt;code&gt;"weekly"&lt;/code&gt;, &lt;code&gt;"monthly"&lt;/code&gt;, &lt;code&gt;"yearly"&lt;/code&gt;, &lt;code&gt;"never"&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"always"&lt;/strong&gt;: Các trang thay đổi liên tục, như dữ liệu thị trường chứng khoán.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"hourly"&lt;/strong&gt;: Các trang tin tức được cập nhật thường xuyên.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"daily"&lt;/strong&gt;: Các blog có bài đăng hàng ngày.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"weekly"&lt;/strong&gt;: Các trang sản phẩm có bản cập nhật hàng tuần.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"monthly"&lt;/strong&gt;: Các trang FAQ được cập nhật hàng tháng.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"yearly"&lt;/strong&gt;: Các trang liên hệ hoặc trang giới thiệu.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"never"&lt;/strong&gt;: Nội dung được lưu trữ không bao giờ thay đổi.
Sitemap thường là một tệp XML trông giống như sau:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"&amp;gt;
  &amp;lt;url&amp;gt;
    &amp;lt;loc&amp;gt;https://example.com/&amp;lt;/loc&amp;gt;
    &amp;lt;lastmod&amp;gt;2023-06-21&amp;lt;/lastmod&amp;gt;
    &amp;lt;changefreq&amp;gt;daily&amp;lt;/changefreq&amp;gt;
    &amp;lt;priority&amp;gt;1.0&amp;lt;/priority&amp;gt;
  &amp;lt;/url&amp;gt;
  &amp;lt;url&amp;gt;
    &amp;lt;loc&amp;gt;https://example.com/about&amp;lt;/loc&amp;gt;
    &amp;lt;lastmod&amp;gt;2023-06-20&amp;lt;/lastmod&amp;gt;
    &amp;lt;changefreq&amp;gt;monthly&amp;lt;/changefreq&amp;gt;
    &amp;lt;priority&amp;gt;0.8&amp;lt;/priority&amp;gt;
  &amp;lt;/url&amp;gt;
&amp;lt;/urlset&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trang web này sẽ được triển khai tới &lt;code&gt;https://example.com/sitemap.xml&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Chúng ta không muốn trình thu thập dữ liệu web (crawler) lập chỉ mục tất cả các trang
&lt;/h2&gt;

&lt;p&gt;Một số trang của chúng tôi là &lt;strong&gt;riêng tư&lt;/strong&gt;, ví dụ như sau khi xác thực. Chúng tôi không muốn trình thu thập dữ liệu web lập chỉ mục các trang đó. Ngay từ đầu, các công cụ tìm kiếm sẽ không thể phát hiện ra chúng.&lt;/p&gt;

&lt;p&gt;Bạn có thể truyền đạt điều này tới trình thu thập dữ liệu web bằng cách thêm tệp &lt;strong&gt;robots.txt&lt;/strong&gt; vào gốc trang web của bạn.&lt;/p&gt;

&lt;p&gt;Trong Next.js, bạn có thể tạo tệp &lt;code&gt;robots.txt&lt;/code&gt; bằng cách thêm tệp &lt;code&gt;robots.ts&lt;/code&gt; vào thư mục &lt;code&gt;app/&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
  return {
    rules: [
      {
        userAgent: "*",
        allow: "/",
        disallow: "/private/",
      },
    ],
    sitemap: "https://example.com/sitemap.xml",
  };
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Tối ưu Package Imports Nextjs</title>
      <dc:creator>Việt Anh Trần Hữu</dc:creator>
      <pubDate>Fri, 28 Feb 2025 14:50:29 +0000</pubDate>
      <link>https://dev.to/va2212/toi-uu-package-imports-nextjs-5df0</link>
      <guid>https://dev.to/va2212/toi-uu-package-imports-nextjs-5df0</guid>
      <description>&lt;p&gt;Hello mọi người lại là Slao đây !&lt;br&gt;
Sau đây vấn đề chúng ta sẽ giải quyết là hiểu tại sao lại dẫn đến sự ảnh hưởng khi import Package một cách bừa bãi và cách giải quyết nó&lt;/p&gt;
&lt;h1&gt;
  
  
  Vấn đề về Barrel File
&lt;/h1&gt;

&lt;p&gt;Nhiều thư viện (đặc biệt là các thư viện biểu tượng/thành phần) sử dụng "tệp Barrel", các tệp xuất lại nhiều mô-đun từ một điểm nhập duy nhất.&lt;/p&gt;

&lt;p&gt;Ví dụ, nếu bạn nhập &lt;code&gt;{ AlertIcon }&lt;/code&gt; từ &lt;code&gt;'lucide-react'&lt;/code&gt;, thì thực ra bạn đang nhập thông qua tệp Barrel có thể chứa hàng nghìn biểu tượng xuất khác. Mặc dù bạn chỉ muốn một biểu tượng, thời gian chạy JavaScript phải xử lý &lt;strong&gt;TẤT CẢ&lt;/strong&gt; các lần xuất, có thể mất &lt;strong&gt;200-800ms&lt;/strong&gt; hoặc thậm chí &lt;strong&gt;vài giây&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Tại sao đây là vấn đề về hiệu suất?
&lt;/h2&gt;

&lt;p&gt;Mỗi &lt;code&gt;require()&lt;/code&gt; hoặc &lt;code&gt;import&lt;/code&gt; đều có chi phí phát sinh trong JavaScript.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trong quá trình phát triển&lt;/strong&gt;: Làm chậm quá trình khởi động ban đầu và tải lại mô-đun nóng.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trong quá trình sản xuất&lt;/strong&gt;: Đặc biệt ảnh hưởng đến môi trường &lt;strong&gt;không có máy chủ (serverless)&lt;/strong&gt;, nơi thường xuyên khởi động nguội.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Một số thư viện có &lt;strong&gt;tới 10.000 lần xuất lại&lt;/strong&gt; trong các tệp barrel của chúng!&lt;/p&gt;
&lt;h1&gt;
  
  
  optimizePackageImports trong Next.js
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Cách hoạt động
&lt;/h2&gt;

&lt;p&gt;Bạn có thể bật &lt;code&gt;optimizePackageImports&lt;/code&gt; trong &lt;code&gt;next.config.js&lt;/code&gt; cho các gói cụ thể để tối ưu hóa quá trình nhập.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  experimental: {
    optimizePackageImports: ["lucide-react", "my-lib"],
  },
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Next.js phân tích tệp barrel của các gói này. Khi nó thấy import { AlertIcon } from 'lucide-react', nó tự động chuyển đổi tệp đó để import trực tiếp từ tệp module cụ thể. Giống như thay đổi import { AlertIcon } from 'lucide-react' thành import AlertIcon from 'lucide-react/dist/icons/alert' ở bên trong.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Khi nào nên sử dụng
&lt;/h2&gt;

&lt;p&gt;Nên cân nhắc sử dụng &lt;code&gt;optimizePackageImports&lt;/code&gt; khi:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Đang sử dụng các thư viện biểu tượng lớn&lt;/strong&gt; (&lt;code&gt;lucide-react&lt;/code&gt;, &lt;code&gt;@tabler/icons-react&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Đang sử dụng các thư viện thành phần có nhiều exports&lt;/strong&gt; (&lt;code&gt;@mui/material&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nhận thấy thời gian khởi động development server chậm&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lo ngại về thời gian khởi động nguội trong production&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Việc tải lại mô-đun nóng có cảm giác chậm chạp&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Cải thiện hiệu suất
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Môi trường&lt;/th&gt;
&lt;th&gt;Cải thiện hiệu suất&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Development&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Thời gian khởi động nhanh hơn &lt;strong&gt;15-70%&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Build time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bản dựng nhanh hơn khoảng &lt;strong&gt;28%&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cold Start&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Nhanh hơn tới &lt;strong&gt;40%&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Ví dụ: Khi sử dụng &lt;code&gt;@material-ui/icons&lt;/code&gt;, thời gian phát triển giảm từ &lt;strong&gt;10,2 giây&lt;/strong&gt; xuống còn &lt;strong&gt;2,9 giây&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cách phát hiện khi cần tối ưu hóa
&lt;/h2&gt;

&lt;p&gt;Bạn có thể kiểm tra các dấu hiệu sau:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;node_modules&lt;/strong&gt; chứa các gói có tệp &lt;code&gt;index.js&lt;/code&gt; lớn với nhiều lần export (sử dụng trình phân tích gói).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sử dụng các thư viện UI component hoặc thư viện biểu tượng phổ biến&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Máy chủ development khởi động chậm (mất vài giây)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quá trình build chậm hơn mong đợi&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nhận thấy vấn đề về hiệu suất khi nhập từ các thư viện lớn&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Có thể kiểm tra thời gian nhập bằng cách thêm &lt;code&gt;console.time()&lt;/code&gt; trước và sau khi nhập&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Console time :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.time("import");
import { AlertIcon } from "lucide-react";
console.timeEnd("import");

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Ưu điểm của optimizePackageImports
&lt;/h2&gt;

&lt;p&gt;Điều hay ho là &lt;strong&gt;Next.js tự động xử lý mọi thứ&lt;/strong&gt;. Bạn chỉ cần chọn các gói cần tối ưu hóa, và Next.js sẽ lo phần còn lại.&lt;/p&gt;




&lt;h2&gt;
  
  
  Không dành cho các tệp barrel của riêng bạn
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;optimizePackageImports&lt;/code&gt; &lt;strong&gt;chỉ áp dụng cho các gói trong &lt;code&gt;node_modules&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;không phải&lt;/strong&gt; cho các tệp barrel trong dự án của bạn.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Using a barrel file
import { Button, Card, TextField } from "@/components";

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Đây là sự nhầm lẫn mà nhiều người gặp phải.&lt;/li&gt;
&lt;li&gt;Đối với &lt;strong&gt;các tệp barrel của riêng&lt;/strong&gt;, &lt;strong&gt;nên tránh hoàn toàn&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Direct imports - better performance
import Button from "@/components/Button";
import Card from "@/components/Card";
import TextField from "@/components/TextField";

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Giải pháp:&lt;/strong&gt; Cấu trúc lại mã để &lt;strong&gt;sử dụng import trực tiếp&lt;/strong&gt; thay vì tối ưu hóa các tệp barrel.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Khi nào &lt;code&gt;optimizePackageImports&lt;/code&gt; thực sự hữu ích?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;optimizePackageImports&lt;/code&gt; hỗ trợ các gói bên thứ ba có cấu trúc phức tạp mà bạn không thể kiểm soát, đặc biệt là:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Thư viện biểu tượng&lt;/strong&gt; (&lt;code&gt;lucide-react&lt;/code&gt;, &lt;code&gt;@tabler/icons&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thư viện UI component&lt;/strong&gt; (&lt;code&gt;@mui/material&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thư viện tiện ích lớn&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nếu gặp vấn đề về hiệu suất với các &lt;strong&gt;tệp barrel của riêng bạn&lt;/strong&gt;, hãy &lt;strong&gt;cấu trúc lại mã&lt;/strong&gt; thay vì tìm cách tối ưu hóa chúng.&lt;/p&gt;




</description>
    </item>
    <item>
      <title>Server Component và Client Component Patterns Nextjs</title>
      <dc:creator>Việt Anh Trần Hữu</dc:creator>
      <pubDate>Fri, 28 Feb 2025 14:11:46 +0000</pubDate>
      <link>https://dev.to/va2212/server-component-va-client-component-patterns-nextjs-1k5i</link>
      <guid>https://dev.to/va2212/server-component-va-client-component-patterns-nextjs-1k5i</guid>
      <description>&lt;p&gt;Hello mọi người lại là Slao đây !&lt;/p&gt;

&lt;h1&gt;
  
  
  Sự khác biệt giữa Client và Server Component và những điều bạn chưa biết
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Server Component có thể
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Truy xuất dữ liệu trực tiếp&lt;/strong&gt;: Server Components có thể lấy dữ liệu trực tiếp từ các nguồn dữ liệu mà không cần thông qua client. Điều này giúp tối ưu hóa hiệu suất vì dữ liệu được xử lý trực tiếp trên máy chủ trước khi gửi đến client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Truy cập tài nguyên backend (cơ sở dữ liệu, API nội bộ)&lt;/strong&gt;: Chúng có thể tương tác trực tiếp với các tài nguyên backend như cơ sở dữ liệu hoặc các API nội bộ, giúp đơn giản hóa quy trình phát triển và bảo mật hơn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bảo mật thông tin nhạy cảm (token, API keys)&lt;/strong&gt;: Vì các thành phần này chạy trên máy chủ, các thông tin nhạy cảm như token hay API keys không bao giờ được gửi đến client, giảm thiểu rủi ro bị lộ thông tin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chứa các dependencies lớn không cần gửi đến client&lt;/strong&gt;: Server Components có thể chứa các thư viện hoặc dependencies lớn mà không cần gửi chúng đến client, giúp giảm tải cho trình duyệt và cải thiện hiệu suất tổng thể.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Client Component có thể
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Thêm tính tương tác với các sự kiện (onClick, onChange)&lt;/strong&gt;: Client Components có thể xử lý các sự kiện như nhấp chuột (onClick) hoặc thay đổi giá trị (onChange), giúp tạo ra các tương tác động trên giao diện người dùng.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sử dụng React state và lifecycle effects (useState, useEffect)&lt;/strong&gt;: Chúng có thể sử dụng các hook như &lt;code&gt;useState&lt;/code&gt; để quản lý trạng thái và &lt;code&gt;useEffect&lt;/code&gt; để thực hiện các tác vụ phụ khi component được render hoặc cập nhật.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Truy cập các API chỉ có trên trình duyệt (window, localStorage)&lt;/strong&gt;: Client Components có thể truy cập các API đặc thù của trình duyệt như &lt;code&gt;window&lt;/code&gt; hoặc &lt;code&gt;localStorage&lt;/code&gt;, điều mà Server Components không thể làm được.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sử dụng custom hooks phụ thuộc vào state hoặc browser APIs&lt;/strong&gt;: Chúng có thể sử dụng các custom hooks mà phụ thuộc vào trạng thái hoặc các API của trình duyệt, giúp tái sử dụng logic một cách hiệu quả.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sử dụng React class components&lt;/strong&gt;: Client Components cũng có thể sử dụng các class components của React, mặc dù functional components với hooks đã trở nên phổ biến hơn.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Lưu ý&lt;/strong&gt;: Các Client Components cần có chỉ thị &lt;code&gt;"use client"&lt;/code&gt; ở đầu file để báo cho Next.js biết rằng chúng nên được chạy trên client. Điều này giúp phân biệt giữa các thành phần chạy trên máy chủ và các thành phần chạy trên trình duyệt.&lt;/p&gt;




&lt;h2&gt;
  
  
  Chia sẻ dữ liệu giữa các Components
&lt;/h2&gt;

&lt;p&gt;Khi nhiều Server Components cần cùng một dữ liệu, bạn không cần phải truyền dữ liệu thông qua props hoặc sử dụng React Context. Thay vào đó, mỗi component có thể tự fetch dữ liệu mà nó cần một cách độc lập.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js tự động memoize các lệnh fetch&lt;/strong&gt;: Nếu nhiều component yêu cầu cùng một dữ liệu, Next.js sẽ đảm bảo rằng lệnh fetch thực tế chỉ được thực hiện một lần. Điều này giúp tối ưu hiệu suất và tránh lãng phí tài nguyên.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Đối với các hàm không phải fetch&lt;/strong&gt;: Bạn có thể sử dụng hàm &lt;code&gt;cache&lt;/code&gt; của React để đạt được hiệu quả tương tự (memoization).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Giữ mã Server Code tránh xa Client
&lt;/h2&gt;

&lt;p&gt;Đôi khi, các đoạn mã chỉ dành cho server (như truy cập biến môi trường riêng tư) có thể vô tình được đưa vào các gói client (client bundles). Để ngăn chặn điều này, bạn có thể sử dụng gói &lt;code&gt;server-only&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// In your server-only module
import "server-only";

export async function getData() {
  // Code that should only run on the server
  const res = await fetch("https://api.example.com", {
    headers: { authorization: process.env.API_KEY },
  });
  return res.json();
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nếu bất kỳ Client Component nào cố gắng import module này, bạn sẽ nhận được lỗi &lt;strong&gt;build-time error&lt;/strong&gt;, giúp đảm bảo rằng mã server không bao giờ bị rò rỉ vào client.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sử dụng Third-Party Components (Các thành phần từ bên thứ ba)
&lt;/h2&gt;

&lt;p&gt;Nhiều thư viện bên thứ ba chưa thêm chỉ thị &lt;code&gt;"use client"&lt;/code&gt; mặc dù chúng sử dụng các tính năng chỉ dành cho client. Điều này khiến chúng hoạt động trong Client Components nhưng sẽ gây lỗi trong Server Components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Giải pháp&lt;/strong&gt;: Bọc các thành phần bên thứ ba trong một Client Component của riêng bạn. Bây giờ, bạn có thể sử dụng thành phần đã bọc này trong Server Components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// carousel.tsx
"use client";
import { Carousel } from "acme-carousel";
export default Carousel;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Sử dụng Context Providers
&lt;/h2&gt;

&lt;p&gt;React Context không hoạt động trong Server Components. Để sử dụng context, bạn cần tạo provider trong một Client Component. Sau đó, sử dụng provider này trong layout của Server Component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// theme-provider.tsx
"use client";
import { createContext } from "react";
export const ThemeContext = createContext({});

export default function ThemeProvider({ children }) {
  return &amp;lt;ThemeContext.Provider value="dark"&amp;gt;{children}&amp;lt;/ThemeContext.Provider&amp;gt;;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sau đó sử dụng ở Server Component Layout&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// layout.tsx
import ThemeProvider from "./theme-provider";

export default function Layout({ children }) {
  return (
    &amp;lt;html&amp;gt;
      &amp;lt;body&amp;gt;
        &amp;lt;ThemeProvider&amp;gt;{children}&amp;lt;/ThemeProvider&amp;gt;
      &amp;lt;/body&amp;gt;
    &amp;lt;/html&amp;gt;
  );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Client Component Patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Di chuyển Client Components xuống dưới cây component
&lt;/h3&gt;

&lt;p&gt;Để giảm lượng JavaScript gửi đến trình duyệt, hãy di chuyển các phần tương tác vào các Client Components riêng biệt thay vì biến toàn bộ layout hoặc trang thành Client Components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ví dụ&lt;/strong&gt;: Giữ layout là một Server Component, nhưng biến thanh tìm kiếm tương tác thành một Client Component.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Truyền Props từ Server Components sang Client Components
&lt;/h3&gt;

&lt;p&gt;Bạn có thể truyền dữ liệu từ Server Components sang Client Components, nhưng các props phải có thể &lt;strong&gt;serializable&lt;/strong&gt; (có thể chuyển đổi thành JSON). Các đối tượng phức tạp như hàm, ngày tháng hoặc lớp sẽ không hoạt động.&lt;/p&gt;

&lt;p&gt;Nếu bạn cần dữ liệu không thể serializable, hãy fetch trực tiếp trong Client Component hoặc sử dụng &lt;strong&gt;Route Handler&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Interleaving Server and Client Components
&lt;/h2&gt;

&lt;p&gt;Bạn có thể hình dung giao diện người dùng của mình như một cây bắt đầu từ layout gốc (một &lt;strong&gt;Server Component&lt;/strong&gt;). Một số nhánh cây có thể được render trên client bằng cách thêm &lt;code&gt;"use client"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Trong các nhánh client, bạn vẫn có thể bao gồm &lt;strong&gt;Server Components&lt;/strong&gt;, nhưng cần tuân theo các quy tắc quan trọng.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pattern to Avoid: Importing Server Components vào Client Components
&lt;/h2&gt;

&lt;p&gt;Điều này &lt;strong&gt;không hoạt động&lt;/strong&gt;: Bạn không thể import một Server Component vào Client Component. Thay vào đó, hãy sử dụng pattern truyền Server Components dưới dạng props.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"use client";
// ❌ Error: You cannot import a Server Component into a Client Component
import ServerComponent from "./server-component";

export default function ClientComponent() {
  const [count, setCount] = useState(0);
  return (
    &amp;lt;&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(count + 1)}&amp;gt;{count}&amp;lt;/button&amp;gt;
      &amp;lt;ServerComponent /&amp;gt;
    &amp;lt;/&amp;gt;
  );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Supported Pattern: Truyền Server Components dưới dạng Props
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// In client-component.tsx
'use client'
export default function ClientComponent({ children }) {
  const [count, setCount] = useState(0)
  return (
    &amp;lt;&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(count + 1)}&amp;gt;{count}&amp;lt;/button&amp;gt;
      {children}
    &amp;lt;/&amp;gt;
  )
}

// In page.tsx (a Server Component)
import ClientComponent from './client-component'
import ServerComponent from './server-component'

export default function Page() {
  return (
    &amp;lt;ClientComponent&amp;gt;
      &amp;lt;ServerComponent /&amp;gt;
    &amp;lt;/ClientComponent&amp;gt;
  )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Đây là cách làm đúng: Bạn có thể truyền Server Components vào Client Components thông qua props như &lt;code&gt;children&lt;/code&gt;. Cách tiếp cận này cho phép cả hai component render độc lập: Server Component render trên server trước, và Client Component render trên client sau.&lt;/p&gt;

&lt;p&gt;Bạn không bị giới hạn ở prop &lt;code&gt;children&lt;/code&gt;. Bạn có thể sử dụng bất kỳ prop nào để truyền nội dung &lt;strong&gt;Server Component&lt;/strong&gt; vào &lt;strong&gt;Client Component&lt;/strong&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Caching trong NextJS hoạt động như thế nào</title>
      <dc:creator>Việt Anh Trần Hữu</dc:creator>
      <pubDate>Fri, 28 Feb 2025 10:27:10 +0000</pubDate>
      <link>https://dev.to/va2212/caching-trong-nextjs-hoat-dong-nhu-the-nao-3h4o</link>
      <guid>https://dev.to/va2212/caching-trong-nextjs-hoat-dong-nhu-the-nao-3h4o</guid>
      <description>&lt;h1&gt;
  
  
  Chào mọi người, lại là Slao đây!
&lt;/h1&gt;

&lt;p&gt;Bài viết này sẽ giúp chúng ta hiểu rõ hơn về &lt;strong&gt;cơ chế cached của Next.js&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔥 Có 4 cơ chế caching trong Next.js
&lt;/h2&gt;

&lt;h2&gt;
  
  
  1️⃣ Request Memoization
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Request Memoization&lt;/strong&gt; là cơ chế phổ biến nhất. Trong một trang web, có thể có nhiều &lt;strong&gt;component&lt;/strong&gt; cần sử dụng cùng một dữ liệu, Next.js sẽ &lt;strong&gt;chỉ fetch một lần duy nhất&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  📌 Ví dụ:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Một component hiển thị thông tin người dùng.&lt;/li&gt;
&lt;li&gt;Một component khác hiển thị số lượng bài viết của người dùng đó.&lt;/li&gt;
&lt;li&gt;Một component khác nữa hiển thị avatar của người dùng.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thay vì mỗi component tự fetch dữ liệu từ server một cách độc lập, bạn có thể tối ưu bằng cách &lt;strong&gt;fetch dữ liệu một lần và chia sẻ kết quả cho tất cả các component cần dùng&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚙️ Cách hoạt động:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Khi sử dụng &lt;strong&gt;React Query, SWR&lt;/strong&gt;, hoặc &lt;strong&gt;fetch API&lt;/strong&gt; trong Next.js, dữ liệu chỉ fetch &lt;strong&gt;một lần&lt;/strong&gt; và lưu vào bộ nhớ đệm (cache).&lt;/li&gt;
&lt;li&gt;Các component khác nhau sẽ sử dụng &lt;strong&gt;cùng một bản sao dữ liệu từ cache&lt;/strong&gt; thay vì gọi API nhiều lần.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ✅ Lợi ích của Request Memoization:
&lt;/h3&gt;

&lt;p&gt;✔ Giảm số lượng request đến server.&lt;br&gt;&lt;br&gt;
✔ Tăng tốc độ tải trang.&lt;br&gt;&lt;br&gt;
✔ Đảm bảo tính nhất quán của dữ liệu giữa các component.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Cache này &lt;strong&gt;chỉ tồn tại trong phạm vi của một request&lt;/strong&gt; (một lần tải trang). Khi người dùng tải lại trang hoặc chuyển sang trang khác, cache sẽ bị xóa.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2️⃣ Data Cached
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔹 &lt;strong&gt;Data Cache là gì?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Data Cache&lt;/strong&gt; là một bộ nhớ đệm (cache) trên server, &lt;strong&gt;lưu trữ kết quả của các yêu cầu fetch&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚙️ Cách hoạt động:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Khi gọi &lt;code&gt;fetch()&lt;/code&gt;, Next.js kiểm tra xem dữ liệu có trong &lt;strong&gt;Data Cache&lt;/strong&gt; chưa.&lt;/li&gt;
&lt;li&gt;Nếu có, nó sẽ sử dụng dữ liệu từ cache &lt;strong&gt;thay vì fetch lại&lt;/strong&gt; từ nguồn dữ liệu.&lt;/li&gt;
&lt;li&gt;Nếu chưa có, Next.js sẽ &lt;strong&gt;fetch từ nguồn&lt;/strong&gt;, lưu vào cache và sử dụng nó.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ✅ Lợi ích của Data Cache:
&lt;/h3&gt;

&lt;p&gt;✔ &lt;strong&gt;Tăng tốc độ ứng dụng:&lt;/strong&gt; Giảm thời gian fetch dữ liệu.&lt;br&gt;&lt;br&gt;
✔ &lt;strong&gt;Giảm tải cho database hoặc API:&lt;/strong&gt; Ít request hơn.&lt;br&gt;&lt;br&gt;
✔ &lt;strong&gt;Tiết kiệm tài nguyên:&lt;/strong&gt; Dữ liệu chia sẻ giữa nhiều người dùng.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔧 Kiểm soát Data Cache:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Theo mặc định, &lt;strong&gt;Data Cache vô thời hạn&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Có thể kiểm soát bằng cách thiết lập &lt;strong&gt;revalidation&lt;/strong&gt; hoặc &lt;strong&gt;tắt cache hoàn toàn&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Cache the data, but revalidate it after one hour
fetch('https://api.example.com/data', { next: { revalidate: 3600 } })

// Don't cache this data at all
fetch('https://api.example.com/data', { cache: 'no-store' })

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3️⃣ Full Route Cache
&lt;/h2&gt;

&lt;p&gt;Next.js không chỉ cache &lt;strong&gt;data&lt;/strong&gt;, mà còn cache &lt;strong&gt;toàn bộ trang đã được render&lt;/strong&gt;, bao gồm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTML của trang&lt;/strong&gt; (tạo từ quá trình render).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React Server Component Payload&lt;/strong&gt; (biểu diễn nhỏ gọn của các Server Component trong trang).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🚀 Khi một trang được cache, Next.js không cần phải render lại trang đó mỗi lần truy cập&lt;/strong&gt;, giúp tải trang nhanh hơn.&lt;/p&gt;




&lt;h2&gt;
  
  
  4️⃣ Route Cache
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Khi người dùng &lt;strong&gt;điều hướng&lt;/strong&gt; giữa các trang, Next.js lưu các trang đã truy cập trước đó vào &lt;strong&gt;cache trên trình duyệt&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache này tồn tại trong suốt session của người dùng&lt;/strong&gt; và bị xóa khi họ refresh trang.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📌 Ví dụ cách hoạt động của Cache
&lt;/h2&gt;

&lt;p&gt;🛠 &lt;strong&gt;Bước 1 (Build):&lt;/strong&gt; Next.js render tĩnh trang blog và lưu vào &lt;strong&gt;Full Route Cache&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
🔍 &lt;strong&gt;Bước 2 (Fetch dữ liệu):&lt;/strong&gt; Khi người dùng truy cập trang blog, Next.js fetch dữ liệu bài viết và lưu vào &lt;strong&gt;Data Cache&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
🎨 &lt;strong&gt;Bước 3 (Render):&lt;/strong&gt; Nếu nhiều component cần cùng một dữ liệu, Next.js sử dụng &lt;strong&gt;Request Memoization&lt;/strong&gt; để fetch &lt;strong&gt;chỉ một lần&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
🔄 &lt;strong&gt;Bước 4 (Điều hướng):&lt;/strong&gt; Khi người dùng &lt;strong&gt;chuyển trang&lt;/strong&gt;, Next.js lưu nội dung trang vào &lt;strong&gt;Router Cache&lt;/strong&gt;, giúp người dùng quay lại trang nhanh hơn.  &lt;/p&gt;




&lt;p&gt;📢 &lt;strong&gt;Tóm lại:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request Memoization&lt;/strong&gt;: Fetch một lần trong request, dùng chung giữa các component.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Cache&lt;/strong&gt;: Lưu cache dữ liệu fetch trên server, dùng lại cho nhiều request.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full Route Cache&lt;/strong&gt;: Cache toàn bộ trang đã render.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Route Cache&lt;/strong&gt;: Cache trang trên trình duyệt khi người dùng điều hướng.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hy vọng bài viết giúp bạn hiểu rõ hơn về caching trong Next.js! 🚀🔥&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Trả lời một số câu hỏi về Nextjs (2)</title>
      <dc:creator>Việt Anh Trần Hữu</dc:creator>
      <pubDate>Fri, 31 Jan 2025 12:19:11 +0000</pubDate>
      <link>https://dev.to/va2212/tra-loi-mot-so-cau-hoi-ve-nextjs-2-10oi</link>
      <guid>https://dev.to/va2212/tra-loi-mot-so-cau-hoi-ve-nextjs-2-10oi</guid>
      <description>&lt;p&gt;Xin chào mọi người lại là Slao đây&lt;br&gt;
Sau đây chúng ta sẽ tiếp tục những gì còn dang dở ở bài viết trước nhé&lt;/p&gt;

&lt;p&gt;Dưới đây là 1 số topic chúng ta thảo luận&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
How Can I Skip the Root Layout for Some Pages in Next.js?
&lt;/li&gt;
&lt;li&gt;
How To Set Metadata Tags in App Router?
&lt;/li&gt;
&lt;li&gt;
How To Set Metadata Dynamically for an App Router Page?
&lt;/li&gt;
&lt;li&gt;
Can I Set Metadata in a Layout File?
&lt;/li&gt;
&lt;li&gt;
Can I Use Contexts with App Router?
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  How Can I Skip the Root Layout for Some Pages in Next.js?
&lt;/h2&gt;

&lt;p&gt;Một dự án Nextjs với rất nhiều layout files, về mặt kĩ thuật thì mỗi trang đều có thể có layout riêng. Tệp layout cao nhất bao bọc toàn bộ ứng dụng gọi là Root Layout.&lt;/p&gt;

&lt;p&gt;Các Layout file cho phép bạn tái sử dụng lại component như là một phần bao bọc các Page. Thông thường nhất mỗi ứng dụng Nextjs sẽ có Root Layout bao gồm ứng dụng chính, menu, tiêu đề, hero image....&lt;/p&gt;

&lt;p&gt;Giờ chúng ta sẽ đến với vấn đề chính. How Can I Skip the Root Layout for Some Pages in Next.js? Nextjs có một tính năng gọi là Route Groups cho phép bạn có nhiều Root layout. Có nghĩa là các thành phần khác nhau có bố cục khác nhau, điều này cũng có thể bỏ qua bất kỳ thành phần nào trong bố cục cho một số page nhất định&lt;/p&gt;

&lt;p&gt;Một điều cần lưu ý là khi sử dụng route group bạn sẽ trigger tải toàn bộ trang. Đó là điều bạn sẽ gặp phải khi thay thế thành phần cao nhất của server component trong ứng dụng. Nó đơn giản nghĩa là bạn render một phần hoàn toàn mới trong ứng dụng đọc lập với thành phần còn lại của tất cả các trang&lt;/p&gt;
&lt;h2&gt;
  
  
  How To Set Metadata Tags in App Router?
&lt;/h2&gt;

&lt;p&gt;Nextjs dễ dàng đặt metadataa cho ứng dụng và page. Điều duy nhất phải làm là xuất một đối tượng metadata từ bất kì layout hoặc page file nào của bnaj để đặt metadata cho layout/page đó&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'Next.js Metadata Example',
  description: 'Example of metadata in Next.js',
}

export default function MyPage() { ... }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How To Set Metadata Dynamically for an App Router Page?
&lt;/h2&gt;

&lt;p&gt;Để tối ưu nhất cho SEO việc thiết lập metadata tĩnh không bao giờ là đủ. Vì dữ liệu sẽ là duy nhất cho hầu hết mọi trang và thậm chí được tải trong thời gian chạy từ server. Để đặt metadata động trong nextjs, có thể sử dụng chức năng generateMetadata&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import type { Metadata } from 'next'

export async function generateMetadata(): Promise&amp;lt;Metadata&amp;gt; {
  const data = await fetch('someUrl').then((res) =&amp;gt; res.json())

  return {
    title: 'Next.js Dynamic Metadata Example',
    description: data.pageDescription,
  }
}

export default function MyPage() { ... }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Điều cần biết là chức năng tìm nạp trong nextjs theo mặc định bộ nhớ cache là duplicated requests. Đây là một hành vi chung không cụ thể cho metadata. Ngay cả các yêu cầu Server Component cũng bị cache khi mà fetch. Mặc dù nó có thể từ chối và thậm chí vô hiệu hóa tự động một số tính năng khi chức năng của nextjs được sử dụng&lt;/p&gt;

&lt;h2&gt;
  
  
  Can I Set Metadata in a Layout File?
&lt;/h2&gt;

&lt;p&gt;Bạn có thể đặt metadata trong layout file, cả static và dynamically. &lt;/p&gt;

&lt;h2&gt;
  
  
  Can I Use Contexts with App Router?
&lt;/h2&gt;

&lt;p&gt;Có thể sử dụng React Contexts với App Route trong Next. Bạn có thể đặt bối cảnh ở trong root Layout để có thể cung cấp cho các thành phần của Client Component. Context sẽ không available để sử dụng trong Server Component và sẽ không làm hỏng hành vi kết xuất (render) của Server Component&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Trả lời một số câu hỏi về Nextjs</title>
      <dc:creator>Việt Anh Trần Hữu</dc:creator>
      <pubDate>Fri, 31 Jan 2025 12:17:15 +0000</pubDate>
      <link>https://dev.to/va2212/tra-loi-mot-so-cau-hoi-ve-nextjs-3lm7</link>
      <guid>https://dev.to/va2212/tra-loi-mot-so-cau-hoi-ve-nextjs-3lm7</guid>
      <description>&lt;p&gt;Xin chào mọi người lại là Slao đây&lt;br&gt;
Sau đây mình sẽ trả lời một số câu hỏi có liên quan về Nextjs&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How To Read URL Params in a Client Component?&lt;/li&gt;
&lt;li&gt;How To Read URL Params in a Page File?&lt;/li&gt;
&lt;li&gt;Is it Possible to Render a Client Component in a Server Component?&lt;/li&gt;
&lt;li&gt;How To Read URL Params in a Server Component?&lt;/li&gt;
&lt;li&gt;Why Doesn't searchParams Exist in Next.js Layout Files?&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  How To Read URL Params in a Client Component?
&lt;/h2&gt;

&lt;p&gt;Nếu bạn cần đọc pathname hoặc query params từ URL trong Client Component thì bạn có thể sử dụng usePathname hoặc là useSearchParams như sau&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use client'

import { usePathname, useSearchParams } from 'next/navigation'

const ClientComponent({ children, href }) {
  const pathname = usePathname()
  const searchParams = useSearchParams()
  const search = searchParams.get('search')

  return (
    &amp;lt;div&amp;gt;Next.js usePathname and useSearchParams example&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;{pathname}&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;{search}&amp;lt;/div&amp;gt;
  )
}

export default ClientComponent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;để điều hướng thì có thể dùng useRouter&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use client'

import { useRouter } from 'next/navigation'

const ClientComponent({ children }) {
  const router = useRouter()

  const handleClick = () =&amp;gt; {
    router.push('someUrl')
  }

  return (
    &amp;lt;div onClick={handleClick}&amp;gt;Click me&amp;lt;/div&amp;gt;
  )
}

export default ClientComponent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How To Read URL Params in a Page File?
&lt;/h2&gt;

&lt;p&gt;Các tham số thường được truyền tự động như là props ở các page component. Bạn có thể đơn giản cung cấp prop cho nó&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const PageComponent({ params, searchParams }) {
  const { slug } = params

  return &amp;lt;div&amp;gt;Next.js URL params in page.tsx file&amp;lt;/div&amp;gt;
}

export default PageComponent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Is it Possible to Render a Client Component in a Server Component?
&lt;/h2&gt;

&lt;p&gt;Hoàn toàn có thể render Client component trong Server component. Tất cả Props truyền từ Client component phải được xử lí được.Thay vào đó dữ liệu mà không thể xử lí được từ bên trong Client component&lt;/p&gt;

&lt;h2&gt;
  
  
  How To Read URL Params in a Server Component?
&lt;/h2&gt;

&lt;p&gt;Trong Server Component, không phải là Page Component, bạn có thể lấy URL params bằng cách truyền dới dạng props. &lt;/p&gt;

&lt;p&gt;Quan trọng là phải nhớ rằng Server Component không phải là thành phần page file component và không được làm mới trong quá trình điều hướng. Vì lí do đó phải cần thận khi sử dụng thông tin từ URL ở Server Component vì các thông só URL sẽ outdated khi điều hướng&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Doesn't searchParams Exist in Next.js Layout Files?
&lt;/h2&gt;

&lt;p&gt;SearchParams chỉ có sẵn trong các Page Files. Page Files sẽ luôn re-render khi mà người dùng điều hướng giữa 2 trang. Vì component re-renders khi url thay đổi, chúng ta có thể biết chắc rằng URL Params được truyền đã được cập nhật.&lt;/p&gt;

&lt;p&gt;Mục đích của Layout Component là tránh render không cần thiết và chứa các thành phần static của giao điện người dùng không được cập nhật khi mà người dùng điều hướng giữa các trang. Do đó thành phần Layout Component chỉ re-render khi người dùng điều hướng đến một thành phần khác của màn hình nơi nó không hiển thị. Ở trong code thì nó có nghĩa là điều hướng giữa 2 trang không chia sẻ chung Layout File&lt;/p&gt;

&lt;p&gt;Thực tế điều này có nghĩa là URl sẽ thay đổi thường xuyên hơn so với Layout File Renders, và nếu chúng ta đọc các thông số URL trong Layout Component thì compoennt sẽ không biết khi nào thông số url được cập nhật. Nhớ rằng Layout File là server component và được renđẻ thành HTML khi nạp lần đầu tiên và sau đó lưu trong bộ nhớ cache trên client nên nó sẽ không bao giờ phải re-render lại&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Top 5 Custom Hook For React</title>
      <dc:creator>Việt Anh Trần Hữu</dc:creator>
      <pubDate>Fri, 31 Jan 2025 12:13:26 +0000</pubDate>
      <link>https://dev.to/va2212/top-5-custom-hook-for-react-2di2</link>
      <guid>https://dev.to/va2212/top-5-custom-hook-for-react-2di2</guid>
      <description>&lt;p&gt;Chào mọi người lại là Slao đây, &lt;br&gt;
Sau đây sẽ là top 5 Custom Hook thuận tiện và mới lạ để mọi người có thể sử dụng &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;useMediaQuery&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;useMediaQuery lắng nghe các truy vấn media, cho phép bạn áp dụng các kiểu hoặc hành vi cụ thể dựa trên kích thước thiết bị&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useEffect, useState } from 'react';

function useMediaQuery(query) {
  const [matches, setMatches] = useState(false);

  useEffect(() =&amp;gt; {
    const mediaQuery = window.matchMedia(query);
    setMatches(mediaQuery.matches);

    const handler = event =&amp;gt; setMatches(event.matches);
    mediaQuery.addEventListener('change', handler);

    return () =&amp;gt; mediaQuery.removeEventListener('change', handler);
  }, [query]);

  return matches;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cách dùng&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const isLargeScreen = useMediaQuery('(min-width: 1024px)');

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;useWebSocket&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;useWebSocket hook kết nối ứng dụng của bạn với WebSocket server, dễ dàng gửi và nhận real-time dữ liệu. Nó xử lí các kết nối lại, message buffering, và event-base handling, làm cho dễ dàng cập nhập thời gian thực&lt;/p&gt;

&lt;p&gt;Ví dụ này trình bày một hook WebSocket có thể tái sử dụng với các tính năng quản lý kết nối, xử lý sự kiện và dọn dẹp gọn gàng.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect, useRef, useCallback } from 'react';

function useWebSocket(url, options = {}) {
  const { reconnect = true, reconnectInterval = 5000, onOpen, onMessage, onError, onClose } = options;
  const [isConnected, setIsConnected] = useState(false);
  const [lastMessage, setLastMessage] = useState(null);
  const websocketRef = useRef(null);
  const reconnectTimeout = useRef(null);

  const connect = useCallback(() =&amp;gt; {
    websocketRef.current = new WebSocket(url);

    websocketRef.current.onopen = (event) =&amp;gt; {
      setIsConnected(true);
      onOpen &amp;amp;&amp;amp; onOpen(event);
    };

    websocketRef.current.onmessage = (event) =&amp;gt; {
      setLastMessage(event.data);
      onMessage &amp;amp;&amp;amp; onMessage(event);
    };

    websocketRef.current.onerror = (event) =&amp;gt; {
      onError &amp;amp;&amp;amp; onError(event);
    };

    websocketRef.current.onclose = (event) =&amp;gt; {
      setIsConnected(false);
      onClose &amp;amp;&amp;amp; onClose(event);
      if (reconnect) {
        reconnectTimeout.current = setTimeout(connect, reconnectInterval);
      }
    };
  }, [url, reconnect, reconnectInterval, onOpen, onMessage, onError, onClose]);

  const sendMessage = useCallback((message) =&amp;gt; {
    if (isConnected &amp;amp;&amp;amp; websocketRef.current) {
      websocketRef.current.send(message);
    }
  }, [isConnected]);

  useEffect(() =&amp;gt; {
    connect();

    return () =&amp;gt; {
      if (websocketRef.current) {
        websocketRef.current.close();
      }
      clearTimeout(reconnectTimeout.current);
    };
  }, [connect]);

  return { isConnected, sendMessage, lastMessage };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Các tính năng của useWebSocket&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reconnection Handling: nếu kết nối đóng, nó sẽ tự động kết nối lại sau 1 khoảng thời gian nhất định&lt;/li&gt;
&lt;li&gt;Event Handling: chấp nhận các thuộc tính gọi lại onOpen, onMessage, onError, and onClose events để xử lí khi cần thiết&lt;/li&gt;
&lt;li&gt;Message Sending: cung cấp chúc năng sendMessage cái mà chỉ gửi message khi websocket mở&lt;/li&gt;
&lt;li&gt;Last Message Storage: lưu dữ liệu mới nhất nhận được , chấp nhận các dữ liệu gần nhất mà không cần đăng kí.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cách dùng&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function ChatApp() {
  const { isConnected, sendMessage, lastMessage } = useWebSocket('ws://localhost:4000/chat', {
    reconnect: true,
    reconnectInterval: 3000,
    onOpen: () =&amp;gt; console.log('Connected to WebSocket'),
    onMessage: (event) =&amp;gt; console.log('New message received:', event.data),
    onClose: () =&amp;gt; console.log('Disconnected from WebSocket'),
  });

  const [inputValue, setInputValue] = useState('');

  const handleSend = () =&amp;gt; {
    sendMessage(inputValue);
    setInputValue('');
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h3&amp;gt;WebSocket Chat&amp;lt;/h3&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;p&amp;gt;{isConnected ? 'Connected' : 'Disconnected'}&amp;lt;/p&amp;gt;
        &amp;lt;input
          type="text"
          value={inputValue}
          onChange={(e) =&amp;gt; setInputValue(e.target.value)}
          placeholder="Type your message..."
        /&amp;gt;
        &amp;lt;button onClick={handleSend} disabled={!isConnected}&amp;gt;
          Send
        &amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;h4&amp;gt;Last Message:&amp;lt;/h4&amp;gt;
        &amp;lt;p&amp;gt;{lastMessage}&amp;lt;/p&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;useHover&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Phát hiện di chuột qua 1 phần tử để xử lí cho các công cụ, hình ảnh động hoặc bất kì phản hồi UI nào trên trạng thái di chuột&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useRef, useEffect } from 'react';

function useHover() {
  const [hovered, setHovered] = useState(false);
  const ref = useRef(null);

  useEffect(() =&amp;gt; {
    const handleMouseOver = () =&amp;gt; setHovered(true);
    const handleMouseOut = () =&amp;gt; setHovered(false);
    const node = ref.current;
    if (node) {
      node.addEventListener('mouseover', handleMouseOver);
      node.addEventListener('mouseout', handleMouseOut);
    }
    return () =&amp;gt; {
      if (node) {
        node.removeEventListener('mouseover', handleMouseOver);
        node.removeEventListener('mouseout', handleMouseOut);
      }
    };
  }, [ref]);

  return [ref, hovered];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [hoverRef, isHovered] = useHover();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;useDebounce&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ngăn chặn sự kích hoạt nhanh chóng của các sự kiện, đã sử dụng có thể hữu ích cho các trường đầu vào hoặc thanh tìm kiếm&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect } from 'react';

function useDebounce(value, delay) {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() =&amp;gt; {
    const handler = setTimeout(() =&amp;gt; {
      setDebouncedValue(value);
    }, delay);

    return () =&amp;gt; clearTimeout(handler);
  }, [value, delay]);

  return debouncedValue;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const debouncedSearchTerm = useDebounce(searchTerm, 500);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;useInfiniteScroll&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;useInfiniteScroll hook rất hữu ích để tìm nạp dữ liệu khi người dùng scroll xuống. Nó có thể xử líu các state phúc tạp như loading, error handling, pagination...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect, useRef, useCallback } from 'react';

function useInfiniteScroll(fetchData, options = {}) {
  const { threshold = 0.8, hasMore = true } = options;
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const observerRef = useRef();

  const loadMore = useCallback(async () =&amp;gt; {
    if (loading || !hasMore) return;
    setLoading(true);
    setError(null);
    try {
      const newData = await fetchData();
      setData((prevData) =&amp;gt; [...prevData, ...newData]);
    } catch (err) {
      setError(err);
    } finally {
      setLoading(false);
    }
  }, [fetchData, loading, hasMore]);

  useEffect(() =&amp;gt; {
    if (!hasMore) return;

    const observer = new IntersectionObserver(
      (entries) =&amp;gt; {
        if (entries[0].isIntersecting) {
          loadMore();
        }
      },
      { threshold }
    );

    if (observerRef.current) observer.observe(observerRef.current);

    return () =&amp;gt; {
      if (observerRef.current) observer.unobserve(observerRef.current);
    };
  }, [loadMore, hasMore, threshold]);

  return { data, loading, error, observerRef };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function InfiniteScrollList() {
  const fetchMoreData = async () =&amp;gt; {
    const response = await fetch('/api/data'); // Example API
    return response.json();
  };

  const { data, loading, error, observerRef } = useInfiniteScroll(fetchMoreData, {
    threshold: 0.9,
    hasMore: true
  });

  return (
    &amp;lt;div&amp;gt;
      {data.map((item, index) =&amp;gt; (
        &amp;lt;div key={index}&amp;gt;{item}&amp;lt;/div&amp;gt;
      ))}
      &amp;lt;div ref={observerRef} style={{ height: '1px' }} /&amp;gt;
      {loading &amp;amp;&amp;amp; &amp;lt;p&amp;gt;Loading...&amp;lt;/p&amp;gt;}
      {error &amp;amp;&amp;amp; &amp;lt;p&amp;gt;Error loading data...&amp;lt;/p&amp;gt;}
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>How to Use DeepSeek R1 for Free in Visual Studio Code with Cline or Roo Code</title>
      <dc:creator>Việt Anh Trần Hữu</dc:creator>
      <pubDate>Fri, 31 Jan 2025 11:43:07 +0000</pubDate>
      <link>https://dev.to/va2212/how-to-use-deepseek-r1-for-free-in-visual-studio-code-with-cline-or-roo-code-58hh</link>
      <guid>https://dev.to/va2212/how-to-use-deepseek-r1-for-free-in-visual-studio-code-with-cline-or-roo-code-58hh</guid>
      <description>&lt;p&gt;Xin chào mọi người lại là Slao đây&lt;br&gt;
Dạo gần đây DeepSeek đang khuấy đẩo thị trường AI, làm cho các ông lớn phải đau đầu&lt;br&gt;
Chúng ta sẽ đi qua một chút về DeepSeek và cách sử dụng nó nhé&lt;/p&gt;

&lt;p&gt;Nếu bạn đang tìm kiếm  một AI vượt trội trong lý luận và cũng như miễn phí thì DeepSeek R1 là lựa chọn tuyệt vời vì nó là mã nguồn mở cạnh tranh vượt trội với GPT-4, o1-mini, Claude 3.5 ....&lt;/p&gt;

&lt;p&gt;Bài viết này sẽ hướng dẫn bạn tích hợp DeepSeek vào visual studio code tương tự như github copilot&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tại sao DeepSeek R1 lại được nhắc đến nhiều như vậy trong thời gian gần đây?&lt;/li&gt;
&lt;li&gt;Miễn phí và mã nguồn mở: Không giống như nhiều mô hình tính phí rất cao, bạn có thể sử dụng mà không phải trả bất kỳ khoản phí nào. Thậm chí còn có thể trò chuyện tại &lt;a href="https://chat.deepseek.com" rel="noopener noreferrer"&gt;https://chat.deepseek.com&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Hiệu suất: Nó cạnh tranh và vượt trội hơn các mô hình khác trong các tác vụ liên quan đến logic, toán học và thậm chí là tạo mã (đây là phần tôi thích nhất).&lt;/li&gt;
&lt;li&gt;Nhiều phiên bản: Để chạy cục bộ (LLM), có các mô hình có tham số từ 1,5B đến 70B, vì vậy bạn có thể chọn mô hình nào hoạt động tốt nhất trên PC của mình tùy thuộc vào phần cứng của bạn.&lt;/li&gt;
&lt;li&gt;Dễ tích hợp: Bạn có thể kết nối nó với VSCode bằng các tiện ích mở rộng như Cline hoặc Roo Code.&lt;/li&gt;
&lt;li&gt;Không mất phí: Nếu bạn chạy cục bộ, bạn không phải trả tiền cho các mã thông báo hoặc API. Nên sử dụng card đồ họa vì chạy chỉ trên CPU sẽ chậm hơn.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How to Run DeepSeek R1 Locally&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Dươi đây mình sẽ viết tiếng anh lấy từ các trang chính thống nhé :)))&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Using LM Studio&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download and install LM Studio: Just go to the LM Studio website and download the version for your system.&lt;/li&gt;
&lt;li&gt;Download the DeepSeek R1 model: In LM Studio, go to the Discover tab, search for "DeepSeek R1," and select the version most compatible with your system. If you're using a MacBook with Apple processors, keep the MLX option selected next to the search bar (these versions are optimized for Apple hardware). For Windows or Linux, choose the GGUF option.&lt;/li&gt;
&lt;li&gt;Load the model: After downloading, go to Local Models, select DeepSeek R1, and click Load.&lt;/li&gt;
&lt;li&gt;Start the local server: In the Developer tab, enable Start Server. It will start running the model at &lt;a href="http://localhost:1234" rel="noopener noreferrer"&gt;http://localhost:1234&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Proceed to step 4 Integrating with VSCode!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Using Ollama&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Ollama: Download it from the Ollama website and install it.&lt;/li&gt;
&lt;li&gt;Download the model: In the terminal, run*:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   ollama pull deepseek-r1  

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;*This is the main model; if you want smaller models, go to &lt;a href="https://ollama.com/library/deepseek-r1" rel="noopener noreferrer"&gt;https://ollama.com/library/deepseek-r1&lt;/a&gt; and see which command to run in the terminal.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start the server: In the terminal, execute:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   ollama serve  

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command will start running the model at &lt;a href="http://localhost:11434" rel="noopener noreferrer"&gt;http://localhost:11434&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Proceed to step 4 Integrating with VSCode!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Using Jan&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download and install Jan: Choose the version for your system on the Jan website.&lt;/li&gt;
&lt;li&gt;Download the model: I couldn't find DeepSeek R1 directly in Jan. So, I went to the Hugging Face website and manually searched for "unsloth gguf deepseek r1." I found the desired version, clicked the "Use this model" button, and selected Jan as the option. The model automatically opened in Jan, and I then downloaded it.&lt;/li&gt;
&lt;li&gt;Load the model: After downloading, select the model and click Load.&lt;/li&gt;
&lt;li&gt;Start the server: Jan automatically starts the server, usually at &lt;a href="http://localhost:1337" rel="noopener noreferrer"&gt;http://localhost:1337&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Proceed to step 4 Integrating with VSCode!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Integrating with VSCode&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install the extension: In VSCode, open the Extensions tab and install Cline or Roo Code.&lt;/li&gt;
&lt;li&gt;Configure the extension for Jan or LM Studio: The configuration for both Cline and Roo Code is practically identical. Follow the steps below:&lt;/li&gt;
&lt;li&gt;Click on the extension and access "Settings".&lt;/li&gt;
&lt;li&gt;In API Provider, select "LM Studio".&lt;/li&gt;
&lt;li&gt;In the Base URL field, enter the URL configured in Jan or LM Studio.&lt;/li&gt;
&lt;li&gt;The Model ID field will be automatically filled if you only have one model available. Otherwise, manually select the DeepSeek model you downloaded.&lt;/li&gt;
&lt;li&gt;Finish by clicking "Done".&lt;/li&gt;
&lt;li&gt;Configure the extension for Ollama:&lt;/li&gt;
&lt;li&gt;Click on the extension and access "Settings".&lt;/li&gt;
&lt;li&gt;In API Provider, select "Ollama".&lt;/li&gt;
&lt;li&gt;In the Base URL field, enter the URL configured in Ollama.&lt;/li&gt;
&lt;li&gt;The Model ID field will be automatically filled if you only have one model available. Otherwise, manually select the DeepSeek model you downloaded.&lt;/li&gt;
&lt;li&gt;Finish by clicking "Done".&lt;/li&gt;
&lt;li&gt;Integration complete, now just enjoy the functionalities of Cline or Roo Code.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
