Skip to content

fix: pin @remix-run/* to ~1.17.0 to stop the hydration reload loop#63

Merged
mmcky merged 2 commits into
mainfrom
fix/pin-remix-1.17
Jun 4, 2026
Merged

fix: pin @remix-run/* to ~1.17.0 to stop the hydration reload loop#63
mmcky merged 2 commits into
mainfrom
fix/pin-remix-1.17

Conversation

@mmcky
Copy link
Copy Markdown
Contributor

@mmcky mmcky commented Jun 4, 2026

Problem

Pages rendered with the 2.0.0 candidate flash continuously (constant page reloads) and the in-page "On this page" outline never appears.

Root cause

PR #29 bumped @remix-run/* 1.17 → 1.19 to satisfy @myst-theme/site's ^1.19 peer range and clear a CI error. Remix 1.19's client hard-reloads (window.location.reload()) whenever window.__remixContext.url is undefined — which it always is under the mystmd CLI's SSR (confirmed in both v1.1.1 and 2.0.0). That produces an infinite reload loop ("flashing"), and the client never settles, so useHeaders never builds the outline.

Remix 1.17 — what v1.1.1 shipped, and what upstream jupyter-book/myst-theme themes still pin — has no such check and hydrates gracefully (recoverable React #418/#423 only).

Fix

Verification

Rebuilt on Remix 1.17.1 and probed via myst start: 0 reload-loop errors, outline restored (all headings), render matches the v1.1.1 baseline.

Pairs with #62 (content column) — both are needed for 2.0.0 to render correctly.

🤖 Generated with Claude Code

PR #29 bumped @remix-run/* 1.17 -> 1.19 to satisfy @myst-theme/site's
`^1.19` peer range and clear a CI error. But Remix 1.19's client
hard-reloads (`window.location.reload()`) whenever
`window.__remixContext.url` is undefined — which it always is under the
mystmd CLI's SSR (true in both v1.1.1 and 2.0.0). The result is an
infinite reload loop ("flashing") that also stops the client from
settling, so the in-page "On this page" outline never renders.

Remix 1.17 — what v1.1.1 shipped, and what upstream jupyter-book/myst-theme
themes still pin — has no such check and hydrates gracefully. Pin back
to ~1.17.0 across react/node/vercel/dev/eslint-config/serve, and add
.npmrc `legacy-peer-deps=true` so npm install/ci accept the intentional
version below @myst-theme/site's peer range.

Verified: 0 reload-loop errors, outline restored, render matches the
v1.1.1 baseline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 4, 2026 07:23
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses a Remix 1.19 client-side hydration behavior that triggers a hard reload under mystmd CLI SSR, causing an infinite reload loop (“flashing”) and preventing the in-page outline (“On this page”) from rendering. It resolves the issue by reverting/pinning @remix-run/* back to the previously working ~1.17.0 series and ensuring installs succeed despite @myst-theme/site’s stricter peer range.

Changes:

  • Pin all @remix-run/* dependencies/devDependencies from ~1.19.0 back to ~1.17.0.
  • Add a repo-level .npmrc setting legacy-peer-deps=true to allow npm install / npm ci with the intentional peer mismatch.
  • Update package-lock.json to reflect the downgraded Remix dependency tree.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated no comments.

File Description
package.json Downgrades/pins @remix-run/* packages to ~1.17.0 to avoid the hydration reload loop.
package-lock.json Updates the resolved dependency graph consistent with Remix 1.17.x pins.
.npmrc Enables legacy-peer-deps=true so CI/local installs proceed despite @myst-theme/site peer requirements.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Remix 1.17's @remix-run/dev declares typescript as a *peer* dependency
(1.19 had it as a direct dep), so with .npmrc legacy-peer-deps it is no
longer auto-installed. `npm ci` then left no root tsc, and CI's
`npm run compile` resolved a stray newer TypeScript that hard-errors on
the deprecated tsconfig options (moduleResolution=node10, baseUrl).

Pin typescript ~5.9.0 (matching main's known-good 5.9.3) as an explicit
devDependency, and regenerate package-lock.json minimally from main so
the rest of the tree is unchanged. Verified: npm ci + npm run compile
pass locally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mmcky mmcky merged commit 332192b into main Jun 4, 2026
1 check passed
@mmcky mmcky deleted the fix/pin-remix-1.17 branch June 4, 2026 07:41
mmcky added a commit that referenced this pull request Jun 4, 2026
Bump 1.1.1 -> 2.0.0 across package.json, package-lock.json and
template.yml, and finalize the CHANGELOG [2.0.0] section.

2.0.0 is the @myst-theme 0.14 -> 1.x upgrade (breaking: new notebook
output-node AST; Node engine >=20) plus the technical-review pass, the
visual-regression harness (#60), and three pre-release fixes for
regressions the 1.x upgrade introduced and caught before deploy: the
BannerStateProvider 500 (#61), the full-bleed content column (#62), and
the Remix 1.19 hydration reload loop (#63).

CHANGELOG corrections vs the old [Unreleased] draft: drop the reverted
#29 Remix 1.17->1.19 bump (2.0.0 stays on the v1.0.1 ~1.17.0 pin, so no
net Remix change), correct the Node floor to >=20, and restate the
Security note now that the older Remix v1 toolchain remains.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.

2 participants