Skip to content

Fix preserved URL not cleared when navigating to root or restarting#2422

Merged
wwwillchen merged 2 commits intodyad-sh:mainfrom
wwwillchen:fix-preserved-url-not-cleared-on-root-navigation
Feb 2, 2026
Merged

Fix preserved URL not cleared when navigating to root or restarting#2422
wwwillchen merged 2 commits intodyad-sh:mainfrom
wwwillchen:fix-preserved-url-not-cleared-on-root-navigation

Conversation

@wwwillchen
Copy link
Copy Markdown
Collaborator

@wwwillchen wwwillchen commented Feb 2, 2026

Summary

  • Fix regression from PR Fix refresh to preserve current route (#253) #2336 where previewCurrentUrlAtom wasn't cleared when navigating back to root (/)
  • Clear preserved URL in pushState/replaceState handlers when pathname is "/" or empty
  • Clear preserved URL in restartApp before restarting to prevent stale route restoration
  • Add E2E test to verify route stays on root after restart

Fixes the issue where HMR/restart would load the wrong URL after navigating back to root from a sub-route.

Test plan

  • E2E test restart after navigating back to root should stay on root passes
  • Existing test refresh preserves current route still passes
  • Unit tests pass (661 tests)

🤖 Generated with Claude Code


Open with Devin

Note

Medium Risk
Touches preview navigation state and route preservation behavior, which could affect iframe routing/back-forward history across HMR and restarts. Changes are localized and covered by a new Playwright E2E regression test.

Overview
Fixes a regression where the preview could restore a stale sub-route after returning to / and then triggering HMR/reload.

PreviewIframe now clears previewCurrentUrlAtom when pushState/replaceState navigates back to the app’s root path, and useRunApp.restartApp clears the preserved URL before restarting to avoid stale route restoration. Adds a Playwright E2E test (hmr_path.spec.ts) covering the root-navigation + HMR scenario, and allows disabling the Claude stop hook via DISABLE_DYAD_STOP_HOOK.

Written by Cursor Bugbot for commit e5aaa06. This will update automatically on new commits. Configure here.


Summary by cubic

Fixes a regression where the preview restored a stale sub-route after returning to “/” or restarting. We now clear the preserved URL so the app stays on the expected root route.

  • Bug Fixes

    • Clear preserved URL on pushState/replaceState when navigating back to root in PreviewIframe.
    • Clear preserved URL during restart (useRunApp) to prevent stale route restoration.
    • Add E2E test to ensure HMR after returning to root stays on “/”.
  • New Features

    • Allow disabling the stop hook via DISABLE_DYAD_STOP_HOOK environment variable.

Written for commit e5aaa06. Summary will update on new commits.

PR dyad-sh#2336 introduced previewCurrentUrlAtom to preserve routes across HMR,
but it wasn't cleared when:
1. Navigating back to root (/) via pushState/replaceState
2. Restarting the app

This caused the wrong route to load after restart/HMR if the user had
previously visited a sub-route and then navigated back to root.

Changes:
- Clear preserved URL in pushState/replaceState handlers when pathname is "/"
- Clear preserved URL in restartApp before restarting
- Add E2E test for restart after navigating back to root

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@wwwillchen
Copy link
Copy Markdown
Collaborator Author

@BugBot run

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @wwwillchen, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a regression that caused incorrect URL restoration after an application restart, particularly when navigating back to the root path. The changes ensure that the application's internal state for preserved URLs is correctly cleared during root navigation and before restarts, providing a more predictable user experience.

Highlights

  • URL Preservation Fix: Corrected a regression where the previewCurrentUrlAtom was not cleared when navigating to the root path (/), leading to incorrect route restoration after a restart.
  • Navigation State Handling: Implemented logic within pushState and replaceState handlers to explicitly clear the preserved URL when the application navigates to its root.
  • Application Restart Behavior: Enhanced the restartApp function to ensure that any previously preserved URLs are cleared before an application restart, preventing stale routes from being loaded.
  • E2E Test Coverage: Added a new end-to-end test case to specifically verify that the application correctly stays on the root path after navigating back to root and then restarting.
  • Hook Disablement Option: Introduced an environment variable (DISABLE_DYAD_STOP_HOOK) to allow for disabling the .claude/hooks/stop-hook.py script.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively fixes a regression where the preserved URL was not cleared upon navigating to the root path or restarting the application. The changes in PreviewIframe.tsx and useRunApp.ts correctly handle clearing the stale URL. The addition of a new end-to-end test in restart.spec.ts is excellent as it verifies the fix and prevents future regressions. I have one suggestion to improve maintainability by addressing code duplication. Overall, this is a solid contribution.

Comment on lines +681 to 688
} else if (newUrlObj.origin === appUrlObj.origin) {
// Clear preserved URL when navigating back to root
setPreservedUrls((prev) => {
const next = { ...prev };
delete next[selectedAppId];
return next;
});
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

This logic for handling preserved URLs is also present in the pushState handler (lines 631-657). Duplicating this code block makes it harder to maintain, as future changes would need to be made in two places. Consider extracting this logic into a helper function within the useEffect hook to avoid repetition and ensure consistency between pushState and replaceState handling.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional flags.

Open in Devin Review

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 2, 2026

Greptile Overview

Greptile Summary

Fixed regression from PR #2336 where navigating back to root (/) didn't clear the preserved URL, causing the app to restore the wrong route after HMR/restart.

Changes:

  • PreviewIframe.tsx: Added else if blocks in both pushState and replaceState handlers to explicitly clear the preserved URL when pathname is / or empty. Also updated handleNavigateBack and handleNavigateForward to clear preserved URLs when navigating to root.
  • useRunApp.ts: Added preserved URL clearing in restartApp() before restarting the app to prevent stale route restoration.
  • restart.spec.ts: Added comprehensive E2E test that verifies the fix by navigating to /about, then back to /, then restarting and confirming root is loaded.
  • stop-hook.py: Added environment variable flag to disable the hook (unrelated infrastructure change).

The fix ensures that whenever a user navigates to the root path, the preserved URL is explicitly deleted from state, preventing incorrect route restoration during subsequent HMR or restart operations.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The changes are well-targeted bug fixes with comprehensive test coverage. The logic consistently handles root path detection across all relevant code paths (pushState, replaceState, navigation handlers, and restart). The E2E test validates the exact regression scenario.
  • No files require special attention

Important Files Changed

Filename Overview
e2e-tests/restart.spec.ts Added comprehensive E2E test that verifies preserved URL is cleared when navigating back to root, then restarting
src/components/preview_panel/PreviewIframe.tsx Fixed preserved URL clearing logic in pushState/replaceState handlers and navigation functions to properly clear when pathname is root
src/hooks/useRunApp.ts Added preserved URL clearing in restartApp to prevent stale route restoration after restart

Sequence Diagram

sequenceDiagram
    participant User
    participant PreviewIframe
    participant Router as React Router in iframe
    participant PreservedUrls as previewCurrentUrlAtom
    participant RestartApp as useRunApp.restartApp()

    Note over User,RestartApp: Scenario: Navigate to /about, then back to /, then restart

    User->>PreviewIframe: Navigate to /about
    Router->>PreviewIframe: postMessage: pushState with /about
    PreviewIframe->>PreviewIframe: Check: pathname !== "/" && pathname !== ""
    PreviewIframe->>PreservedUrls: Store /about for appId
    
    User->>PreviewIframe: Navigate back to /
    Router->>PreviewIframe: postMessage: pushState with /
    PreviewIframe->>PreviewIframe: Check: pathname === "/" or pathname === ""
    PreviewIframe->>PreservedUrls: Delete entry for appId (FIX)
    
    User->>PreviewIframe: Click Restart button
    PreviewIframe->>RestartApp: Call restartApp()
    RestartApp->>PreservedUrls: Delete entry for appId (FIX)
    RestartApp->>RestartApp: Stop and restart app
    
    Note over PreviewIframe,PreservedUrls: On component remount after restart
    PreviewIframe->>PreservedUrls: Check for preserved URL
    PreservedUrls-->>PreviewIframe: null (no preserved URL)
    PreviewIframe->>PreviewIframe: Load root URL /

Loading

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 4 files

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

@wwwillchen
Copy link
Copy Markdown
Collaborator Author

@BugBot run

@wwwillchen wwwillchen merged commit 92b9072 into dyad-sh:main Feb 2, 2026
4 of 5 checks passed
@wwwillchen wwwillchen deleted the fix-preserved-url-not-cleared-on-root-navigation branch February 2, 2026 18:23
@github-actions github-actions bot locked and limited conversation to collaborators Feb 2, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant