Skip to content

feat: Improve package format publishing and release verification for issue #51#52

Open
anyelopetit wants to merge 4 commits into
mainfrom
feat/package-improvement
Open

feat: Improve package format publishing and release verification for issue #51#52
anyelopetit wants to merge 4 commits into
mainfrom
feat/package-improvement

Conversation

@anyelopetit

@anyelopetit anyelopetit commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

The package format was fixed by separating ESM and CommonJS outputs, rewriting generated internal imports/requires to explicit file extensions, preserving the existing UMD CDN artifact, adding an explicit UMD artifact name, and adding packed-package smoke tests to CI.

The root package entry remains the browser/bundler pixel entry. The @hellotext/hellotext/vanilla entry is the Node/SSR-safe entry.

Resolves #51

Decisions From Issue

# Proposal Decision Rationale
1 Fix ESM build with extensionful internal imports. Taken The advertised ESM entry was broken. Generated ESM now uses explicit paths like ./hellotext.js, ./core/index.js, and ./api/index.js.
2 Fix CJS build so internal require() calls resolve CJS files. Taken CJS require('./hellotext') could resolve the adjacent .js ESM file first. Generated CJS now uses explicit .cjs paths.
3 Separate module formats cleanly. Taken, modified We use lib/esm and lib/cjs instead of a larger dist/esm and dist/cjs move. This keeps the existing dist/hellotext.js UMD path stable.
4 Add packed-package smoke tests in CI. Taken CI now verifies the packed tarball, not only source tests. The smoke test installs the tarball into temporary consumers and checks Node, bundler, CSS, and UMD paths.
5 Clarify browser vs Node entrypoints. Taken README now documents root as the browser/bundler pixel entry and ./vanilla as the Node/SSR/test-safe entry.
6 Clean up the exports map. Taken Root, ./vanilla, CSS, and ./package.json exports now point to precise ESM/CJS/browser/type paths.
7 Reconsider vague default export condition pointing at UMD. Modified We kept default: ./dist/hellotext.js for compatibility with older bundlers and consumers. Removing it would be riskier than documenting and preserving it.
8 Align engines and Babel targets. Deferred The mismatch is real but not part of the immediate package breakage. Changing Node support policy or Babel targets could create avoidable compatibility risk.
9 Modernize ESM output. Deferred Smaller/tree-shakable output is useful, but it is an optimization. We avoided changing transpilation semantics for a battle-tested public pixel.
10 Reduce package payload by removing src. Deferred Shipping src may support debugging or undocumented consumer workflows. Removing it is not required to fix package resolution and could break current users.
11 Ship source maps. Deferred Source maps would improve debugging, but are not necessary for the compatibility fix. This should be handled in a separate follow-up.
12 Make CSS side effects explicit. Taken sideEffects now includes CSS, root side-effectful entries, and the UMD bundle. CSS import behavior remains documented.
13 Improve type packaging. Partially taken The existing shared index.d.ts is preserved for root and ./vanilla. We did not redesign declarations, but the smoke test now verifies the exported package paths that rely on them.
14 Make release packaging harder to stale. Taken Added release:check and smoke:package; prepublishOnly now runs the full release check.
15 Name CDN artifacts intentionally. Taken with compatibility alias We added dist/hellotext.umd.js as the explicit UMD artifact while preserving dist/hellotext.js as the stable CDN/GTM/script-tag path. Package metadata still points to dist/hellotext.js to avoid breaking existing integrations.

Package Shape Decision

Chosen output shape:

lib/
  esm/
    package.json
    index.js
    vanilla.js
    ...
  cjs/
    index.cjs
    vanilla.cjs
    ...
dist/
  hellotext.js
  hellotext.umd.js
styles/
  index.css
index.d.ts

Reasons:

  • Avoids .js and .cjs sibling ambiguity.
  • Allows ESM files to work without setting the whole package to "type": "module".
  • Keeps CommonJS consumers on .cjs files.
  • Keeps the existing UMD bundle path stable while adding a conventional explicit UMD filename.
  • Keeps the existing package-level type behavior unchanged for compatibility.

Entrypoint Decision

The root entry remains browser-facing:

import Hellotext from '@hellotext/hellotext'

