build(esm): emit one bundle per form so a CDN page pays for what it uses - #431
Merged
Conversation
A dist bundle is a prebuilt file fetched from a CDN, so whatever it contains
is what the page downloads — there is no bundler on the other end to prune
the forms it didn't ask for. dist/en-US.js carries all three, which is most
of its weight for a page that only spells prices.
Adds dist/{langCode}/{form}.js alongside it, built from a virtual entry that
re-exports the single form so Rollup drops the other two and everything only
they reach — the currency vocabulary for a cardinal bundle, the scale tables
for a currency one:
dist/en-US.js 7,778 B all three forms
dist/en-US/cardinal.js 4,293 B -45%
dist/en-US/ordinal.js 3,815 B -51%
dist/en-US/currency.js 3,827 B -51%
Only for forms a language actually exports, read from the module's real
exports via getExportedForms — a language without toOrdinal gets no
ordinal.js rather than an empty bundle. 216 new files for the current 72
languages.
ESM only. UMD is the legacy path, its globals are already namespaced by form
(n2words.currency.enUS), and splitting it would double the file count for the
consumers least likely to be counting bytes.
npm consumers are unaffected and need nothing: src/{lang}.js already exports
the three forms independently and the package is sideEffects-free, so
`import { toCurrency } from 'n2words/en-US'` has always tree-shaken cardinals
and ordinals away. This closes the gap for the one consumer that couldn't.
FORM_EXPORTS moves from module-private to exported in language-helpers.js so
rollup.config.js uses the same form -> export-name mapping instead of
declaring a second copy that could drift.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follows up @TylerVigario's
proto/form-splitnumbers on #428. This takes the per-form half of that idea — the larger half by bytes — as a standalone change againstmain, independent of the currency-matrix discussion.3 files, +85/−4.
The problem
A dist bundle is a prebuilt file fetched from a CDN, so whatever it contains is what the page downloads — there's no bundler on the other end to prune the forms it didn't ask for.
dist/en-US.jscarries all three, which is most of its weight for a page that only spells prices.The change
Adds
dist/{langCode}/{form}.jsalongside the existing combined bundle, built from a virtual entry that re-exports the single form so Rollup drops the other two and everything only they reach — the currency vocabulary for a cardinal bundle, the scale tables for a currency one.Measured from an actual
npm run build:en-USdist/en-US.js(all three)dist/en-US/cardinal.jsdist/en-US/ordinal.jsdist/en-US/currency.jsHolds across languages —
ja-JP5,100 → 2,706/2,766/2,799,fr-FR7,602 → 4,400/4,583/4,733.Scope decisions
n2words.currency.enUS), and splitting it would double the file count for the consumers least likely to be counting bytes.getExportedForms— a language withouttoOrdinalgets noordinal.jsrather than an empty bundle.FORM_EXPORTSmoves from module-private to exported inlanguage-helpers.jssorollup.config.jsuses the same form → export-name mapping rather than a second copy that could drift.npm consumers are unaffected and need nothing
src/{lang}.jsalready exports the three forms independently and the package issideEffects-free, soimport { toCurrency } from 'n2words/en-US'has always tree-shaken cardinals and ordinals away. This only closes the gap for the one consumer that couldn't.No
exportsmap changes — these are fetched by URL, not resolved as bare specifiers.Verification
npm test— 453 tests passnpm run lint— cleannpm run build— clean; 216 per-form bundles emitted, spot-checked thatdist/en-US/currency.jsruns anddist/en-US/cardinal.jscontains no currency vocabulary