Giải Mã var __filename: string;: "Chứng Minh Nhân Dân" Của File Và Tuyệt Chiêu Trích Xuất Định Dạng Chuẩn Senior
Chào anh em Viblo! 👋
Để khép lại series mổ xẻ các tham số "quyền lực" được Node.js tiêm (inject) ngầm vào bên trong Module Wrapper Function thời kỳ CommonJS (sau khi chúng ta đã đi qua exports, require, module, và __dirname), hôm nay chúng ta sẽ cùng nhau gặp gỡ mảnh ghép cuối cùng: __filename.
Nếu anh em mở file định nghĩa core của Node.js trong TypeScript (@types/node), biến này được khai báo tối giản hết mức:
declare var __filename: string;
Nếu như __dirname được ví như tấm bản đồ chỉ đường đến cửa nhà, thì __filename chính là số nhà và tên phòng chính xác của bạn trên tấm bản đồ đó. Nhiều bạn nghĩ biến này đơn giản nên thường bỏ qua, nhưng trong thực tế, nó là vũ khí cực mạnh để làm hệ thống Log tập trung, xử lý dynamic import, hoặc trích xuất định dạng file tự động.
Cùng mình bóc tách xem ông thần __filename này có gì thú vị nhé!
1. Bản chất của __filename từ đâu mà có?
Như một quy luật bất biến của CommonJS, trước khi file của bạn được V8 Engine thực thi, Node.js đã nhanh tay bọc toàn bộ code vào một hàm ẩn danh. Biến __filename chính là tham số thứ 4 đứng ngay trước __dirname.
Định nghĩa chính xác: __filename là một chuỗi (string) chứa đường dẫn tuyệt đối bao gồm cả tên file và đuôi mở rộng của file JavaScript hiện tại đang chứa dòng code đó.
Ví dụ, nếu file src/utils/logger.js của bạn nằm ở thư mục /Users/project/src/utils/logger.js, thì giá trị của __filename bên trong file đó sẽ chính xác là chuỗi: /Users/project/src/utils/logger.js.
2. Bản đồ phân biệt: __filename vs __dirname vs process.cwd()
Để anh em có một cái nhìn trực quan nhất và không bao giờ bị loạn giữa 3 khái niệm đường dẫn kinh điển này, hãy cùng nhìn vào sơ đồ phân cấp dưới đây:
Bảng so sánh nhanh:
| Biến toàn cục | Kiểu dữ liệu | Kết quả trả về (Ví dụ) | Bản chất cốt lỏi |
|---|---|---|---|
| process.cwd() | string | /Users/project | Thư mục nơi gõ lệnh chạy |
| __dirname | string | /Users/project/src/utils | Thư mục chứa file hiện tại |
| __filename | string | /Users/project/src/utils/logger.js | Đường dẫn đến thẳng file hiện tại |
3. Các tuyệt chiêu thực chiến với __filename (Kinh nghiệm Senior)
Thay vì chỉ để in ra màn hình chơi, __filename khi kết hợp với module node:path sẽ sinh ra những giải pháp xử lý cực kỳ thông minh:
Tuyệt chiêu 1: Tự động gắn tên File vào Hệ thống Log (Auto-context Logging)
Khi hệ thống của bạn có hàng trăm file service, việc in log ra Terminal mà không biết lỗi này sinh ra từ file nào là một cơn ác mộng. Hãy dùng __filename để tự động hóa việc này.
const path = require('node:path');
function logInfo(message) {
// path.basename sẽ cắt bỏ phần đường dẫn dài, chỉ giữ lại tên file + đuôi
const fileName = path.basename(__filename);
console.log(`[${new Date().toISOString()}] [${fileName}] INFO: ${message}`);
}
logInfo('Kết nối Database thành công!');
// 👉 Kết quả: [2026-06-27T02:59:17Z] [logger.js] INFO: Kết nối Database thành công!
Tuyệt chiêu 2: Trích xuất phần mở rộng (Extension) để chặn mã độc
Giả sử bạn viết một script tự động quét và phân loại file trong hệ thống, hoặc đọc chính tên file hiện tại để quyết định logic chạy:
const path = require('node:path');
const ext = path.extname(__filename);
console.log(ext); // 👉 Kết quả: '.js' (hoặc '.ts' tùy môi trường chạy)
4. Góc nhìn thời đại: Tái tạo __filename trong kỷ nguyên ES Modules (ESM)
Cũng giống như toàn bộ các biến global khác của CommonJS, khi bạn cấu hình dự án chạy theo chuẩn ES Modules (import/export), biến __filename sẽ hoàn toàn bị xóa sổ khỏi bộ nhớ.
Nếu bạn cố tình gọi __filename trong file ESM, hệ thống sẽ ném lỗi ReferenceError: __filename is not defined.
Cách "hồi sinh" filename chuẩn chỉ nhất trong ESM
Để có được một biến chứa đường dẫn file tuyệt đối tương thích với thời đại mới, chúng ta phải đi đường vòng thông qua đối tượng meta dữ liệu import.meta.url kết hợp với thư viện node:url:
import { fileURLToPath } from 'node:url';
import path from 'node:path';
// 1. Biến đổi chuỗi URL (file://...) thành đường dẫn ổ cứng tuyệt đối
const __filename = fileURLToPath(import.meta.url);
// 2. Từ __filename, bạn cũng có thể dễ dàng suy ngược ra __dirname cũ nếu cần
const __dirname = path.dirname(__filename);
console.log(__filename);
// 👉 Kết quả: /Users/project/src/utils/logger.js (Mượt mà như chưa từng có cuộc chia ly!)
Đúc Kết Lại
Khai báo var __filename: string; là mảnh ghép cuối cùng hoàn thiện bức tranh về cơ chế quản lý module độc lập của Node.js. Hiểu sâu về cách nó vận hành giúp bạn viết các script kiểm soát file an toàn, xây dựng hệ thống ghi log thông minh và tự tin chuyển dịch source code cũ lên chuẩn ES Modules hiện đại mà không sợ dính các lỗi runtime bẻ gãy hệ thống.
Hy vọng chuỗi bài viết mổ xẻ file core này đã mang lại cho anh em một nền tảng kiến thức vững chắc để làm chủ mọi ngóc ngách của Node.js/TypeScript. Chúc anh em tối ưu code thành công! Happy Coding! 🚀💻
All rights reserved