Vấn đề Build Production
Mục tiêu bài học
- Hiểu root cause của production bug
- Nắm debug process để identify issue
- Biết tại sao chỉ xảy ra với MediaPipe
- Học cách so sánh dev vs production
Triệu chứng
Error Message
Uncaught TypeError: FaceMesh is not a constructor
at MediaPipeFaceMeshWrapper.ts:45
at setup (EkycSettingEnhanced.vue:123)Khi nào xảy ra?
- ✅ Chế độ Development: Hoạt động bình thường
- ❌ Build Production: Lỗi ngay khi component mount
- ❌ Preview build production: Lỗi tương tự
Stack Trace
javascript
// Production build error
Uncaught TypeError: FaceMesh is not a constructor
at new MediaPipeFaceMeshWrapper (MediaPipeFaceMeshWrapper.ts:45:15)
at setup (EkycSettingEnhanced.vue:123:25)
at callWithErrorHandling (runtime-core.esm-bundler.js:157:24)Root Cause Analysis
Vấn đề: ES Module vs CommonJS
MediaPipe FaceMesh được build dưới dạng ES Module, nhưng Vite production build có thể bundle nó thành CommonJS hoặc IIFE, gây ra xung đột.
Code gây lỗi
typescript
// MediaPipeFaceMeshWrapper.ts
import { FaceMesh } from "@mediapipe/face_mesh";
export class MediaPipeFaceMeshWrapper {
private faceMesh: FaceMesh;
constructor() {
// ❌ Production: FaceMesh is undefined hoặc không phải constructor
this.faceMesh = new FaceMesh({
locateFile: (file) => {
return `https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/${file}`;
},
});
}
}Tại sao chỉ xảy ra với MediaPipe?
- Phụ thuộc WASM: MediaPipe sử dụng WebAssembly, cần xử lý đặc biệt
- Import động: MediaPipe tải file từ CDN tại thời gian chạy
- Cấu trúc ES Module: MediaPipe export default, nhưng Vite có thể chuyển đổi sai
- Tối ưu hóa build: Vite production build tối ưu quá mức, làm hỏng cấu trúc MediaPipe
So sánh Dev vs Production
Development Mode
typescript
// Vite dev server
import { FaceMesh } from "@mediapipe/face_mesh";
// ✅ FaceMesh is a class constructor
console.log(typeof FaceMesh); // "function"
console.log(FaceMesh.prototype); // Has methodsProduction Build
typescript
// Vite production build
// After bundling/optimization
const FaceMesh = /* some transformed code */;
// ❌ FaceMesh might be:
// - undefined
// - An object instead of constructor
// - A function but not a constructor
console.log(typeof FaceMesh); // "undefined" or "object"Debug Process
Step 1: Check Import
typescript
import { FaceMesh } from "@mediapipe/face_mesh";
console.log("FaceMesh:", FaceMesh);
console.log("Type:", typeof FaceMesh);
console.log("Is constructor?", typeof FaceMesh === "function");Step 2: Check Build Output
bash
# Build production
npm run build
# Check dist folder
ls -la dist/assets/
# Look for MediaPipe bundle
# Check if it's properly includedStep 3: Check Browser Console
javascript
// In browser console (production build)
import("@mediapipe/face_mesh").then((module) => {
console.log("Module:", module);
console.log("FaceMesh:", module.FaceMesh);
console.log("Default:", module.default);
});Bước 4: Kiểm tra tab Network
- ✅ Kiểm tra xem file WASM có được tải không
- ✅ Kiểm tra xem MediaPipe JS có được tải không
- ❌ Kiểm tra lỗi 404 trên tài sản MediaPipe
Common Causes
1. Vite Build Optimization
Vite production build có thể:
- Tree-shake các export của MediaPipe
- Chuyển đổi ES modules không đúng
- Bundle MediaPipe thành định dạng sai
2. Rollup Plugin Issues
Vite dùng Rollup nội bộ, và Rollup có thể:
- Làm rối tên class
- Chuyển đổi default exports không đúng
- Làm hỏng phụ thuộc WASM
3. Manual Chunks Configuration
Nếu có build.rollupOptions.output.manualChunks:
- MediaPipe có thể bị bundle vào chunk sai
- Thứ tự tải chunk có thể sai
4. External Dependencies
Nếu MediaPipe được đánh dấu là external:
- Runtime sẽ không tìm thấy
- Tải từ CDN có thể thất bại
Verification Steps
Test Development
bash
npm run dev
# ✅ Should work fineTest Production Build
bash
npm run build
npm run preview
# ❌ Should fail with "FaceMesh is not a constructor"Check Bundle Size
bash
# MediaPipe should be ~7MB
# If much smaller → might be tree-shaken incorrectlyImpact
Trải nghiệm người dùng
- ❌ eKYC không thể khởi động
- ❌ Phát hiện liveness khuôn mặt không hoạt động
- ❌ Người dùng không thể hoàn tất xác thực
Tác động kinh doanh
- ❌ Chặn đăng ký/xác thực người dùng
- ❌ Lỗi ưu tiên cao
- ❌ Cần sửa ngay lập tức
Các bước tiếp theo
Sau khi xác định nguyên nhân gốc rễ, cần triển khai giải pháp:
→ Giải pháp Workaround: Vite Plugin
Tổng kết
Nguyên nhân gốc rễ: Vite production build chuyển đổi MediaPipe ES Module không đúng, làm FaceMesh không còn là constructor.
Điểm chính:
- ✅ Chế độ dev hoạt động (không tối ưu hóa)
- ❌ Production thất bại (có tối ưu hóa)
- ⚠️ Vấn đề đặc thù MediaPipe (WASM + ES Module)
- 🔍 Debug bằng cách kiểm tra import và đầu ra build
Giải pháp: Cần plugin Vite tùy chỉnh để xử lý MediaPipe đúng cách.