It starts Stimulus controllers and assigns window.Hellotext. This is intentional and matches the public pixel behavior.

The vanilla entry is the Node/SSR-safe entry:

import Hellotext from '@hellotext/hellotext/vanilla'

It imports the Hellotext class without starting Stimulus or touching window at import time.

Compatibility Decisions

I intentionally preserved:

  • dist/hellotext.js for CDN/script-tag users.
  • dist/hellotext.umd.js as the explicit UMD artifact name.
  • browser and unpkg fields pointing to dist/hellotext.js.
  • default export condition pointing to dist/hellotext.js.
  • ./styles/* export in addition to the documented ./styles/index.css path.
  • src in published package contents for compatibility, while treating internal deep imports as unsupported public API.
  • CommonJS support.
  • Current runtime APIs and browser behavior.

I intentionally did not:

  • Remove or rename the legacy UMD artifact.
  • Remove src from the package.
  • Change the Node engine policy.
  • Modernize Babel output.
  • Add source maps in this change.

Release Verification Decision

I added a packed-package smoke test because the previous CI only tested source files. The new release check validates the artifact users actually install.

The smoke test verifies:

  • import '@hellotext/hellotext/vanilla'
  • require('@hellotext/hellotext/vanilla')
  • require('@hellotext/hellotext/package.json')
  • Bundling root import with @hellotext/hellotext/styles/index.css
  • The UMD artifact exists at the configured unpkg path
  • dist/hellotext.umd.js exists and matches the legacy dist/hellotext.js alias
  • import/require('@hellotext/hellotext') (root) loads under a DOM stub and attaches window.Hellotext

The root package entry is intentionally browser-facing and touches browser globals, so the smoke test loads it under a minimal DOM stub rather than bare Node. It asserts the root entry imports and attaches window.Hellotext for both ESM and CJS, while still treating browser/bundler usage (via webpack) as the primary supported path.

Deep Import Decision

Deep imports are not considered public API. Supported public entrypoints are:

  • @hellotext/hellotext
  • @hellotext/hellotext/vanilla
  • @hellotext/hellotext/styles/index.css
  • @hellotext/hellotext/package.json

We are still publishing src and generated lib files for compatibility and debugging in this release, but consumers should not rely on internal paths such as @hellotext/hellotext/src/... or @hellotext/hellotext/lib/.... If real consumer needs appear, the public API should be expanded intentionally through documented exports rather than by supporting arbitrary internals.

Follow-Up Candidates

These are intentionally left for future, lower-risk changes:

  1. Add source maps for lib and dist/hellotext.js.
  2. Decide in a future major whether dist/hellotext.js should remain forever or become a documented legacy alias.
  3. Revisit whether src should remain in the published package.
  4. Align Babel targets with the Node 20 support floor.
  5. Modernize the ESM Babel target for smaller output.
  6. Add more explicit TypeScript declaration tests if TypeScript becomes part of CI.

Note

Medium Risk
Changes how consumers resolve the package (exports and dual builds); risk is mitigated by preserving UMD/CDN paths and packed-artifact smoke tests, but wrong resolution could still break integrators until they upgrade.

Overview
Fixes npm package resolution for ESM and CommonJS by splitting outputs into lib/esm and lib/cjs, with generated imports using explicit .js / .cjs paths so Node and bundlers resolve the right files. Public entrypoints stay documented: root @hellotext/hellotext (browser pixel + window.Hellotext), @hellotext/hellotext/vanilla (Node/SSR/tests), and @hellotext/hellotext/styles/index.css; exports, sideEffects, and engines (Node ≥20) are tightened accordingly.

CDN/script-tag compatibility is preserved: dist/hellotext.js remains the metadata path; dist/hellotext.umd.js is added as the named UMD artifact and kept identical to the legacy file. Release safety: CI runs npm run release:check (tests, build, typecheck, packed-tarball smoke tests) instead of tests alone; prepublishOnly uses the same gate. README and new docs/packaging.md explain the layout and compatibility choices.

Reviewed by Cursor Bugbot for commit c09fcf9. Bugbot is set up for automated code reviews on this repo. Configure here.

@anyelopetit anyelopetit self-assigned this Jun 11, 2026
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.

Improve package format publishing and release verification

1 participant