Skip to content

fix: make module import-safe in non-browser environments (SSR/Node)#38

Open
dmchaledev wants to merge 1 commit into
mainfrom
claude/sleepy-rubin-43dero
Open

fix: make module import-safe in non-browser environments (SSR/Node)#38
dmchaledev wants to merge 1 commit into
mainfrom
claude/sleepy-rubin-43dero

Conversation

@dmchaledev

Copy link
Copy Markdown
Contributor

Problem

The README advertises calculate() as a "pure DOM-free calculator" that works in Next.js and other bundlers:

// Or import the pure DOM-free calculator:
import { calculate } from '@hailbytes/vulnerability-calculator';

But importing the module in any non-browser environment (Node.js, SSR / React Server Components, serverless functions, edge runtimes, or a test runner without a DOM shim) throws at module-evaluation time — before calculate is ever reachable:

ReferenceError: document is not defined
    at hailbytes-vuln-calculator.js:553

This happens because three pieces of module-level code touch the DOM unconditionally:

  1. const TMPL = document.createElement('template') (top level)
  2. class HailbytesVulnCalculator extends HTMLElement — the extends clause is evaluated at class-definition time, so it throws if HTMLElement is undefined
  3. customElements.define(...) (top level)

The existing test suite passed only because both test files inject a global DOM shim before importing the module, masking the bug.

Fix

Guard all three DOM touchpoints behind environment checks so the module loads cleanly under Node.js / SSR / serverless / test runners, while preserving 100% of the browser behavior:

  • Build the template HTML into a string and only create the <template> element when document exists.
  • Subclass a plain-object fallback base class when HTMLElement is unavailable.
  • Register the custom element only when both customElements and document are present.

The calculate() export is now genuinely DOM-free, as documented.

Testing

  • Added test/dom-free.test.mjs — a regression test that imports the module with no DOM globals defined and runs calculate(). node:test isolates each test file in its own process, so this exercises the real non-browser path (no shim leakage from the other test files).
  • Full suite: 66 tests pass (was 65). Verified a raw node -e "import(...)" with no shim now succeeds.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ni4iqvgAU45pJsxvcuwYth


Generated by Claude Code

The README advertises `import { calculate }` as a "pure DOM-free
calculator" for Next.js/SSR, but importing the module in any non-browser
environment threw `ReferenceError: document is not defined` at load time,
before `calculate` was even reachable. Module top-level code called
`document.createElement`, subclassed `HTMLElement`, and invoked
`customElements.define` unconditionally.

Guard all three DOM touchpoints behind environment checks so the module
loads cleanly under Node.js/SSR/serverless/test runners while preserving
all browser behavior. Add a regression test that imports the module with
no DOM globals present (node:test isolates each file in its own process).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ni4iqvgAU45pJsxvcuwYth
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants