Skip to content

Upgrade the library build to Rollup 4 and TypeScript 5 - #2406

Merged
spaceninja merged 1 commit into
mainfrom
upgrade/library-build
Aug 20, 2026
Merged

Upgrade the library build to Rollup 4 and TypeScript 5#2406
spaceninja merged 1 commit into
mainfrom
upgrade/library-build

Conversation

@spaceninja

Copy link
Copy Markdown
Member

Overview

Upgrades the library build toolchain: rollup 2 → 4, rollup-plugin-dts 4 → 6, @rollup/plugin-terser 0.4 → 1, @rollup/plugin-babel 6 → 7, @rollup/plugin-node-resolve 13 → 16, and TypeScript 4.9 → 5.9. These six travel together — rollup-plugin-dts 6 requires rollup ^3 || ^4, and its older 4.x line caps TypeScript below 5 — so splitting them further would leave the tree unresolvable.

No build code changed. gulpfile.js/tasks/build-scripts.js was already using the plain Rollup JS API with the modern scoped plugin packages, so all six majors were drop-in. The diff is 12 lines of package.json plus the lockfile.

The published UMD bundles get substantially smaller.sky-nav.ts imports the generated design-token module for three values, and rollup 2 emitted all 97KB of it. Rollup 4 tree-shakes the object literal down to the reachable leaves, so dist/cloudfour-patterns.js drops 116KB → 21KB and dist/cloudfour-patterns.min.js 37KB → 7.8KB, with the same seven exports. dist/cloudfour-patterns.mjs is byte-for-byte identical, which explains the asymmetry: terser's module: true pass was already doing this elimination on the ESM output, so only the UMD builds — which terser cannot treat as a module — were carrying the dead tokens. There's a patch changeset for the size win.

Decisions a reviewer might question

  • TypeScript 5.9, not the current 7. rollup-plugin-dts 6 accepts ^4.5 || ^5 || ^6 || ^7, so it isn't the constraint. @typescript-eslint is: it's held at 5.17 by @cloudfour/eslint-plugin, which peers on ESLint 8. TypeScript 6 also removesmoduleResolution: "node", which tsconfig.json still uses, and 7 is the native compiler rewrite. Both belong with the lint upgrade rather than here. TypeScript 5.9 does not warn about that option, so tsconfig.json is untouched.
  • The @types/node override is not removed here.Dependency modernization: Node 24, Vite, and Storybook 10 #2391 lists that as part of this PR, but the overrides block only exists on Upgrade to Storybook 10 + Vite, and Twing 7 #2405's branch — main has no override, because webpack 4's dependency tree still pins @types/node to 12.20.6 there. It becomes a rebase step for whichever of the two PRs merges second. It will work in either order: TypeScript 5 parses @types/node 26 fine, and skipLibCheck covers the residual Buffer/Uint8Array mismatches, since those are check errors rather than the parse errors TypeScript 4.9 hit.
  • Type declarations shift from declare const to declare let for namespace members inferred from JS object literals. That's a TypeScript 5 declaration-emit change, and a widening, so no consumer breaks. It's the only change in dist/cloudfour-patterns.d.ts.

This PR touches neither Storybook nor Twig, so it's independent of #2405. Both edit package.json and the lockfile, so the second to merge will need a rebase.

One thing noticed but deliberately left alone: dist/cloudfour-patterns.d.ts exports defaultArgs and defaultArgTypes, which come from src/components/*/*-args.js — Storybook demo args leaking into the library's public types via the rollup entry glob. It's pre-existing on main and the same class of bug #2405 fixed for .stories.js. Worth a follow-up on #2391 rather than widening this.

Screenshots

Testing

CI covers lint, types, build, the test suite and build-storybook. What it can't judge is whether the published artifacts are actually correct, so that's what's worth checking by hand.

Run npm run build first, then:

  • Confirm dist/cloudfour-patterns.js is roughly 21KB and dist/cloudfour-patterns.min.js roughly 7.8KB — both were several times larger before this change
  • Confirm both files still export all seven names: grep -c 'exports\.' dist/cloudfour-patterns.js should report 7
  • Confirm the three design-token values Sky Nav needs survived tree-shaking — grep -o '40em\|0\.4s\|cubic-bezier(0\.455' dist/cloudfour-patterns.js should print all three
  • Confirm the token dump is gone: grep -c 'isSource' dist/cloudfour-patterns.js should report 0 (it was 172 before)
  • Confirm dist/cloudfour-patterns.d.ts still declares the same exports, now using declare let instead of declare const inside the defaultArgs namespace
  • Confirm dist/standalone.css is unchanged at roughly 470KB — the Sass build is not affected by this PR

Then check Sky Nav still works from the built bundle, since it's the component whose tokens were tree-shaken:

  • Start Storybook and open Components → Sky Nav
  • Narrow the window until the menu button appears, and confirm it opens and closes the navigation
  • Confirm the open/close animation still runs smoothly rather than snapping instantly — the timing comes from one of the tree-shaken token values
  • Widen the window again and confirm the navigation returns to its full horizontal layout with no menu button

These six travel together: rollup-plugin-dts 6 requires rollup ^3 || ^4, and its
older 4.x line caps TypeScript below 5. rollup 2 -> 4, rollup-plugin-dts 4 -> 6,
@rollup/plugin-terser 0.4 -> 1, @rollup/plugin-babel 6 -> 7,
@rollup/plugin-node-resolve 13 -> 16, and typescript 4.9 -> 5.9.
No build code changed. build-scripts.js was already using the plain Rollup JS API
with the modern plugin packages, so the majors were drop-in.
The published UMD bundles get substantially smaller. sky-nav.ts imports the
generated token module for three values, and rollup 2 emitted all 97KB of it;
rollup 4 tree-shakes the object down to the reachable leaves. cloudfour-patterns.js
goes 116KB -> 21KB and .min.js 37KB -> 7.8KB, with the same seven exports. The ESM
bundle is byte-for-byte identical, because terser's `module: true` pass was already
doing this elimination -- only the UMD builds, which terser cannot treat as a
module, were carrying the dead tokens.
TypeScript 5.9 rather than the current 7. The constraint is not rollup-plugin-dts,
which accepts ^4.5 || ^5 || ^6 || ^7, but @typescript-eslint -- held at 5.17 by
@cloudfour/eslint-plugin, which peers on eslint 8. TypeScript 6 also removes
`moduleResolution: "node"`, which tsconfig.json still uses, and 7 is the native
compiler rewrite. Both belong with the lint upgrade, not here.
Type declarations shift from `declare const` to `declare let` for namespace members
inferred from JS object literals -- a TypeScript 5 declaration-emit change, and a
widening, so no consumer breaks.
Refs #2391
@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: eea840e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
NameType
@cloudfour/patternsPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify

netlifyBot commented Aug 20, 2026

Copy link
Copy Markdown

Deploy Preview for cloudfour-patterns ready!

NameLink
🔨 Latest commiteea840e
🔍 Latest deploy loghttps://app.netlify.com/projects/cloudfour-patterns/deploys/6a8767af8ec3300008b3c524
😎 Deploy Previewhttps://deploy-preview-2406--cloudfour-patterns.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@spaceninja
spaceninja merged commit eb1bb81 into mainAug 20, 2026
8 checks passed
@spaceninja
spaceninja deleted the upgrade/library-build branch August 20, 2026 21:11
@github-actionsgithub-actionsBot mentioned this pull request Aug 20, 2026
Sign up for freeto 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

@spaceninja