feat(docs): generate PDF previews in the browser instead of committing them - #16
Open
avdoseferovic wants to merge 1 commit into
Open
feat(docs): generate PDF previews in the browser instead of committing them#16avdoseferovic wants to merge 1 commit into
avdoseferovic wants to merge 1 commit into
Conversation
…g them Feature and example pages now render their PDF preview client-side from paper.wasm, using the very same GetPaper builder the page displays as its code sample, so a preview can no longer drift from the code beside it. 29 of the 35 committed PDFs are gone from the repository. Examples become importable - Each directory under docs/assets/examples/ is split into paper.go (the existing GetPaper builder) and a thin cmd/main.go that does the file I/O. unittests is unchanged. - bookmark and watermark gain builders and structure tests. - compression.GetPaper returned by calling os.Exit(1) on a missing image. os.Exit bypasses recover(), so under wasm it would have killed every export on the page. It returns an error now. - The 31 pre-existing golden structure fixtures are byte-identical, which is the evidence that repackaging altered no output. Rendering in the browser - exampleregistry maps 29 names to a builder and the images it reads. - paperGenerateExample / paperExampleAssets join the existing wasm exports. - paper-fs.js provides a read-only in-memory globalThis.fs so the library's ordinary os.ReadFile works, leaving both library and example code untouched. It is pinned by paper-fs.test.mjs, run from make test and CI, because a break there draws an error box into a valid PDF rather than failing. - ExampleToBase64 treats an unreadable asset as an error for the same reason. - paper-preview.js replaces docsify-pdf-embed-plugin and PDFObject, which needed localStorage, executeScript, and dropped the project-pages prefix. The wasm loads lazily on the first preview and is reused for the session: pages without a preview never fetch it. What stays committed - background, customfont, disablepagebreak, mergepdf and showcase keep static embeds because their inputs are impractical to ship to a browser, and paper.pdf remains because mergepdf reads it. make examples still generates everything locally. Also fixes make site deleting every *.go, which had been quietly emptying the code samples on the locally served site. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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
Feature and example pages now render their PDF preview client-side from
paper.wasm, using the sameGetPaperbuilder the page displays as its code sample — so a preview can no longer drift from the code beside it. 29 of the 35 committed PDFs leave the repository.How it works
Each directory under
docs/assets/examples/is split intopaper.go(the existingGetPaperbuilder) plus a thincmd/main.gothat does the file I/O, which makes the builders importable. A registry maps 29 example names to a builder and the images it reads, and the wasm binary gainspaperGenerateExample(name)andpaperExampleAssets(name).The tricky part is that wasm has no filesystem, and eight examples load images via
image.NewFromFileCol. Rather than rewrite those examples to a byte-based API — which would have made the documented code less idiomatic than what users should actually write —docs/assets/js/paper-fs.jsprovides a read-only in-memoryglobalThis.fs.wasm_exec.jsonly installs its own stub whenglobalThis.fsis absent, so defining ours first means the library's ordinaryos.ReadFilejust works. Neither the library nor the example code changed how it loads images.Tricky details worth knowing
syscall.Openalways followsopenwithfstat+isDirectory(), andsetStatcalls.Int()on 13 numeric fields —.Int()onundefinedpanics and takes the whole instance down.readmust keep a per-fd cursor (position === nulladvances it, a numeric position must not) and report EOF as 0 bytes, oros.ReadFilespins forever.image.loadissue, draws an error box, and still returns a valid%PDF-. So a "did a PDF come out?" check passes with the shim completely broken.ExampleToBase64fails on any recordedimage.loadissue, and that is what makes the tests meaningful.compression.GetPapercalledos.Exit(1)on a missing image.os.Exitbypassesrecover(), so under wasm it would have killed every export on the page. It returns an error now — the one example whose signature changed.paper-preview.jsreplacesdocsify-pdf-embed-plugin+ PDFObject, which round-tripped embeds throughlocalStorage, required$docsify.executeScript, and built absolute URLs fromlocation.hostnamealone (dropping the/paper/project-pages prefix). The wasm loads lazily on the first preview and is cached for the whole SPA session.<embed>as a blank box and raise no error, so there is nothing to catch and fall back from.Cost, stated plainly
The module is ~19.6MB raw / 4.7MB gzipped. A visitor's first preview costs that, where it previously cost 4–36KB for a static PDF. It is cached for the session and pages without a preview never fetch it (verified), but the real win here is repository history, not visitor bandwidth.
What stays committed
background,customfont,disablepagebreak,mergepdfandshowcasekeep static embeds because their inputs are impractical to ship (792KB PNG, 23MB TTF, an existing PDF).paper.pdfstays becausemergepdfreads it as input.make examplesstill generates everything locally.Evidence
image.loadissue.paper-fs.test.mjs(11 tests, wired intomake testand CI) pins the syscall contract. Mutation-tested: dropping astatfield and ignoring the read cursor each fail the suite./paper/-prefixed replica of the Pages artifact: previews render (including image-dependent ones), static fixtures still embed, preview-free pages fetch zero wasm, and SPA navigation across four routes instantiates it exactly once.Drive-by fix:
make sitedeleted every*.gowhilepages.ymldeliberately keeps them, so the locally served site had been rendering empty code samples. It now removes only*_test.go.Related Issue
Checklist
func (<first letter of struct> *struct) method() {}name style.when,shouldnaming pattern.m := mocks.NewConstructor(t).m.EXPECT().MethodName()method to mock methods.example_test.go.make dodwith no issues🤖 Generated with Claude Code