Skip to content

fix(useIsDark): never throw when localStorage access is blocked - #521

Open
kevbarns wants to merge 1 commit into
codegouvfr:mainfrom
kevbarns:fix/safe-local-storage-access
Open

fix(useIsDark): never throw when localStorage access is blocked#521
kevbarns wants to merge 1 commit into
codegouvfr:mainfrom
kevbarns:fix/safe-local-storage-access

Conversation

@kevbarns

@kevbarns kevbarns commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes #442

Problème

Quand le stockage est bloqué pour le document (iframe tierce avec cookies tiers bloqués, WebView avec stockage désactivé, politique d'entreprise…), Chromium lève une SecurityError dès la lecture de window.localStorage. startClientSideIsDarkLogic n'était pas protégé : start() plantait dans DsfrProvider, $clientSideIsDark n'était jamais initialisé et le premier useIsDark() levait ensuite « react-dsfr not initialized… ». Le rendu client de la page était perdu.

Données de production et stacktrace complète dans #442 (comment) (~870 événements Sentry depuis mars 2026 sur un seul site, quasi exclusivement Chromium).

Correctif

  • Nouveau src/tools/safeLocalStorage.ts : getItem / setItem / removeItem enveloppés dans un try/catch. En cas d'échec, le stockage se comporte comme s'il était vide (getItemnull, écritures ignorées). Le code appelant retombe alors naturellement sur colorSchemeExplicitlyProvidedAsParameter puis prefers-color-scheme, sans changement de logique.
  • src/useIsDark/client.ts : les 6 accès directs passent par le wrapper.
  • src/useIsDark/scriptToRunAsap.ts : même wrapper inliné dans le script exécuté avant hydratation (5 accès), pour que la prévention du flash blanc ne plante pas non plus dans ces environnements.

Non modifié, volontairement : consentManagement/createConsentManagement.ts accède aussi à localStorage sans garde, mais c'est un autre périmètre fonctionnel (le consentement ne peut pas être « oublié » silencieusement sans décision produit). Je peux ouvrir une PR séparée si souhaité.

Tests

  • test/runtime/lib/safeLocalStorage.test.ts : délégation quand le stockage fonctionne ; comportement « stockage vide » quand le getter window.localStorage lève une SecurityError (simulation du comportement Chromium) ; écriture qui lève un QuotaExceededError.
  • test/runtime/lib/scriptToRunAsap.test.ts : exécute le script généré contre un DOM minimal avec un localStorage fonctionnel puis bloqué, et vérifie que data-fr-theme / data-fr-scheme sont bien posés dans les deux cas.
  • Vérifié que les nouveaux tests échouent bien sans le correctif (2 échecs sur 3 dans scriptToRunAsap.test.ts) et que yarn build && yarn test passe avec (114 tests), yarn lint:check et yarn format:check sans erreur sur les fichiers touchés, tsc -p src sans erreur.

Copilot AI lite review requested due to automatic review settings September 2, 2026 18:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The change safely prevents initialization crashes when storage access is blocked and is backed by targeted runtime tests for both the client logic and the ASAP script.

Pull request overview

This PR fixes crashes in the useIsDark initialization path when window.localStorage access is blocked (notably Chromium throwing SecurityError on read), ensuring the client-side theme logic still initializes and falls back to defaults instead of breaking rendering.

Changes:

  • Add a safeLocalStorage wrapper that never throws and behaves like an empty storage when access fails.
  • Replace direct localStorage accesses in the client-side useIsDark logic with safeLocalStorage.
  • Harden the pre-hydration “run ASAP” inline script against blocked storage and add runtime tests covering both working and blocked storage scenarios.
File summaries
File Description
src/tools/safeLocalStorage.ts Introduces a safe localStorage wrapper that swallows read/write failures and returns null on reads when unavailable.
src/useIsDark/client.ts Switches persisted scheme reads/writes to safeLocalStorage so initialization never crashes when storage is blocked.
src/useIsDark/scriptToRunAsap.ts Inlines a safe storage wrapper inside the ASAP script to prevent pre-hydration theme setup from crashing.
test/runtime/lib/safeLocalStorage.test.ts Adds runtime tests for normal delegation, blocked-storage getter behavior, and write errors like QuotaExceededError.
test/runtime/lib/scriptToRunAsap.test.ts Adds runtime tests executing the generated script with both functional and blocked localStorage.
Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@kevbarns kevbarns self-assigned this Sep 2, 2026
@kevbarns
kevbarns requested a review from garronej September 2, 2026 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Erreur dans la console lors de l'utilisation de la lib

2 participants