Bỏ qua tới nội dung

Hướng dẫn

Giám sát ứng dụng vibe coding: thứ gì hỏng sau khi publish

Mình chạy năm bản build hỏng của một app React. Bản nào cũng ra trang trắng và vẫn trả HTTP 200. Công cụ theo dõi lỗi báo được ba bản, một bản chỉ báo được sau khi dời đúng một dòng import.

Andrew Babo9 phút đọc

Chia sẻ
Trong bài này
Giám sát ứng dụng vibe coding: thứ gì hỏng sau khi publish

App vibe coding thường hỏng ở chỗ công cụ tạo ra nó không nhìn thấy: trên trình duyệt của người dùng, sau khi bạn đã publish. Cần theo dõi ba thứ. Lỗi trên trình duyệt, với công cụ theo dõi lỗi được khởi động trước mọi code của app; các file script của trang có tải được không; và lỗi từ server cùng các job chạy định kỳ.

Mình thử điều này ngày 26/10/2026 với một app bán hàng nhỏ. Mình tạo năm bản build hỏng, bản nào mở ra cũng là trang trắng. Và bản nào cũng trả HTTP 200, nên một uptime check chỉ hỏi "trang có lên không?" sẽ thấy site khoẻ suốt từ đầu đến cuối.

Bản preview không phải là production#

Trong lúc bạn làm, app chạy trong bản preview của công cụ, và công cụ đọc được lỗi ở đó. Hướng dẫn debug của Lovable nói rõ: “Lovable reads your app's console logs itself”, rồi thêm rằng dán đúng thông báo lỗi vẫn có ích “when the error happens outside the preview, for example on your published site” (hướng dẫn debug của Lovable). Tức là: Lovable tự đọc console trong preview, còn lỗi trên site đã publish thì bạn phải mang về cho nó.

Sau khi publish, lỗi xảy ra trên máy của người khác. Họ dùng trình duyệt khác, để tab mở qua lần publish tiếp theo của bạn, và chạy app với đúng cấu hình mà bản build đã publish đang có. Không ai mở console ở đó cả.

Các công cụ cũng đang thêm phần kiểm tra riêng. Project monitoring của Lovable, đang beta trên các gói trả phí, xem lại code và “recent errors from visitors” theo lịch, mặc định mỗi ngày một lần, rồi gửi email cho chủ project khi có phát hiện quan trọng (tài liệu Project monitoring). Đó là một bản rà soát hằng ngày có ích. Chính trang đó cũng ghi nó “does not replace testing” và có thể bỏ sót. Phần dưới đây là thứ một lần rà soát theo lịch không cho bạn được: báo từng lỗi ngay khi nó xảy ra, và kiểm tra những kiểu hỏng không sinh ra lỗi nào.

Năm bản build hỏng, bản nào cũng 200#

App thử nghiệm là một shop React 19 dạng single-page: trang chủ, trang cài đặt chỉ tải khi cần, và một Supabase client được tạo ngay lúc module nạp, đúng kiểu nhiều app do AI tạo hay làm. Mình build bằng esbuild, chạy trên máy, mở bằng Chromium ba lần cho mỗi trường hợp. Một collector cục bộ ghi lại những gì công cụ theo dõi lỗi gửi đi.

Năm bản build hỏng: người dùng thấy gì và có được báo không
Thí nghiệm 26/10/2026 · app single-page React 19.2.8 · Chromium 141 · cả 3/3 lần mỗi trường hợp
  • Một component lỗi khi render. Không có error boundary nên React gỡ cả trang. Công cụ theo dõi lỗi báo được.
  • Thiếu một giá trị cấu hình trong bản publish. createClient() ném lỗi supabaseUrl is required. trước khi bất cứ thứ gì hiện lên. Có báo được hay không phụ thuộc vào đúng một dòng, nói ở phần sau.
  • Tab cũ đòi một file mà lần publish mới đã xoá. Người dùng bấm sang trang cài đặt, nhưng file code của trang đó không còn. Trang trắng; vẫn báo được.
  • Mất file script chính. HTML trỏ tới một bundle mà server không có. Không có dòng code nào chạy, nên không công cụ theo dõi lỗi nào lên tiếng được.

Chỗ khó chịu nằm ở mã trạng thái. App single-page gửi về cùng một khung HTML nhỏ, dù app bên trong chạy hay chết. Uptime check gọi trang đó, kể cả kiểm tra HTML có chứa một chữ nào đó, sẽ nhận cùng một câu trả lời từ app đang chạy lẫn app đã chết.

