vite를 통해 react앱을 만들고 로컬 환경에서 express로 서버를 구축하던 중 오류가 발생했다.
바로 __dirname
이 정의되지 않았다는 것이다.
app.use(express.static(path.join(__dirname, '/dist')))
이 코드에서 문제가 발생했는데, dist
라는 디렉터리를 express에 등록하는 코드이다.
vite로 build를 할 경우 루트 디렉터리 내에 dist
라는 디렉터리가 생기고,
그 안에는 index.html, 이미지 파일과 같은 정적인(static) 파일이 저장된다.
이 디렉터리를 express가 전송해주기 위해선 먼저 등록하는 과정이 필요한데,
나는 그 과정에서 오류가 발생한 것이다.
구글링 하던 중 원인과 해결방법을 찾을 수 있었다.
ES module을 사용하면 __dirname
을 '그냥' 사용할 수 없다는 것이다.
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
tsconfig.json파일의 내용 중 compilerOptions 일부분을 가져온 것이다.
코드를 보면 ESNext
라는 module을 사용하고 있다는 것을 알 수 있다.
코드 2줄을 server.js파일 상단에 추가했다.
import path from 'path';
import { fileURLToPath } from 'url';
파일이나 디렉터리 경로를 다루는 path
모듈과
일반적인 파일 url을 Node.js 파일 path로 바꿔주는 fileURLToPath
함수를 가져온다.
다음은 fileURLToPath 함수에 관한 공식문서이다.
url을 입력받으면 (완전히 플랫폼 문제가 해결된) 특정한 Node.js 파일 경로를 리턴해준다고 한다.
그 다음 하단에 코드 2줄을 추가한다.
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
fileURLToPath
로 경로 변환해서 __filename
에 저장하고__dirname
에 저장한다.이렇게 코드를 작성하면 오류가 해결되는데, 도대체 어떤 과정을 거쳐 해결되는지 궁금해서 더 알아봤다.
server.js의 경로를 저장하고 있는건 맞는데, 앞에 file:///
가 붙어있다.
아마 이를 제거하기 위해 fileURLToPath
함수를 사용하는 것 같다.
console.log로 __filename
과 __dirname
을 출력해보면 다음과 같은 결과를 얻는다.
__filename
에 저장된 값
C:\Users\user\Desktop\Programing\nodejs-study\my-blog-app\server.js
__dirname
에 저장된 값
C:\Users\user\Desktop\Programing\nodejs-study\my-blog-app
결론적으로
fileURLToPath(import.meta.url)
을 통해 서버 파일의 경로, 즉 server.js의 경로를 가져온 후,path.dirname(__filename)
을 통해 그 파일이 포함된 디렉토리를 찾아서 경로를 반환하는 것을 알 수 있다.
이를 통해 정상적으로 __dirname
을 사용할 수 있게 됐다.
__dirname
오류 원인과 해결방법
https://flaviocopes.com/fix-dirname-not-defined-es-module-scope/
fileUrlToPath
함수 관련 Node.js 공식 문서
https://nodejs.org/api/url.html#urlfileurltopathurl