fix: make module importable without a DOM (SSR/serverless/CLI)#33
Open
dmchaledev wants to merge 1 commit into
Open
fix: make module importable without a DOM (SSR/serverless/CLI)#33dmchaledev wants to merge 1 commit into
dmchaledev wants to merge 1 commit into
Conversation
The module ran DOM-dependent code at import time (document.createElement
for the template, customElements.define, and `extends HTMLElement`), so
`import { calculate } from '@hailbytes/vulnerability-calculator'` threw
`ReferenceError: document is not defined` in plain Node — despite the
README documenting a "pure DOM-free calculate()" import and index.d.ts
describing calculate() as "no DOM required". The test suite had to inject
a fake DOM just to import the module.
Guard the browser-only code so the module imports cleanly without a DOM,
while keeping custom-element registration in real browsers unchanged:
- build the <template> only when `document` exists
- fall back to a plain base class when `HTMLElement` is undefined
- register the element only when `customElements` and `document` exist
Add test/pure-import.test.mjs, which imports the module with no DOM shim
(node --test isolates each file in its own process) to lock in the fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv4GpGxQq4AYEtbZVtJpch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The package advertises a pure, DOM-free
calculate()— but importing it in any non-browser environment throws beforecalculate()is ever reachable.The module runs DOM-dependent code at import time:
const TMPL = document.createElement('template')(top level)class HailbytesVulnCalculator extends HTMLElement(theextendsclause is evaluated at module load, so an undefinedHTMLElementthrows immediately)customElements.define('hailbytes-vuln-calculator', …)(top level)This contradicts the project's own documentation:
README.md:32-34— "Or import the pure DOM-free calculator:import { calculate } from '@hailbytes/vulnerability-calculator'"index.d.ts:94— "Pure infrastructure-sizing calculation — no DOM required."The symptom is already visible in the repo:
test/smoke.test.mjsandtest/calculate.test.mjsboth inject a hand-written fake DOM (globalThis.document,HTMLElement,customElements, …) just toimportthe module. Without that shim, the import fails — so anyone using the package for SSR, a serverless function, a CLI, or build tooling hits the error on the first line.Reproduction (before this PR)
Fix
Guard the browser-only code so the module imports cleanly with no DOM, while keeping custom-element behavior in real browsers byte-for-byte the same:
<template>only whendocumentexists.class {}) whenHTMLElementis undefined, so the class declaration doesn't throw.customElementsanddocumentexist.After
Tests
Added
test/pure-import.test.mjs, which imports the module with no DOM shim and assertscalculate()works.node --testruns each test file in its own process, so this file genuinely exercises the non-browser path (it assertsglobalThis.document/HTMLElementareundefinedbefore importing).Full suite is green — 67 passing (65 existing + 2 new):
The existing tests keep their DOM shims and continue to exercise the browser path, so both paths are covered.
Impact
calculate()" import actually work — unblocks SSR / serverless / CLI / build-tool consumers.🤖 Generated with Claude Code
Generated by Claude Code