Khởi động công cụ theo dõi lỗi trước code của app#

Ở trường hợp thiếu cấu hình, lỗi được báo 3/3 lần khi công cụ theo dõi lỗi khởi động đầu tiên, và 0/3 lần khi nó khởi động muộn hơn vài dòng. Vài dòng đó là vấn đề:

src/main.tsx — bỏ lỡ lỗi lúc khởi động
import { createRoot } from "react-dom/client";import { App } from "./App"; // nạp supabase.ts, file này ném lỗi ở đâyimport { init } from "./tracker";init({ dsn: "…" }); // không bao giờ chạycreateRoot(document.getElementById("root")!).render(<App />);

JavaScript chạy mọi import trước phần còn lại của file. MDN viết rất rõ: tác dụng của một import “are produced before the rest of the module's code runs” (MDN). Nên khi một module mà App import ném lỗi lúc đang nạp, dòng init() bên dưới không bao giờ được chạy. Cách sửa là cho công cụ theo dõi lỗi một file riêng và import nó đầu tiên:

src/main.tsx — báo được lỗi lúc khởi động
import "./instrument"; // gọi init(); phải là dòng đầu tiênimport { createRoot } from "react-dom/client";import { App } from "./App";createRoot(document.getElementById("root")!).render(<App />);

Điều này đúng với mọi công cụ theo dõi lỗi trên trình duyệt khởi động bằng một lệnh init. Nó cũng đúng với chính hướng dẫn cài đặt của mình: trước thí nghiệm này, hướng dẫn React và TanStack Start của Belvador đặt init sau các import của app. Mình đã sửa ngay trong ngày.

App chạy TanStack Start, framework mà Lovable dùng cho một số project (trang Logs của Lovable ghi server logs chỉ có “only on TanStack Start projects”), có thêm hai điểm khác. Server render sẵn trang, nên lỗi lúc khởi động trên trình duyệt để lại một trang vẫn hiện nhưng đứng im: trong thí nghiệm, nút "Add to cart" bấm không có tác dụng gì, 3/3 lần. Và router chỉ báo lỗi qua defaultOnCatch ở nơi có error component. Bài debug trang trắng trên Lovable chỉ cách phân biệt các trường hợp này, còn bài prompt cài đặt theo dõi lỗi có đúng thứ tự file cần làm.

Kiểm tra các file của trang có tải được không#

Trường hợp mất bundle cần một kiểu kiểm tra khác, vì không có gì chạy để báo cả. Trang tải về, xin file script chính và nhận 404. Cách duy nhất để thấy là kiểm tra từ bên ngoài: tải trang, rồi tải từng file script và stylesheet mà trang trỏ tới.

check-assets.mjs
// Sau khi publish: tải trang, rồi tải từng script và stylesheet mà trang trỏ tới.const url = process.argv[2];const res = await fetch(url);const html = await res.text();const refs = [...html.matchAll(/<(?:script[^>]+src|link[^>]+href)="([^"]+\.(?:js|css))"/g)]  .map((m) => new URL(m[1], url).href);let bad = res.ok ? 0 : 1;for (const ref of refs) {  const r = await fetch(ref);  console.log(r.status, ref);  if (!r.ok) bad++;}if (refs.length === 0) bad++; // trang không có script nào thì không phải app của bạnprocess.exit(bad ? 1 : 0);

Chạy với server thử nghiệm, script thoát mã 0 cho app đang chạy và mã 1 cho bản mất bundle. Chạy node check-assets.mjs https://app-cua-ban.example ngay sau mỗi lần publish.

Chạy thêm theo lịch thì bắt được cả trường hợp phía bạn không đổi gì. Ngày 27/3/2026, trang trạng thái của Lovable báo “an issue that is causing published projects to display blank pages”, tức các project đã publish hiện trang trắng; publish lại thì hết (trang trạng thái Lovable). Để chạy theo lịch, đặt script vào một cron job hay lịch CI bất kỳ và chỉ gửi heartbeat khi kiểm tra đạt: node check-assets.mjs https://app-cua-ban.example && curl -fsS <heartbeat-url>. Nếu kiểm tra hỏng hoặc ngừng chạy, heartbeat im lặng và monitor sẽ cảnh báo. Cron monitoring của Belvador hoạt động theo cách này, và hướng dẫn heartbeat có các bước cài.

Đừng quên server và job chạy định kỳ#

