docs(changelog): scope the 4.4.0 entry to the patterns addition - #67
Merged
Conversation
…nto cdn.full.global.js
…ocal build to the example
…te and cover the CDN artifacts in a browser
… Adding a guard so it can't creep back
…ing allocation-free in production
…ple at cdn.full.global.js
…the full bundle in the runtime error
…ne CDN runtime request
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.
Description
Patterns reach no-build pages for the first time, plus two latent bugs the work uncovered and an example that no longer needs a build step.
cdn.full.global.js— patterns for no-build pagesA
<script>tag resolves no specifiers, so a no-build page could not reachsibujs/patternsat all:machineand its siblings were unavailable to exactly the audience islands are aimed at. They now ship in a second CDN bundle — a superset of the default one, sameSibuglobal, namespace kept asSibu.patterns, core spread last so it wins any collision. New export paths:sibujs/cdn-fullandsibujs/cdn-full-dev.A separate artifact rather than a merge. Merging patterns into
cdn.global.jscharged every no-build page +13.0% gzip for code it never calls. That was measured, caught in review, and reverted before release.Sizes are zlib level 9, matching the budget test — the default level is not reproducible across zlib builds:
cdn.global.jscdn.dev.global.jscdn.full.global.jscdn.full.dev.global.jsThe default bundle came out smaller than it went in, because it also lost esbuild's
globalNamewrapper. A test asserts both raw ≤ 80,202 B and gzip ≤ 26,330 B + 2%, because raw size can stay flat while transfer size grows if the new bytes compress worse.Fix:
validatePropsandassertTyperan in production browserspatterns/contracts.tsreadprocess.env.NODE_ENVdirectly. That is not adefinetarget, andprocessdoes not exist in a browser — which the guards read as development:validatePropsvalidated and warned on every production page, andassertTypethrew in exactly the builds its doc comment promised it would be a no-op. Latent for as long as the file existed, invisible while the module was bundler-only.Fixing it properly took three passes, each caught in review:
DEVconst made the behaviour right but left the code in the bundle — esbuild folds the const after dead-code elimination, emittingif (!1) { … throw new TypeError(\[SibuJS Contract] ${r}`) }. Both gates now lead with a bareSIBU_DEV`, which is substituted early.errorsallocation but reordered user callbacks — defaults and validators are caller-supplied, so a later property's factory stopped seeing what an earlier property's validator wrote. It is now two whole loops, one per mode, each finishing a property before starting the next.applyDefaulthelper still normalized shorthand entries into{ type: def }in production — validation-only work, and a place an allocation hides from atoString()guard. Both paths are inlined and the production loop skips shorthand entries outright.Production now contains the props copy, one schema-entry iteration, and object-form default application. No validation-only allocations, validator calls, warnings, or internal contract diagnostic strings remain. Shorthand validator entries are skipped without normalization:
Not asserted absent:
"… is required"and"… must be one of:". Those are the return values of the exportedvalidators.requiredandvalidators.oneOf, which run in production by design.Fix: the CDN builds no longer take esbuild's
globalNameglobalName: "Sibu"emitsvar Sibu = (() => { … })()after the module body, overwriting whatever the body installed with the module's export namespace. Harmless while the two matched; silently wrong the moment a bundle merged anything in. Both entry points now assignglobalThis.Sibuthemselves — which also makes them self-register in a worker, and ~3.7 KB smaller.The chess example runs from the CDN, with no build step
It imported
../../dist/index.js, so it only ran afternpm run build— a build step in the one demo whose subject is that islands need none. It now loadscdn.full.global.jsfrom a<script>tag and takesmachinefromSibu, so it exercises the artifact this PR adds, with no local reduced copy left behind. The missing-runtime error names the full bundle, since the core-only one would installSibuand leavemachineundefined. Setup dropped from four commands to one.Also in the example:
noneplaceholder.ctx.attrserializesfalseto the string"false", so a presence selector matched both states. The stylesheet matches on the value, which also keeps the server-rendered markup correct before hydration.data-side.Related Issue
Closes #
Type of Change
Checklist
Verification
npm run build— 7 build steps, cleannpm run typecheck/npm run typecheck:tests/npm run lint— clean, 682 filesnpm test— 6552 passing, 1 skippednpx playwright test --project=chromium— 125 passing (Playwright 1.61.1)Several test changes fix tests that passed while proving nothing. Each was verified by mutation — breaking the thing under test and confirming the assertion fails:
validatePropsleak for a release. Tests now run the published IIFEs and pass a spy validator, asserting it is never invoked in production with the dev bundle as positive control — "it did not warn" also passes for a branch that ran and stayed quiet.html.indexOf("cdn.global.js")matched the explanatory HTML comment above the tag — and could never have matched the real tag, since"cdn.full.global.js"does not contain that substring. Detection is now attribute-level over comment-stripped HTML, with seven extraction tests at module scope that run without a server or build.dist/, every request is recorded, andtoEqual([EXPECTED_CDN])rejects duplicates and extras — a scalar would have accepted a page downloading two runtimes if the expected one came last. Filenames are checked against an allowlist before becoming a filesystem path.toHaveText("♞")passes for a black knight too, and the promotion test exists to provehxg8=Nproduces a white one./dist/in the island's import graph — plus tests that the runtime tag precedes the deferred island and that the missing-runtime error names the full bundle.tests-browser/cdn-full.spec.tscovers the new artifact in a real browser:machinedriving a coreeffectacross the patterns/core boundary, and the negative thatcdn.global.jsexposes neithermachinenorpatterns.