Tại sao __dirname lại biến mất?Nếu gần đây bạn đã chuyển đổi từ require sang import trong dự án Node.js của mình, có thể bạn đã gặp phải một trở ngại. Bạn cố gắng truy cập thư mục hiện tại và Node.js ném ra lỗi ReferenceError. Điều này xảy ra vì ES Modules (ESM) không bao gồm các biến toàn cục như __dirname hoặc __filename theo mặc định.
CommonJS cung cấp các biến này một cách tự động. Tuy nhiên, ESM được thiết kế để độc lập với nền tảng. Vì trình duyệt không có "cấu trúc thư mục" giống như máy chủ, các biến toàn cục này đã bị loại bỏ để giữ cho ESM nhất quán trên các môi trường khác nhau. Nếu bạn đang chạy Node.js 14 trở lên, bạn sẽ cần phải tái cấu trúc các đường dẫn này một cách thủ công.
Giải pháp: Sử dụng import.meta.urlĐể lấy lại các đường dẫn của mình, bạn cần sử dụng import.meta.url. Thuộc tính này cung cấp cho bạn URL đầy đủ của module hiện tại, ví dụ như file:///Users/dev/project/index.js. Sau đó, chúng ta có thể chuyển đổi URL này thành đường dẫn tệp tiêu chuẩn bằng các tiện ích tích hợp sẵn của Node.js.
1. Import các module path và urlBắt đầu bằng việc thêm các công cụ cần thiết để xử lý URL tệp và chuỗi đường dẫn. Thêm các dòng sau vào đầu script của bạn:
import { fileURLToPath } from 'url';
import { dirname } from 'path';
2. Tái tạo các biến toàn cục còn thiếuBạn có thể định nghĩa __filename và __dirname một cách thủ công chỉ với hai dòng mã. Điều này giúp mã ESM của bạn trở nên quen thuộc hơn.
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
3. Tổng hợp lạiDưới đây là cấu hình điển hình khi bạn cần xác định vị trí thư mục config tương đối với script của mình:
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Ví dụ: Nối các đường dẫn cho một tệp cài đặt
const configPath = path.join(__dirname, 'config', 'settings.json');
console.log(`Đường dẫn đích: ${configPath}`);
Kiểm tra giải phápXác minh giải pháp bằng cách tạo một tệp có tên app.mjs (hoặc app.js nếu package.json của bạn có "type": "module"). Dán logic ở trên vào và chạy nó:
node app.mjs
Terminal của bạn bây giờ sẽ in ra đường dẫn tuyệt đối đến tệp và thư mục của bạn. Sẽ không còn lỗi ReferenceError nữa.
Mẹo chuyên nghiệp cho đường dẫn tệp ESM### Đừng chỉ dựa vào process.cwd()Sử dụng process.cwd() như một lối tắt rất dễ gây nhầm lẫn. Hãy cẩn thận: process.cwd() trả về thư mục nơi bạn bắt đầu lệnh terminal, không phải nơi script tọa lạc. Nếu bạn chạy node ./src/app.js từ thư mục gốc, process.cwd() và __dirname sẽ trỏ đến các vị trí khác nhau.
Tải các tệp JSON một cách an toànHầu hết các lập trình viên cần __dirname để đọc các tệp JSON. Mặc dù các phiên bản Node.js hiện đại (v20.10+) hỗ trợ Import Attributes cho JSON, nhưng module fs kết hợp với cách khắc phục __dirname của chúng ta vẫn là phương pháp tương thích nhất cho các phiên bản LTS cũ hơn:
import { readFileSync } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const rawData = readFileSync(path.join(__dirname, 'data.json'), 'utf8');
const data = JSON.parse(rawData);

