Xin chào độc giả của 2coffee.dev, 4 tháng trôi qua nhanh như một cơ gió, lần này tôi quay trở lại với một bài viết mới. Dạo này các bạn thế nào? Thay đổi và thích ứng ra sao trong thời đại AI lên ngôi, tự động hoá hầu hết mọi thứ trong công việc? Thi thoảng vài người bạn lại hỏi rằng dạo này có viết bài nữa không? Có dùng AI viết bài không? Hmm... chắc chắn là không rồi. Tại sao phải dùng AI viết bài trong khi ai cũng có thể dùng nó để tạo ra hàng loạt bài viết theo ý thích của họ? Ý tôi là nếu họ muốn, họ có thể dùng AI để tạo ra bài viết và đọc chúng. Nhưng nếu đôi khi cảm thấy cần một điều gì đó mới mẻ thì hãy quay lại đây vì tất cả nội dung ở đây đều do chính tôi tạo ra với hàng nhiều giờ suy ngẫm.
À! Riêng tôi vừa có điều mới là thay đổi môi trường làm việc, có phần bận rộn hơn nên cũng đang dần thay đổi thói quen để thích ứng. Một tháng nay tôi đã dậy sớm đi bộ, có hôm còn tranh thủ ngồi làm việc rồi mới đi làm. Dậy sớm khiến tôi cảm thấy một ngày như dài hơn, còn mình thì như sống chậm lại hơn, có thêm thời gian để làm nhiều việc khác.
Như có chia sẻ cách đây vài tuần, tôi lại vừa đập đi xây lại blog một lần nữa. Chuyện này nghe nhiều đến mức có thể bạn đọc thấy nhàm chán. Nhưng ít ai biết rằng để quyết định làm lại một thứ gì đó quả thật không dễ dàng, vì chẳng ai thích từ bỏ một thứ đang ổn định để sang làm một cái mới mà còn chưa đánh giá hết độ rủi ro. Như bộ công nghệ đang áp dụng vào trang blog bạn đang thấy đây chưa từng sử dụng chúng lần nào, chưa biết cách triển khai như nào, có thể gặp vấn đề gì hay không? Đáng lẽ tôi không mạo hiểm đến thế đâu, nhưng "thời thế tạo anh hùng", trí tuệ nhân tạo - AI Agents là trợ thủ đắc lực giúp hoàn thành công việc này.
Trong thời buổi ai cũng có thể viết mã, ít ai tự tin nói rằng bản thân không cần đến sự trợ giúp của trí tuệ nhân tạo. Và có đi chăng nữa, thì có thể họ đang bỏ lỡ cơ hội mở ra con đường học tập mới. Hãy tưởng tượng AI như là một cuốn bách khoa toàn thư, chứa kho tàng kiến thức khổng lồ nhưng rời rạc. Việc khai thác và sử dụng thông tin trong đó hoàn toàn phụ thuộc vào người dùng. Nếu biết cách tra cứu bạn sẽ nhìn thấy con đường học tập sáng lạn phía trước.
Việc xây dựng lại blog một lần nữa không phải là quyết định vội vàng mà phải đắn đo rất nhiều. Nhân dịp này tôi kể lại cho bạn đọc tường tận lý do đằng sau. Qua đó chỉ ra một vài điểm thú vị mà bộ công nghệ mới này mang lại, hy vọng rằng nó giúp ích được cho các bạn.
Deno ngày càng hoàn thiện, tăng tính ổn định và thêm nhiều tính năng mới. Deno là một sản phẩm ứng dụng Rust mà gây được nhiều thiện cảm trong giới công nghệ. Deno Fresh là framework tôi sử dụng để tạo ra trang blog. Nó đơn giản, dễ tiếp cận, có những thứ cần như đã nói trong bài viết Đập đi xây lại - Tạo ra một trang web ít JavaScript nhất có thể, điều chỉnh mã JS chỉ được trả về ở một vài nơi trong trang web. Hạn chế mã thừa, tiết kiệm tài nguyên và tăng tốc xử lý.
Deno Deploy là nền tảng để triển khai ứng dụng viết bằng Deno hoặc Deno Fresh, như nhiều nền tảng khác, nó có gói miễn phí với mức dung lượng hào phóng. Tại thời điểm đó Deno Deploy cho 1 triệu truy vấn hàng tháng cùng với 100GB băng thông, quá đủ để vận hành trang blog cá nhân. Đủ gạo đủ lửa, còn gì tuyệt vời hơn sử dụng mọi thứ trong hệ sinh thái của Deno?
Hai tháng trước Deno Deploy thông báo chuẩn bị "khai tử" nền tảng này (họ gọi là Deno Deploy Classic) để chuẩn bị tung ra phiên bản mới, tập trung vào cải thiện tính năng và giao diện điều khiển. Tôi háo hức chờ đợi phiên bản mới nhưng trong tâm trạng lo lắng. Háo hức vì điều này chứng tỏ đội ngũ phát triển vẫn rất quan tâm đến sản phẩm, đầu tư công sức thì biết đâu nó còn tốt hơn bản cũ. Lo lắng vì không biết việc chuyển sang có gặp nhiều khó khăn, có tương thích ngược và đặc biệt là chuyển sang có dễ hay không.
Blog của tôi có cách tiếp cận khá độc đáo. Trước đây sử dụng Turso để làm cơ sở dữ liệu, nhưng một ngày đẹp trời Turso sắp đạt đến giới hạn miễn phí nên buộc tôi phải chuyển dữ liệu thành các tệp json rồi thêm logic đọc dữ liệu ra từ đó. Lúc này lại phát sinh vấn đề dữ liệu trong chuyên mục Threads được đăng tải hàng ngày nên cứ mỗi bài đăng phải tạo lại json rồi đẩy lên máy chủ. Dần dần cải tiến bằng cách thêm dữ liệu vào KV (một dạng cơ sở dữ liệu dạng key - value như Redis) để làm dữ liệu đệm mà không cần triển khai lại. Việc sắp khai tử Deno Deploy Classic đồng thời ngăn chặn luôn các triển khai mới. Tức là tôi không thể tiếp tục cách triển khai lâu nay đang sử dụng bởi vì nền tảng không chấp nhận triển khai mới nào nữa. Nếu muốn phải chuyển sang nền tảng Deploy mới.
Chỉ trong vòng vài ngày, tôi chuyển hoàn toàn ứng dụng từ hệ thống cũ sang hệ thống mới. Nó hoạt động mượt mà, còn tôi lấy làm vui sướng. Nhưng chỉ 1 ngày sau, khi truy cập vào xem bảng điều khiển của quản trị viên, ô chỉ báo "CPU Limits" chạm ngưỡng hơn 30%. Lúc đó không tin vào mắt mình, sau vài ba lần tải lại trang thì đó đúng là sự thật. Chỉ số này thể hiện thời gian ứng dụng sử dụng CPU để xử lý việc kết xuất trang web vì nó hoạt động theo kiểu Server Side Render. Hàng tháng nền tảng cho 15 giờ sử dụng miễn phí, nếu hết thì phải trả tiền hoặc chấp nhận trang web không thể truy cập.
Cuối cùng tôi buộc phải trỏ lại tên miền trở lại hệ thống cũ, chấp nhận chỉ đọc (read-only) để người dùng có thể truy cập. Còn mình phải tìm cách xử lý vấn đề, hoặc tìm cách tiếp cận mới mà không bị phụ thuộc vào nền tảng của Deno.
Nếu bạn đọc còn nhớ trước đây tôi đã nhắc đến sql.js-httpvfs - là thư viện truy vấn dữ liệu SQLite dựa trên HTTP-Range-request. Cách hoạt động của thư viện này rất thú vị, dựa vào kích thước trang (page size) của cơ sở dữ liệu để đọc chính xác vùng chứa dữ liệu. SQLite tổ chức dữ liệu dựa trên các trang cho nên khi truy vấn nó hoàn toàn biết dữ liệu nằm ở đâu mà không cần tải về toàn bộ kích thước của cơ sở dữ liệu. Tức là chỉ với một tệp lưu trữ trên máy chủ có hỗ trợ HTTP-Range-request, khi truy vấn SQL, nó biết chính xác dữ liệu nằm ở đâu rồi chỉ định đúng điểm đầu và điểm cuối để lấy dữ liệu về, đó là lý do tại sao máy chủ cần phải hỗ trợ HTTP-Range.
Từ khi tình cờ biết đến thư viện qua một bài viết, tôi đã dành thời gian tìm hiểu cách hoạt động, thử áp dụng vào dự án đơn giản. Nó hoạt động đúng như mong đợi. Thật tuyệt diệu! Từ đó tôi nung nấu ý định một ngày nào đó tạo ra trang web "động nhưng lại tĩnh". Tức là chỉ cần đóng gói dữ liệu vào một tệp SQLite, đẩy lên một máy chủ lưu trữ, rồi áp dụng các truy vấn SQL như bình thường. Cách này có lợi thế là giúp tạo truy vấn, lấy dữ liệu thoải mái hơn so với việc "build" dữ liệu cứng ra thành các tệp HTML. Sẽ có một vài nơi nào đó dữ liệu cần biến đổi liên tục như bài viết liên quan, tránh chôn chặt dữ liệu vào một trang khiến nó trở nên nhàm chán. Lúc đó sql.js-httpvfs phát huy tối đa năng lực không phụ thuộc vào bất kỳ dịch vụ SQL bên thứ ba nào cả.
Cùng với 11ty, tôi thử nghiệm tính khả thi của "Một trang web động nhưng lại tĩnh" cho quá trình đập đi xây lại.
Nhắc đến 11ty chắc là nhiều người biết, công cụ tạo trang web đơn tĩnh đơn giản, rất nhiều người đang sử dụng nó để tạo ra các trang HTML tĩnh từ một kho dữ liệu động. Nếu bạn đã làm việc với Next.js, Nuxt.js... thì đã nghe đến khái niệm Static Site Generator (SSG). Bạn có một kho dữ liệu, bạn tạo ra một bộ khung cho các trang web, thông qua quá trình "build" nó tạo ra tất cả các trang HTML tĩnh từ kho dữ liệu. Chỉ cần tải toàn bộ lên máy chủ hỗ trợ HTML, không cần phải có server xử lý kết xuất (render) cho mỗi lần truy cập.
Áp dụng 11ty vào dự án này không có gì để nói vì nó hoàn toàn phù hợp. Việc tạo ra các tệp HTML tĩnh giúp tăng tốc độ tải trang, mở rộng khả năng bảo trì vì có rất nhiều nơi lưu trữ không tốn phí. Điều còn băn khoăn là chưa có kinh nghiệm làm việc với 11ty nên chưa biết cách tổ chức thư mục cũng như thực hành tốt nhất (best practices). Nhưng không sao, cái gì khó đã có các mô hình ngôn ngữ lớn lo. Cách đây không lâu Anthropic công bố bài viết nói về mô hình Claude Opus 4.6 tự viết lại trình biên dịch C, biên dịch thành công nhân (kernel) Linux 6.9. Mới đây nhất là sự kiện Anthropic mua lại Bun, sau đó vài hôm khởi động chiến dịch viết lại Bun bằng Rust... Thì việc chuyển từ Deno Fresh sang 11ty chắc chắn trong tầm tay.
Nói thế chứ tôi đã phải lên kế hoạch rất kỹ cho việc chuyển đổi này. Đó không chỉ đơn giản là ra lệnh cho AI Agents: "Này! Hãy giúp tôi convert hoàn toàn dự án này từ Deno Fresh sang 11ty kết hợp với sql.js-httpvfs"!
Đầu tiên bạn phải nắm rất rõ cấu trúc dự án cũ của mình, biết nó những trang nào, giao diện và logic xử lý đặc thù. Sau đó hãy lên kế hoạch chia thành các giai đoạn rõ ràng, từng bước một để hướng dẫn AI lập kế hoạch chi tiết trước khi bắt đầu viết mã.
Tốt nhất hãy đi từ tính năng cốt lõi nhất để kiểm tra tính khả thi, cũng như khi đã xây dựng xong thì việc mở rộng không còn nhiều khó khăn. Tính năng cốt lõi mà tôi xác định trong dự án lần này là khả năng tạo dữ liệu ra thành các trang tĩnh. Tôi có một tệp sqlite chứa tất cả dữ liệu bài viết, có các mẫu trang chi tiết bài viết, sau đó bằng một lệnh 11ty giúp tạo ra các trang HTML. Một câu lệnh gì đó giống như là:
Dĩ nhiên trước đó AI đã tạo ra cấu trúc cơ bản của dự án 11ty. Sau đó nó bắt đầu quá trình chuyển đổi giao diện của trang chi tiết bài viết và đọc cách truy vấn dữ liệu từ sqlite để làm dữ liệu đầu vào cho quá trình tạo trang tĩnh.
Sau nhiều lần hiệu chỉnh, cuối cùng nó cũng chạy thành công. Sau đó tôi tiếp tục yêu cầu nó hoàn thành các trang còn lại.
Sau khi tạo xong các trang tĩnh, lúc này đến với phần khó hơn là ứng dụng sql.js-httpvfs để truy vấn dữ liệu động, hãy tưởng tượng 11ty chỉ giúp tạo ra các trang tĩnh, vậy dữ liệu khi người dùng cuộn xuống cuối trang mà nó tự động tải thêm thì lấy ở đâu? Ban đầu tôi nghĩ các phần cần truy vấn động là phần tải thêm bài viết ngoài trang chủ, bình luận của bài viết, mục bài viết liên quan và một số chỗ. Sẵn tệp sqlite để làm dữ liệu đầu vào ở dưới máy (dữ liệu này được xuất từ Turso - cơ sở dữ liệu SQLite dùng cho blog lâu nay), mặc dù dung lượng lớn (khoảng 16MB do chứa toàn bộ các bảng), ở giai đoạn này mục đích là tăng tốc khả năng tích hợp nên chưa cần tối ưu, tôi sử dụng Preact.js để xử lý phần tương tác phía máy khách. Tức là phần dữ liệu động được xử lý tải xuống bằng JavaScript. Cùng với thư viện sql.js-httpvfs để truy vấn SQL từ một tệp sqlite lưu trữ trên máy chủ, ở đây chính là tệp sqlite kia.
Sau nhiều lần thử nghiệm, cuối cùng mọi thứ cũng hoạt động ăn khớp với nhau. Khi tất cả tính năng chính hoạt động mới chắc chắn dự án này khả thi. Sau đó tôi mới bắt tay vào cải thiện cấu trúc cũng như tối ưu hoá quy trình. Tổ chức mã gọn gàng và hiệu quả hơn, có khả năng bảo trì để phát triển thêm tính năng mới trong tương lai.
Sau 2 tuần làm việc không ngừng nghỉ, thử - sai - sửa - thử, kết quả như bạn thấy ở đây, trang web đã chuyển đổi hoàn toàn từ Deno Fresh sang 11ty kết hợp với sql.js-httpvfs và Preact.js. Vẫn còn một số lỗi và tính năng chưa được hoàn thiện nhưng nhìn chung mọi thứ hoạt động như mong đợi, còn tôi có một nơi để tiếp tục viết, tiếp tục chia sẻ thông tin đến với bạn đọc.
Sau hai tuần làm việc không ngừng nghỉ, tôi đã hoàn tất việc chuyển đổi trang blog từ Deno Fresh sang bộ công nghệ mới: 11ty làm nền tảng tạo trang tĩnh, sql.js-httpvfs để truy vấn dữ liệu SQLite trực tiếp trên trình duyệt, và Preact.js xử lý các tương tác phía client. Đây là lần đập đi xây lại thú vị nhất mà tôi từng thực hiện, không chỉ vì bộ công nghệ mới mà còn vì cách tôi đã chủ động làm chủ quá trình với sự hỗ trợ của AI.
Cuối cùng thì việc biến ý tưởng "một trang web động nhưng lại tĩnh" trở thành hiện thực. Chỉ với một tệp SQLite lưu trữ trên GitHub Pages, kết hợp với sql.js-httpvfs và Preact.js, tôi có thể tạo ra những truy vấn dữ liệu động mà không cần bất kỳ dịch vụ cơ sở dữ liệu đám mây nào. Cách tiếp cận này vừa tiết kiệm chi phí vừa giúp blog hoạt động nhanh hơn.
Nếu bạn muốn tìm hiểu kỹ hơn về công nghệ và cách triển khai, hãy để lại bình luận xuống phía dưới bài viết nhé. Còn bạn, bạn đã từng thử nghiệm hướng tiếp cận mới lạ nào cho dự án của mình chưa?