Node.js Office 라이브러리 — 빠른 시작
office-oxide npm 패키지는 네이티브 Node.js 바인딩입니다 — koffi로 liboffice_oxide를 동적 로딩하고, 작고 관용적인 JavaScript API를 제공합니다. WebAssembly 빌드보다 빠르고 작지만, 단일 이식 가능한 바이너리 대신 플랫폼별 사전 빌드 바이너리를 배포합니다.
브라우저, 번들러, 또는 네이티브 라이브러리 없는 Node에서 단일 결과물로 동작시키려면
office-oxide-wasm을 사용하세요.
설치
npm install office-oxide
postinstall 시 node_modules/office-oxide/prebuilds/<platform>-<arch>/에서 맞는 사전 빌드 바이너리를 찾습니다. 없으면 첫 사용 전에 다음 중 하나를 구성하세요:
OFFICE_OXIDE_LIB— 라이브러리 절대 경로(예:/opt/office_oxide/liboffice_oxide.so).- 사전 빌드 디렉터리 — 패키지 안의
prebuilds/<platform>-<arch>/(예:linux-x64,darwin-arm64,win32-x64)에 라이브러리를 둡니다. - 시스템 라이브러리 경로 —
LD_LIBRARY_PATH/DYLD_LIBRARY_PATH/PATH로 발견 가능한 위치에 설치.
Node 18+에서 동작합니다.
문서 읽기
import { Document } from 'office-oxide';
const doc = Document.open('report.docx');
try {
console.log(doc.plainText());
} finally {
doc.close();
}
또는 TC39 explicit resource management (Node 22+):
import { Document } from 'office-oxide';
using doc = Document.open('report.docx');
console.log(doc.plainText());
// 스코프 종료 시 doc.close()가 자동 호출됨
원샷 헬퍼:
import { extractText } from 'office-oxide';
console.log(extractText('report.docx'));
핵심 API
import { Document } from 'office-oxide';
const doc = Document.open('file.xlsx');
try {
console.log(doc.format); // "xlsx"
console.log(doc.plainText());
console.log(doc.toMarkdown());
console.log(doc.toHtml());
const ir = doc.toIr(); // 파싱된 객체
doc.saveAs('file.docx'); // 대상 형식은 확장자에서 추론
} finally {
doc.close();
}
원시 바이트(Uint8Array 또는 Buffer)에서 열기:
import { readFileSync } from 'node:fs';
import { Document } from 'office-oxide';
const data = readFileSync('report.pptx');
using doc = Document.fromBytes(data, 'pptx');
console.log(doc.toMarkdown());
format은 'docx' | 'xlsx' | 'pptx' | 'doc' | 'xls' | 'ppt' 중 하나여야 합니다.
모듈 레벨 헬퍼:
import { extractText, toMarkdown, toHtml, detectFormat, version } from 'office-oxide';
extractText('file.docx'); // string
toMarkdown('file.pptx'); // string
toHtml('file.xlsx'); // string
detectFormat('mystery.bin'); // "docx" | ... | null
version(); // "0.1.0"
편집
편집 가능한 핸들은 저장 시 변경되지 않은 모든 OPC 파트를 보존합니다. DOCX, XLSX, PPTX만 지원합니다.
import { EditableDocument } from 'office-oxide';
using ed = EditableDocument.open('template.docx');
const n = ed.replaceText('{{name}}', 'Alice');
console.log(`${n}건 치환`);
ed.save('out.docx');
XLSX 셀 쓰기
import { EditableDocument } from 'office-oxide';
using wb = EditableDocument.open('budget.xlsx');
wb.setCell(0, 'A1', 'Total'); // 문자열
wb.setCell(0, 'B1', 42.5); // 숫자
wb.setCell(0, 'C1', true); // 불리언
wb.setCell(0, 'D1', null); // 비움
wb.save('budget.xlsx');
sheetIndex는 0부터; cellRef는 표준 스프레드시트 표기법.
형식 무관 IR
using doc = Document.open('report.docx');
const ir = doc.toIr();
for (const section of ir.sections) {
console.log(section.title);
for (const el of section.elements) {
// el.kind: "Heading" | "Paragraph" | "Table" | "List" | ...
}
}
바이트 기반 파이프라인
import { Document } from 'office-oxide';
const res = await fetch('https://example.com/report.docx');
const data = new Uint8Array(await res.arrayBuffer());
using doc = Document.fromBytes(data, 'docx');
console.log(doc.toMarkdown());
레거시 형식
using doc = Document.open('old.xls');
doc.saveAs('modern.xlsx');
CommonJS
const { Document } = require('office-oxide');
const doc = Document.open('file.docx');
try { console.log(doc.plainText()); } finally { doc.close(); }
오류
실패 시 숫자 code와 operation 필드를 가진 OfficeOxideError가 발생합니다:
import { Document, OfficeOxideError } from 'office-oxide';
try {
using doc = Document.open('missing.docx');
} catch (e) {
if (e instanceof OfficeOxideError) {
console.error(`code=${e.code} op=${e.operation}`);
} else {
throw e;
}
}
| Code | 의미 |
|---|---|
| 0 | OK |
| 1 | 잘못된 인자 |
| 2 | IO 오류 |
| 3 | 파싱 오류 |
| 4 | 추출 실패 |
| 5 | 내부 오류 |
| 6 | 미지원 형식 |
문제 해결
| 증상 | 해결 |
|---|---|
office-oxide: failed to load native library |
OFFICE_OXIDE_LIB을 절대 경로로 설정하거나 맞는 사전 빌드 바이너리를 패키지에 두세요. |
koffi: ABI mismatch |
플랫폼/아키텍처용 사전 빌드 바이너리가 Node 프로세스와 맞지 않습니다 — 재설치하거나 새로 받으세요. |
TypeError: data must be a Uint8Array or Buffer |
Document.fromBytes는 바이너리 타입만 받습니다. Buffer.from(base64, 'base64') 사용. |
Document is closed |
close() 후 또는 using 스코프 종료 후 메서드를 호출했습니다. 새 핸들을 여세요. |
레거시 .doc이 열리지만 깨져 보임 |
암호화된 Word 97 문서는 복호화되지 않습니다 — LibreOffice로 먼저 복호화하세요. |