Skip to content

Node.js-библиотека для Office — быстрый старт

npm-пакет office-oxide — это нативная привязка к Node.js: через koffi динамически загружает liboffice_oxide и отдаёт компактный, идиоматический JS API. Быстрее и меньше, чем WebAssembly-сборка, но поставляется с предсобранными бинарниками для конкретных платформ, а не одним переносимым файлом.

Если нужен один артефакт, который работает в браузере, бандлерах или Node без нативных библиотек — берите office-oxide-wasm.

Установка

npm install office-oxide

На postinstall пакет ищет совместимый prebuild в node_modules/office-oxide/prebuilds/<platform>-<arch>/. Если его нет, перед первым использованием настройте одно из следующего:

  1. OFFICE_OXIDE_LIB — абсолютный путь к библиотеке (например, /opt/office_oxide/liboffice_oxide.so).
  2. Каталог prebuild — положите библиотеку в prebuilds/<platform>-<arch>/ (например, linux-x64, darwin-arm64, win32-x64) внутри пакета.
  3. Системный путь библиотек — установите так, чтобы её находили 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"

Редактирование

Editable-handle сохраняет все нетронутые 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 нумеруется с нуля; 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());

Legacy-форматы

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(); }

Ошибки

Сбои бросают OfficeOxideError с числовым code и полем operation:

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;
  }
}
Код Значение
0 OK
1 неверный аргумент
2 IO-ошибка
3 ошибка парсинга
4 сбой извлечения
5 внутренняя ошибка
6 формат не поддерживается

Диагностика

Симптом Что делать
office-oxide: failed to load native library Установите OFFICE_OXIDE_LIB в абсолютный путь или положите подходящий prebuild в пакет.
koffi: ABI mismatch Prebuild не подходит платформе/архитектуре Node — переустановите или возьмите свежий.
TypeError: data must be a Uint8Array or Buffer Document.fromBytes принимает только бинарные типы. Используйте Buffer.from(base64, 'base64').
Document is closed Метод вызван после close() или по выходу из using. Откройте новую handle.
Legacy .doc открывается, но показывает кашу Зашифрованные документы Word 97 не дешифруются — расшифруйте через LibreOffice.

Смотрите также