Skip to content

Feature/cdn considerations - #13

Merged
hexplus merged 4 commits into
mainfrom
feature/cdn-considerations
Sep 7, 2026
Merged

Feature/cdn considerations#13
hexplus merged 4 commits into
mainfrom
feature/cdn-considerations

Conversation

@hexplus

@hexplus hexplus commented Sep 7, 2026

Copy link
Copy Markdown
Owner

Description

sibujs-ui had no no-build story. The package shipped ESM and CJS only, so a page using SibuJS from a <script> tag — islands, most often — could reach the runtime but none of these components. This adds a CDN build, and the stylesheet that makes it actually usable.

The bundle

<link rel="stylesheet" href="https://unpkg.com/sibujs-ui@latest/dist/sibujs-ui.css" />
<script src="https://unpkg.com/sibujs@latest/dist/cdn.global.js"></script>
<script src="https://unpkg.com/sibujs-ui@latest/dist/cdn.global.js"></script>
<script>
  const { Button, Card, Dialog } = window.SibuUI;
</script>

Three new export paths: sibujs-ui/cdn, sibujs-ui/cdn-dev, sibujs-ui/cdn-css.

SibuJS is not bundled in. It stays a peer dependency in this artifact too: an esbuild plugin resolves sibujs to the window.Sibu the runtime tag installed, so a page that already loaded the framework does not download it again. All 59 imports in src/ are bare sibujs, so the plugin's filter covers every one — verified against the built bytes, which contain no framework internals and do read globalThis.Sibu.

That is also why tag order matters. Loading sibujs-ui without the runtime throws a message naming the problem and the fix, rather than surfacing later as an undefined property inside whichever component ran first.

The stylesheet, which is the part that was missing

Every component carries Tailwind utility classes — 29 on a single Button — and the shipped themes are custom properties only. A page that loaded just the script tags got correct behaviour and raw browser defaults. Nothing threw, which makes that harder to diagnose, not easier:

without stylesheet with sibujs-ui.css
display inline-block inline-flex
background rgb(240,240,240) oklch(0.205 0 0)
padding 6px 16px
radius 0px 8px
height 21px 36px
font-weight 400 500

A no-build consumer has no build step by definition, so dist/sibujs-ui.css is now compiled from the components' actual class usage plus the base and default themes — 113.7 KB, 17.7 KB gzip. One <link>, no separate theme import. The destructive variant renders distinctly and dark mode inverts correctly via class="dark".

It includes Tailwind's Preflight, matching what bundler consumers already get from @import "tailwindcss" — the components are designed against that reset, and without it buttons keep their native chrome and borders default to currentColor. It therefore restyles the host page, which the README states plainly.

tw-animate-css turned out to be unnecessary: base.css already defines the keyframes and --animate-* tokens the components name, so the only new dependencies are tailwindcss and @tailwindcss/cli, both dev-only.

Fix: the dev gate could not be folded

components/types.ts tested globalThis.__SIBU_DEV__ first. A member expression is not a define target, so no bundler could replace it: the branch stayed live and its warning text rode into builds that could never print it. It now leads with a bare __SIBU_DEV__, mirroring the framework's own convention, so define: { __SIBU_DEV__: "false" } folds it away. The fallbacks it consulted before are still consulted, in the same order, so behaviour is unchanged wherever the flag was already correct.

Sizes

artifact size
dist/cdn.global.js 573.5 KB raw / 131.3 KB gzip
dist/cdn.dev.global.js 574.1 KB raw / 131.6 KB gzip
dist/sibujs-ui.css 113.7 KB raw / 17.7 KB gzip

The JS carries the whole package — every component and the ~1900-icon set — because a <script> tag cannot tree-shake, and the icons are roughly 79 KB gzip of that total. Bundler consumers are unaffected: the ESM/CJS entry points are untouched and still tree-shake per import.

Related Issue

Closes #

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Checklist

  • I have read CONTRIBUTING.md
  • My code builds without errors
  • I have tested my changes
  • I have updated documentation if needed

Verification

  • npm run build — clean; produces both IIFEs, the stylesheet, and the ESM/CJS entry points
  • npm run lint — clean, 66 files
  • tsc --noEmit — clean
  • npx vitest run432 passing
  • npm pack --dry-run — 23 files, 659.3 kB; confirms dist/cdn.global.js, dist/cdn.dev.global.js, dist/sibujs-ui.css, every theme, and styles/cdn.css all ship. prepublishOnly runs the full build, so a stale artifact cannot be published.

tests/cdn-artifacts.test.ts (12 tests) asserts against the built files what source cannot show: SibuJS absent from the bytes, the ordering guard firing, SibuUI registered without disturbing Sibu, diagnostics compiled out of production and present in dev, and the stylesheet carrying both the utilities and the theme tokens.

One test-design note worth recording: the stylesheet tests first used skipIf(!existsSync(cssPath)), which skipped instead of failing — precisely the behaviour that would let this gap reappear unnoticed. They now gate on the same built flag as the JS bundles, so a built package with a missing stylesheet is a failure. Verified red before implementing.

Verified in a browser

Beyond the unit tests, the actual use case was exercised in Chromium: components built inside a registerIsland setup, appended to server-rendered markup, with a click on a SibuUI Button driving the island's own signal (0 → 1) — one shared runtime, no wiring. Confirmed against both cdn.global.js and cdn.full.global.js, and the load-order guard confirmed firing when the tags are reversed.

Not addressed here

The JS bundle is 131.3 KB gzip, ~79 KB of which is the icon set that no <script> tag can tree-shake. Splitting icons into a second optional artifact would put the base near 54 KB gzip — worth doing, but it changes the public artifact layout and belongs in its own PR.

@hexplus
hexplus merged commit accf45b into main Sep 7, 2026
7 checks passed
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.

1 participant