Extract the browser tier, behind a config seam - #22
Merged
playforge-coding merged 1 commit intoAug 5, 2026
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Fifth and final extraction layer: imageStore, imageRef, storage, docxExport,
docxImport, htmlPreview, pdfExport and the download half of jsonExport, under
@spelling-creator/core/browser/*.
Unlike the earlier layers this shares nothing with the Worker — nothing else can
use a module that needs IndexedDB. The point is that these are browser-dependent
but framework-agnostic: they are the code that survives a rewrite of the React
layer intact, which is the reason for extracting lib/ in the first place.
It was blocked, though, and not by React. imageRef read
import.meta.env.VITE_API_URL at module scope, and storage, docxExport,
docxImport, htmlPreview, pdfExport and imagesClient all sit downstream of it —
so one line pinned the whole tier. 18 modules in apps/web do the same thing;
this is the pattern, not an isolated case.
So core now takes its configuration through a seam instead:
configureCore({ apiUrl: import.meta.env.VITE_API_URL }); // main.jsx, once
Readers resolve lazily rather than capturing at import time, which is load
bearing: ES imports are hoisted, so configureCore runs *after* every module in
the graph has been evaluated, and anything capturing the value would capture "".
config.test.js pins that, and every read was checked to be inside a function
body rather than at module scope.
Two modules that step 1 moved wholesale are now split along the same line they
were always going to split on. image keeps the pure sizing arithmetic and gives
up readImageFile (canvas, FileReader) to browser/imageFile; jsonExport becomes
lessonFile (the envelope, which jsonImport and the MCP server also want) and
browser/jsonExport (the part that clicks an <a>). That removes the layering
violation where a runtime-neutral module would have had to import from the
browser tier for two constants.
The lint rule from step 1 is now structural rather than a list of filenames:
src/browser/** is the browser env, everything else in core is worker.
mammoth and html2pdf.js move to core's dependencies; web keeps docx, which
googleDrive.js still uses directly.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
playforge-coding
force-pushed
the
core-extract-browser-tier
branch
from
August 5, 2026 23:30
e00cba4 to
4e29a02
Compare
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.
Fifth and final extraction layer. Stacked on #20.
Moves
imageStore,imageRef,storage,docxExport,docxImport,htmlPreview,pdfExportand the download half ofjsonExportunder@spelling-creator/core/browser/*.Why, given none of this is shareable
Unlike the earlier layers, this shares nothing with the Worker — nothing else can use a module that needs IndexedDB. The point is that these are browser-dependent but framework-agnostic: they're the code that survives a rewrite of the React layer intact, which is the reason for extracting
lib/in the first place.It was blocked, and not by React
imageRefreadimport.meta.env.VITE_API_URLat module scope, andstorage,docxExport,docxImport,htmlPreview,pdfExportandimagesClientall sit downstream of it. One line pinned the entire tier.18 modules in
apps/webdo the same thing. That's the pattern, not an isolated case — and it's a bigger obstacle to ever changing build tool or framework than React is.So core takes its configuration through a seam:
Readers resolve lazily, and that's load-bearing. ES imports are hoisted, so
configureCoreruns after every module in the graph has been evaluated — anything capturing the value at import time would capture"". I checked every read is inside a function body rather than at module scope, andconfig.test.jspins the behaviour with a test that configures after import.Two modules from #16 now split properly
imageandjsonExportwere moved wholesale in #16 with a note that they'd split later. They split along exactly the line they were always going to:imagefitWithin,imageSizeScale, defaults)browser/imageFile—readImageFile(canvas, FileReader)jsonExportlessonFile— the envelopebrowser/jsonExport— the part that clicks an<a>This removes a real layering violation:
jsonImportis runtime-neutral but needed two constants from each, and would otherwise have had to import from the browser tier.lessonFileis also a latent third duplication —apps/mcp/src/doc.jshas its ownbuildLessonFile, and the old comment asked for them to be kept in sync by hand. Not deduped here; worth a follow-up.The lint rule is now structural
#16 opted two files into the
browserenv by name. That list is replaced bysrc/browser/**, so the boundary is a directory rather than a list someone has to remember to update.Verification
pnpm run lint,pnpm run build,pnpm run build:docspass; core 38, api 27, mcp 14. Bundle total unchanged (4095.8 kB vs 4096.0 kB).mammothandhtml2pdf.jsmove to core's dependencies; web keepsdocx, whichgoogleDrive.jsstill uses directly.Stack created with GitHub Stacks CLI • Give Feedback 💬