fix: make module importable in Node/SSR environments#42
Open
dmchaledev wants to merge 1 commit into
Open
Conversation
The module eagerly touched `document`, `HTMLElement`, and `customElements`
at import time, so `import { calculate }` — documented as the pure DOM-free
calculator and advertised as Next.js-compatible — threw
`ReferenceError: document is not defined` in any Node/SSR context. Only the
tests survived, because they install a DOM shim before importing.
Guard the browser-only work: create the <template> only when `document`
exists, fall back to a plain base class when `HTMLElement` is absent, and
register the custom element only when `customElements` exists. The pure
`calculate()` export now works off the browser while the component still
registers in it.
Add test/ssr.test.mjs, which imports the module in a fresh DOM-free child
process and asserts calculate() works.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V7jeAVU59dscFTawE34JgK
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.
Problem
The module touches browser-only globals at import time, so importing it anywhere without a DOM throws immediately:
Three top-level statements run eagerly on import:
const TMPL = document.createElement('template')— needsdocumentclass HailbytesVulnCalculator extends HTMLElement— needsHTMLElementat class-definition timecustomElements.define(...)— needscustomElementsThis breaks two things the project actively advertises:
calculate()API. The README pitchesimport { calculate }as "the pure DOM-free calculator", but importing it in Node/SSR crashes before you can call it.import '@hailbytes/vulnerability-calculator'on the server crashes the render.The existing test suite didn't catch this because both test files install a DOM shim (
globalThis.document,globalThis.customElements,globalThis.HTMLElement) before importing the module — so they never exercise the real Node/SSR path.Reproduction (before this PR)
Fix
Guard the browser-only work so the module parses and imports everywhere, while the custom element still registers in the browser:
<template>only whendocumentexists (nullotherwise — it's only read when the element is instantiated, which never happens off-browser).HTMLElementwhen present, else a plain base class, so the class definition parses in Node.customElements.define(...)only whencustomElementsexists.No behavior change in the browser; the pure
calculate()export now works in Node/SSR.After this PR
Tests
Added
test/ssr.test.mjs, which imports the module in a fresh child process with no DOM shim and assertscalculate()works — a real regression guard for the SSR path that the shimmed tests can't provide.Full suite: 66 passing (
node --test test/*.test.mjs).🤖 Generated with Claude Code
https://claude.ai/code/session_01V7jeAVU59dscFTawE34JgK
Generated by Claude Code