Server function, edge function và job định kỳ hỏng ở nơi không trình duyệt nào thấy. Các công cụ có hiển thị log, và log đáng đọc. Phần Logs của Lovable có log server, function và database, nhưng “Logs do not stream live”, các khoảng thời gian chọn nhanh chỉ lùi được 5 ngày, và muốn lưu lâu thì tài liệu gợi ý nhờ Lovable “to build logging or analytics into your app itself” (tài liệu Logs của Lovable).

Với lỗi, hãy báo từ server giống như từ trình duyệt: một công cụ theo dõi lỗi hay middleware phía server thấy được từng request thất bại. Với job, một lần chạy bị bỏ lỡ không sinh ra lỗi nào, nên mới cần heartbeat. Bài cron job chạy mãi không xong đã thử xem tín hiệu cuối của một job trông thế nào khi nó bị dừng giữa chừng.

Ba lớp kiểm tra quanh một app đã publish
Mỗi lớp thấy được thứ hai lớp kia không thấy

Nên cài gì, và mỗi lớp bỏ sót gì#

Lớp kiểm traBắt đượcBỏ sótCông sức
Theo dõi lỗi trình duyệt, import đầu tiênLỗi render, lỗi lúc khởi động, file code bị mất sau khi publish, request lỗi mà code của bạn báoBundle không bao giờ tải được; vấn đề không ném lỗiMột file và một dòng import
Kiểm tra file sau khi publish và theo lịchBundle bị mất hoặc cũ, publish hỏng, trang trắng do phía nền tảngMọi thứ xảy ra sau khi script đã tảiMột script và một heartbeat
Lỗi server và heartbeat cho jobServer function lỗi, job lỗi hoặc không chạyVấn đề chỉ có trên trình duyệtMiddleware cộng một heartbeat mỗi job
Rà soát của chính công cụ (ví dụ Project monitoring)Lỗi trong code và lỗi gần đây của người dùng, giải thích ngay trong editorCảnh báo tức thời; nó chạy theo lịchBật một tuỳ chọn

Nếu bạn làm app bằng Lovable hay một công cụ tự sửa code cho bạn, bạn không cần tự viết những thứ này. Bài prompt cài đặt theo dõi lỗi có sẵn prompt và các bước kiểm tra cần yêu cầu, còn hướng dẫn TanStack Start và hướng dẫn React cho thấy các file mà nó phải tạo ra. Thí nghiệm trước của mình về những chỗ lỗi JavaScript lọt ra ngoài nói về các lỗi xảy ra sau lúc khởi động.

Thí nghiệm này không cho thấy điều gì#

Đây là thí nghiệm có kiểm soát trên hai app nhỏ, không phải số liệu sự cố thật. Mình chỉ chạy Chromium, nên Safari và Firefox có thể khác ở chi tiết như nội dung thông báo lỗi. Phần TanStack Start chạy server trên Node chứ không phải Cloudflare Workers; các lỗi được thử đều nằm trên trình duyệt. Một công cụ báo được lỗi chưa có nghĩa là có người biết trang đang hỏng, nên hãy chuyển lỗi mới thành cảnh báo mà bạn sẽ thấy. Toàn bộ cấu hình, script và kết quả nằm trong thư mục bằng chứng của mình, còn trang TanStack Start liệt kê những gì gói của Belvador hỗ trợ.

Andrew Babo

Nhà sáng lập

Trong chủ đề này

Mọi bài viết

Hướng dẫn

Prompt cài theo dõi lỗi cho app Lovable, và cách kiểm tra nó chạy

Prompt cài đặt chỉ tốt bằng thứ tự file của nó. Prompt cũ của mình gọi init muộn vài dòng: trên bản build production nó báo được 0/12 lỗi khởi động và lỗi trang. Thứ tự đã sửa báo được 12/12.

Andrew Babo7 phút đọc

Hướng dẫn

App Lovable bị trang trắng: tìm nguyên nhân trong console

Mở trang đã publish, mở console, tải lại. Trong thí nghiệm, dòng lỗi đỏ đầu tiên đủ để phân biệt năm kiểu trang trắng hoặc trang hỏng, và mỗi kiểu có một cách sửa riêng.

Andrew Babo6 phút đọc

Đọc tiếp trong tài liệu

Xem lỗi production của chính bạn như thế này

Belvador chạy trên máy chủ Hetzner của chính bạn: lỗi, cron, uptime và trace — dữ liệu vẫn là của bạn.