Source map trên production với Vite: mỗi cấu hình thực sự đưa gì vào bản build
Mình build cùng một module với ba lựa chọn source map của Vite rồi cho mỗi bản ném một lỗi. Một bản cho stack frame vô dụng; hai bản còn lại đóng gói toàn bộ mã nguồn vào một file.
Andrew Babo4 phút đọc
Trong bài này

Mặc định Vite không tạo source map cho bản build production. Nếu chọn true hoặc hidden, nó ghi thêm một file .map cạnh mỗi bundle, và file đó chứa toàn bộ mã nguồn gốc của bạn. Khác biệt duy nhất là hidden bỏ đi dòng comment trỏ tới file map.
Vì vậy cách an toàn là: tạo map, upload lên công cụ theo dõi lỗi, rồi xoá map trước khi deploy. Mình đã kiểm từng lựa chọn ngày 26/10/2026 với Vite 8.1.5.
Bài thử#
Một module nhỏ tính tổng tiền đơn hàng và ném lỗi khi có món không có giá. Mình build nó ba lần với build.sourcemap là false, true và "hidden", có minify, rồi gọi hàm và đọc frame đầu tiên của stack trace.
function priceOf(item) { if (item.price == null) { throw new Error(`Missing price for ${item.sku}`); } return Math.round(item.price * 100);}Sau đó mình đưa frame đó qua map của từng bản build, đúng cách một công cụ theo dõi lỗi vẫn làm.
Mỗi lựa chọn cho ra gì#

build.sourcemap | File được ghi | Comment trong bundle | Stack frame | Đọc được mã nguồn từ map |
|---|---|---|---|---|
false (mặc định) | app.mjs | không | app.mjs:6:29, không có gì để giải | không có map |
true | app.mjs, app.mjs.map | có | giải ra src/checkout.js:8 | có, toàn bộ |
"hidden" | app.mjs, app.mjs.map | không | giải ra src/checkout.js:8 | có, toàn bộ |
Mặc định khớp với tài liệu của Vite: “Default: false”. Bạn chỉ có frame app.mjs:6:29. Trong một app thật, nơi hàng trăm hàm bị dồn vào vài dòng, con số đó gần như không nói lên điều gì.
Có map thì cùng frame đó giải ra dòng 8 của src/checkout.js, đúng câu lệnh throw trong priceOf. Hai file map giống hệt nhau, và cả hai đều có trường sourcesContent chứa nguyên file gốc, kể cả comment. Chuẩn source map gọi trường này là “an optional list of source content”, tức là không bắt buộc, nhưng Vite vẫn điền vào.

hidden làm gì và không làm gì#
Vite mô tả hidden là hoạt động “like true except that the corresponding sourcemap comments in the bundled files are suppressed”. Nghĩa là giống true, chỉ bỏ comment trỏ tới map. Trình duyệt sẽ không tự tải map, và DevTools không hiện mã nguồn của bạn.
Nhưng file .map vẫn nằm trong thư mục build. Nếu deploy cả thư mục đó, một static host sẽ trả file cho bất kỳ ai gọi app.mjs.map. Tên file cũng dễ đoán, vì tên map chỉ là tên bundle thêm .map. hidden giấu đường dẫn, không giấu file.
Cách thiết lập mình khuyên dùng#
- Tạo map trong CI, dùng
hiddenđể không bundle nào trỏ tới map. - Đánh dấu để bundle và map nhận ra nhau. Một công cụ như
sentry-cli sourcemaps injectghi Debug ID vào mỗi bundle và map của nó. Tài liệu Sentry định nghĩa chúng là “globally unique ids that identify a transformed JavaScript file and its associated source map”, tức một mã duy nhất gắn một file JavaScript đã biến đổi với source map của nó. - Upload map lên công cụ theo dõi lỗi, gắn đúng release mà SDK của bạn báo.
- Xoá các file
.maptrước khi deploy, hoặc cấu hình host không phục vụ chúng. - Ném thử một lỗi trên release mới và kiểm tra frame có hiện đúng tên file của bạn không.
Bước 2 phải chạy trên đúng những file bạn deploy. Nếu đã inject ID rồi lại build lại, ID sẽ không còn khớp và frame vẫn bị minify.
Belvador giúp ở đâu#
Belvador nhận map qua API upload của sentry-cli hoặc một file tarball, lưu chúng trên node của chính bạn và không bao giờ công khai chúng cùng website. Node của bạn ghép mỗi frame với map theo Debug ID. Hướng dẫn source map có các lệnh CI, cách thiết lập token upload và những gì cần kiểm khi frame vẫn bị minify. Hướng dẫn SDK React đặt giá trị release mà lần upload phải khớp, còn trang React cho thấy toàn bộ cách thiết lập.
Đọc tiếp#
Thuộc bài hướng dẫn: Xử lý lỗi JavaScript trong ứng dụng do AI viết: lỗi thoát ra từ đâu
Bài liên quan
Mọi bài viết
Hướng dẫn
Xử lý lỗi JavaScript trong ứng dụng do AI viết: lỗi thoát ra từ đâu
Mình cố tình gây lỗi ở tám chỗ trong một trang React 19 và năm chỗ trong một server Node.js, mỗi chỗ ba lần. Có lỗi làm sập server, có lỗi để lại một nút bấm không phản hồi, có lỗi treo request mãi.
Andrew Babo7 phút đọc

Kỹ thuật
Lỗi loader trong TanStack Start: vì sao stack lúc SSR lại chỉ vào trang HTML
Một route loader ném lỗi lúc render trên server sẽ đến trình duyệt chỉ còn mỗi message. Mình lần theo một lỗi qua ba cách cấu hình và đếm công cụ theo dõi lỗi nhận được gì mỗi lần.
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.