
next.js 프로젝트를 진행 중, pdfjs를 이용한 파일 처리 기능을 구현했는데, 로컬에서는 정상적으로 worker가 동작하는데 배포서비스에서는 동작하지 않는 현상이 발생했다.
pdfjs 버전도 변경해보고, cmap url도 다르게 지정해보고 해봤지만 해결이 안됐다.
하지만 이 문제가 worker의 문제라는 걸 알게 되었고, worker가 동작해야 파일 처리가 가능한데 pdf worker파일을 public 하위에 pdf.worker.min.mjs로 둔 상황에서 이 mjs 확장자가 배포 시에는 불안정하게 동작할 수 있다는 정보를 접하게 되었다.
.mjs ⇒ .js로 변경하자 정상 작동하게 되었다.
💡생각해보니 mjs와 js 확장자의 차이를 제대로 공부해본 적이 없었음, 이 기회에 정리해보자!
.mjs vs .js 차이점.mjs (ES 모듈, ECMAScript Module)import / export 키워드를 사용하여 모듈을 가져옴.mjs 확장자가 붙어 있으면 자동으로 ESM(ECMAScript Module)으로 인식됨📌 .mjs 예제 (ESM 방식)
// math.mjs
export function add(a, b) {
return a + b;
}
// main.mjs
import { add } from "./math.mjs";
console.log(add(2, 3)); // 5
.js (기본적으로 CommonJS, 하지만 ESM도 가능)require, module.exports).js 파일을 CommonJS로 해석package.json에서 "type": "module"을 설정하면 .js도 ESM처럼 동작할 수 있음<script type="module">을 사용하면 ESM 방식으로 인식📌 .js 예제 (CommonJS 방식)
// math.js (CommonJS)
function add(a, b) {
return a + b;
}
module.exports = { add };
// main.js (CommonJS)
const { add } = require("./math.js");
console.log(add(2, 3)); // 5
.mjs가 배포 환경에서 문제를 일으켰을까?💡 주요 원인은 서버의 MIME 타입과 모듈 시스템 차이 때문!
.mjs를 올바르게 처리하지 못했을 가능성.js를 application/javascript으로 인식.mjs는 일부 서버에서 application/octet-stream(일반 바이너리 파일)로 처리될 수도 있음⭐application/javascript가 아닌 MIME 타입을 받으면 실행을 차단.mjs를 제대로 처리하지 못했을 가능성.mjs 파일을 ES 모듈로 해석pdf.worker.min.mjs는 브라우저에서 Web Worker로 실행되므로, ESM으로 불러오면 import 관련 에러가 날 수도 있음.js로 변경하면 CommonJS 방식으로 로드되기 때문에 문제가 해결됨workerSrc는 내부적으로 <script> 태그를 생성해서 로드.mjs 파일을 ESM 방식으로 불러오려면 <script type="module">로 로드해야 하지만, PDF.js는 그렇게 처리하지 않음.js로 변경하면 기존 방식 그대로 로드할 수 있어서 정상 작동.mjs와 .js를 언제 써야 할까?| 구분 | .mjs (ESM) | .js (CommonJS or ESM) |
|---|---|---|
| Node.js 기본 모드 | ❌ (해석 불가) | ✅ (CommonJS) |
Node.js에서 type: "module" 설정 | ✅ (ESM 모드) | ✅ (ESM 모드) |
| 브라우저 실행 | ✅ (<script type="module">) | ✅ (<script> 기본 실행) |
| PDF.js Web Worker | ⚠️ (충돌 가능) | ✅ (정상 작동) |
| Next.js 환경 | ⚠️ (Webpack 처리 문제 발생 가능) | ✅ (안정적) |