Simplify CSS import strategy for React Web SDK#215
Conversation
Replace module-level injectStyles() side effect with React 19's <style precedence> component. Each public component now renders <YvStyles /> which React handles for hoisting, deduplication, SSR streaming, and Suspense. Fixes FOUC on SSR, RSC incompatibility, and tree-shaking issues. Non-breaking change for consumers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: f3e48c7 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
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 |
Storybook tests run through Storybook's Vite dev server which needs the __YV_STYLES__ constant defined. Storybook already loads CSS via a direct import of dist/tailwind.css, so empty string is correct here. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
davidfedor
left a comment
There was a problem hiding this comment.
Some comments from ChatGPT which seem valid to me:
(Its high level: yes this is directionally wise and fixes a real weakness; some adjustments seem wise...)
The sideEffects: false change is the biggest red flag. Since the PR also adds a ./styles.css export, webpack’s own docs strongly suggest keeping CSS in the sideEffects allowlist or bundlers may drop it. I’d keep sideEffects: ["**/*.css"] rather than blanket false (webpack tree-shaking docs).
“Non-breaking, consumers change nothing” is a little too confident. Primary React consumers probably won’t need changes, but the style-loading semantics are definitely changing, and the new styles.css path is new public surface.
The new approach creates a maintenance footgun: every public component now has to remember to render YvStyles. The old module-level injection was ugly, but impossible to forget. I’d want either a tiny guardrail test or a documented rule that every public root must include it.
The docs should explain the new model in the public README, not just the PR and AGENTS docs. Right now the package README still sells “styled included” without clarifying whether styling is injected on import, on render, or optionally via styles.css.
…aking Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rovider wrapper Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ing model Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Hey @davidfedor, I've looked at each of your pieces of feedback and have made relevant changes. This PR is ready for re-review and reconsideration.
Fixed in e83614b
I have updated the wording of the PR description.
I've now got the
Ditto to the previous comment. It's been fixed. |
|
@davidfedor is this good to go? |
Replaces the module-level
injectStyles()side effect with React 19's<style href precedence>via an internal<YvStyles />component rendered once inYouVersionProvider. Deletesinject-styles.ts, exports./styles.cssfor non-React consumers, setssideEffects: ["*.css"].Areas changed: style injection mechanism (
YvStyles+YouVersionProviderwrapper), package.json exports/sideEffects, vitest + Storybook Vite configs (__YV_STYLES__define), global.css, README, AGENTS.md, CLAUDE.md.Non-breaking — consumers change nothing. React 19 handles hoisting, deduplication, SSR streaming, and Suspense. Fixes FOUC on SSR, RSC incompatibility, and tree-shaking issues.
Build, typecheck, lint, and all tests pass.
Part of https://lifechurch.atlassian.net/browse/YPE-1821
Greptile Summary
Replaces the imperative
injectStyles()module side-effect with a declarative<YvStyles />component rendered once inside a newYouVersionProviderwrapper, leveraging React 19's<style href precedence>for automatic hoisting, deduplication, and SSR/Suspense support. The previously flagged P1 (__YV_STYLES__undefined in Storybook) is resolved in this PR.Confidence Score: 5/5
Safe to merge — all prior P1 concerns are resolved and no new blocking issues found.
The only remaining finding is a P2 comment inaccuracy in global.css. All P1 issues (Storybook ReferenceError, vitest define) are addressed. Implementation is clean and correct.
No files require special attention.
Important Files Changed
<style href precedence>with the embedded CSS constant; straightforward and correct.Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Consumer App] --> B[YouVersionProvider\npackages/ui wrapper] B --> C[YvStyles\nyv-styles.tsx] B --> D[BaseYouVersionProvider\nplatform-react-hooks] C --> E[React 19 hoists style tag\nto head with deduplication\nand SSR streaming support] D --> F[props.children rendered] H[Non-React Consumer] --> I[import styles.css\ndist/tailwind.css] subgraph Build Time J[tsup define injects CSS string into __YV_STYLES__] K[Storybook viteFinal defines __YV_STYLES__ as empty] L[vitest defines __YV_STYLES__ as empty] end J --> C K --> C L --> CPrompt To Fix All With AI
Reviews (5): Last reviewed commit: "Update changeset message" | Re-trigger Greptile
Context used: