Skip to content

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

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

feat: Improve package format publishing and release verification for issue #51#52
anyelopetit wants to merge 5 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 non-DOM entry for Node, SSR, and tests.

Note: This PR primarily fixes package consumption paths and release validation. It is not a meaningful runtime bundle-size optimization. The default legacy UMD bundle is 259 B smaller gzipped, while total dist output increases because we now publish an explicit dist/hellotext.umd.js alias.

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. Existing shared index.d.ts remains mapped to root and ./vanilla; deeper declaration testing is deferred.
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.

Verification

Ran locally:

  • npm test — passing
  • npm run build — passing
  • npm run typecheck — passing
  • npm run smoke:package — passing
  • npm run release:check — passing
  • npm pack --dry-run — inspected package contents
    If not all were run, list only what was actually run.

Bundle Size

Measured after npm run build.

File Before gzip After gzip Change
dist/hellotext.js 48,360 B 48,101 B -259 B
dist/hellotext.umd.js n/a 48,105 B new explicit UMD alias
dist/webchat-emoji-en.js 472 B 472 B 0
dist/webchat-emoji-es.js 525 B 525 B 0
dist/webchat-emoji.js 27,381 B 27,381 B 0

Note: dist/hellotext.umd.js and dist/hellotext.js are intentionally identical. The new file is a clearer alias, not a separate runtime build.

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, dual builds, UMD alias); mitigated by packed-package smoke tests and preserved legacy dist/hellotext.js paths, but any undocumented deep imports could still break.

Overview
Fixes npm consumption by splitting ESM (lib/esm) and CommonJS (lib/cjs) outputs and rewriting generated CJS require() paths to explicit .cjs files so Node does not resolve sibling .js ESM builds. Adds dist/hellotext.umd.js as the named UMD build while keeping dist/hellotext.js as the stable CDN/GTM/unpkg alias (smoke-tested for identity).

CI now runs npm run release:check instead of tests alone, gating publish on build, typecheck, and packed-tarball smoke tests (prepublishOnly uses the same script). README and new docs/packaging.md document supported entrypoints: root browser pixel (@hellotext/hellotext), /vanilla for Node/SSR/tests, and styles/index.css; internal src/lib paths are explicitly non-public API.

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

@anyelopetit anyelopetit self-assigned this Jun 11, 2026
@anyelopetit anyelopetit force-pushed the feat/package-improvement branch from c09fcf9 to 187a375 Compare June 22, 2026 16:50

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 187a375. Configure here.

Comment thread scripts/smoke-package.mjs Outdated
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