Skip to content

import "docxodus" fails under plain Node ESM: the barrel pulls in the browser editor #745

Description

@ifeulner

Summary

The README lists Browser / Node as a supported surface, but import "docxodus"
throws in plain Node. The barrel re-exports the browser editor, which imports
@atlaskit/pragmatic-drag-and-drop subpaths that only a bundler can resolve.

Everything the engine offers — initialize, convertDocxToHtml, docxDiff*,
the annotation overlay, openDocxSession — is defined in dist/index.js itself,
so there is no engine-only entry point to import instead.

Reproduction

mkdir repro && cd repro
npm init -y && npm pkg set type=module
npm install docxodus@12.3.0
node -e "import('docxodus').then(()=>console.log('OK')).catch(e=>console.log(e.code))"
ERR_UNSUPPORTED_DIR_IMPORT: Directory import
'/…/node_modules/@atlaskit/pragmatic-drag-and-drop/element/adapter'
is not supported resolving ES modules imported from
'/…/node_modules/docxodus/dist/editor.js'

Node v26.8.1, docxodus 12.3.0. Reproduces with npm and pnpm alike, so it is
not a package-manager artifact. Under tsx it surfaces differently
(ERR_MODULE_NOT_FOUND, resolving …/element/adapter/index.jsx).

Root cause

@atlaskit/pragmatic-drag-and-drop ships no exports map. Its subpath
directories contain only a legacy redirect:

// element/adapter/package.json
{ "main": "../../dist/cjs/entry-point/element/adapter.js",
  "module": "../../dist/esm/entry-point/element/adapter.js" }

module is a bundler convention; Node ESM does not read it, and directory
imports are unsupported. dist/index.js reaches this via
export { DocxEditor } from "./editor.js" (plus CommentGutter, ribbon), so
the failure happens on import, before any engine call.

exports currently publishes ., ./react, ./embed, ./worker,
./export-browser — none of which is engine-only.

Why it matters

Server-side is a real use case for this library: batch conversion, diffing in a
job queue, agent pipelines, indexing. Those never touch DocxEditor, but today
they cannot import the package at all without a bundler or a loader shim.

Suggested fix

Add an engine-only subpath that excludes the editor, e.g.:

"./core": { "types": "./dist/core.d.ts", "import": "./dist/core.js" }

exporting everything in index.js except DocxEditor, CommentGutter and
ribbon. index.js could then re-export ./core plus the editor, keeping the
current entry point unchanged for browser consumers.

A lazy await import("./editor.js") inside the editor factories would also work
and would fix the default entry point itself, though it changes DocxEditor to
an async acquisition.

Workaround, for anyone hitting this

A ~20-line Node loader hook that resolves @atlaskit/pragmatic-drag-and-drop* to
a stub with the seven named exports the editor imports (draggable,
dropTargetForElements, monitorForElements, autoScrollForElements,
autoScrollWindowForElements, pointerOutsideOfPreview,
setCustomNativeDragPreview). With that in place the engine loads and runs
correctly in Node (cold start around 100 ms), so this is purely a packaging
boundary and not an engine limitation.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions