본문 바로가기

javascript/nodejs

[nodejs] __filename & __dirname / join & resolve

 때로는 파일 혹은 폴더의 절대 경로가 필요할 때가 있다. nodejs에서는 __filename 및 __dirname을 통해 현재 작업중인 폴더 및 파일의 절대 경로를 알 수 있도록 지원하고 있다.

console.log(`dirname : ${__dirname}`)
console.log(`filename : ${__filename}`)

 앞서 언급한 것처럼 __dirname 및 __filename 은 해당 파일의 현재 위치와 관련된 정보를 반환하므로, 다른 파일에서 특정 파일의 절대 경로를 이용할 수도 있다.

# index.cjs 

const folderDir = require('./fol2/myfile.cjs');
console.log(folderDir.basedir);

# fol2/myfile.cjs


console.log(`dirname : ${__dirname}`)
console.log(`filename : ${__filename}`)

module.exports = {
    basedir : __dirname
};

index.cjs에서 fol2/myfile.cjs 의 정보를 받고 있다.

path : join & resolve 

 보통 express에서 html 파일등 서버에 저장된 데이터를 클라이언트 측에 전달할 때는 sendFile 등의 메서드를 이용한다. 해당 메서드들의 특징은 서버의 파일이 존재하는 "절대 경로" 를 요구한다는 점이다. 

 많은 강의에서 파일의 절대 경로를 "현재 프로젝트의 루트 경로" + 상대 경로 의 형태로 구성하여 위 문제를 해결한다.

    return res.status(200).sendFile(join(__dirname, 'public', 'index.html'));

 join

  join 메서드는 인자로 전달된 경로를 좌측에서 우측 순서로 결합하여 정규화해주는 메서드이다. 위에서 언급했듯이, 많은 강의에서 파일의 절대 경로를 얻기 위해 join 메서드를 이용하고는 한다.

//index.cjs 파일

const {join, resolve} = require('path');
const rootDir = require('../root.cjs');

console.log("join : 상대 경로")
console.log(join('a', 'b', 'c'));
console.log(join('a', 'b'));
console.log(join('a'));

console.log("join : 절대 경로")
console.log(join('/a', 'b', 'c'));
console.log(join('/a', '/b', 'c'));
console.log(join('/a', '/b', '/c'));

console.log("join : 루트 경로와 연결")
console.log(join(rootDir, '/a', '/b'));

 

 

 결과를 살펴보면, 정말 정직하게 주어진 문자열들을 결합하는데 중점을 두고 있다. 중간 문자열이 /a 형태의 절대 경로를 가지든, a 형태의 상대 경로를 가지든지와는 크게 상관 없이 단순히 주어진 문자열을 경로 형태로 결합하는 것이 목표일 때 사용하는 것이 좋다.

resolve

 resolve 는 인자로 전달된 경로들을 절대 경로가 결정될 때까지 결합하되, 절대 경로가 없다면 현재 프로젝트 (package.json 기준) 의 루트 폴더와 결합하여 절대 경로 문자열을 반환하는 메서드이다. 

 절대 경로와 직접적으로 연관이 있기 때문에, 실제 경로를 다룰 때 유리한 메서드라고 할 수 있다.

console.log("resolve : 절대 경로")
console.log(resolve('/a', 'b', 'c'));
console.log(resolve('/a', '/b', 'c'));
console.log(resolve('/a', '/b', '/c'));

console.log("resolve : 상대 경로")
console.log(resolve('a'));
console.log(resolve('a', 'b'));
console.log(resolve('a', 'b', 'c'));

 실제 결과를 살펴보면, 생성된 모든 경로에 C: 와 같은 실제 경로 정보가 들어간 것을 볼 수 있다. 절대 경로가 전달될 때까지 경로를 결합하고 있으며, 상대 경로만이 주어지는 경우 프로젝트 루트 경로와 연결되고 있다

이러한 특성 덕분에, join을 위와 같이 사용하는 경우 간단하게 resolve로 대체할 수 있다.

https://stackoverflow.com/questions/35048686/whats-the-difference-between-path-resolve-and-path-join

module 환경에서의 문제 및 대체 방법

 __dirname 및 __filename 기능은 모듈 기반의 프로젝트에서는 사용할 수 없다. 물론, 이를 대신할 수 있는 방법이 있다.

import {dirname} from 'path';
import { fileURLToPath } from 'url';


const url = new URL(import.meta.url).href;
const __filename = fileURLToPath(url);
const __dirname = dirname(__filename);

console.log(import.meta.url);
console.log(__filename);
console.log(__dirname);

  • import.meta.url : 실행중인 파일의 파일 시스템 상 경로를 반환한다.
  • URL API : 입력된 주소를 URL 형태로 파싱하여 제공하는 API.
  • fileURLToPath : 파일 시스템 상 경로 ( file:// ) 를 일반적인 경로로 변환하는 메서드.
  • dirname : 입력된 파일의 위치를 반환하는 메서드.

 위와 같은 메서드를 이용하면 모듈 기반 프로젝트에서도 __dirname 및 __filename을 묘사할 수 있다. 다만 앞서 언급했듯이 절대 경로를 따로 이용해야 하는 경우가 아니면, 절대 경로 결정을 위해 resolve 함수의 사용을 고려할 수 있겠다.