Skip to content

fix(@stacksjs/components): bundled dist/index.js is unusable — .stx re-exports produce invalid defaultN bindings #1690

@glennmichael123

Description

@glennmichael123

The published @stacksjs/components package's bundled dist/index.js is unusable at runtime because the build pipeline (packages/components/build.ts) doesn't transform the .stx re-exports in src/index.ts.

Worked around in b93559a334 by adding a "bun": "./src/index.ts" exports condition (same pattern @stacksjs/bun-router uses), so consumers running on Bun with bun-plugin-stx loaded get a working import. But the underlying bundle is still broken for anyone hitting dist/.

Repro

cd packages/components && bun run build
bun -e "import { Dialog } from '@stacksjs/components/dist/index.js'; console.log(Dialog)"
SyntaxError: Exported binding 'default3' needs to refer to a top-level declared variable.
   at <parse> (.../packages/components/dist/index.js:20:1)

(With minify: true: SyntaxError: Exported binding '$c' needs to refer to a top-level declared variable. — same root cause, different rename.)

Why

src/index.ts re-exports each component from its .stx source:

export { default as Dialog } from './ui/dialog/Dialog.stx'
export { default as DialogPanel } from './ui/dialog/DialogPanel.stx'
// …

build.ts runs:

await Bun.build({
  entrypoints: ['./src/index.ts'],
  outdir: './dist',
  plugins: [dts()],          // ← only dts; no stx transform
  external: [
    '@stacksjs/stx',
    '@cwcss/crosswind',
    'ts-syntax-highlighter',
    'bun-plugin-stx',         // ← marked external but never loaded
  ],
})

bun-plugin-stx is listed as external but never registered as a plugin, so the bundler treats .stx files as opaque text/JS, generates synthetic defaultN bindings for each re-export, and produces an output where those bindings aren't actually declared as top-level vars.

Suggested fix

Option A — load bun-plugin-stx so .stx files transform during bundle:

import { dts } from 'bun-plugin-dtsx'
import { stxPlugin } from 'bun-plugin-stx'

await Bun.build({
  entrypoints: ['./src/index.ts'],
  outdir: './dist',
  plugins: [stxPlugin(), dts()],
  // … remove 'bun-plugin-stx' from `external`
})

Option B — keep the dist for utilities only; mark all .stx re-exports as runtime-resolved by always using the bun: ./src/... condition (current workaround). Means non-Bun consumers can't use the package at all, which is probably fine given the rest of the framework's Bun-first stance.

Severity

Anyone installing @stacksjs/components@0.2.21 from npm and importing a component hits the SyntaxError immediately. The package is currently shippable only because consumers in the stx workspace pick up src/ via the bun condition I added in b93559a334.

Cross-reference

Hit while migrating an app to use @stacksjs/components. Companion docs issue #1688 (lead with JSX-tag form) is unrelated to this — that's a docs polish; this is a real packaging break.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions