Skip to content

feat: reloadApplication for JS bundle restart without restarting app process#384

Open
NathanWalker wants to merge 1 commit into
mainfrom
feat/reload-app
Open

feat: reloadApplication for JS bundle restart without restarting app process#384
NathanWalker wants to merge 1 commit into
mainfrom
feat/reload-app

Conversation

@NathanWalker

@NathanWalker NathanWalker commented Jun 7, 2026

Copy link
Copy Markdown
Contributor
NativeScriptRuntime.reloadApplication()

Helpful for programmatic reset of JS isolate for clean restart of JS application as well as OTA (over-the-air) updates without restarting the entire app process.

NativeScript/NativeScript#11261

Summary by CodeRabbit

  • New Features

    • Added a new NativeScriptRuntime API for reloading the app at runtime.
    • Exposed a JavaScript-accessible reloadApplication(baseDir?) method, with optional base directory support.
    • Reload now preserves the current runtime configuration when restarting the app.
  • Bug Fixes

    • Improved reload handling so the app restarts asynchronously and reports whether reload was successfully scheduled.

…process

Helpful for programmatic reset of JS isolate for clean restart of JS application as well as OTA (over-the-air) updates without restarting the entire app process.
@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds a reload path exposed from JavaScript to Objective-C. It stores the active runtime/configuration, registers a JS hook for reloadApplication(baseDir?), and restarts the application asynchronously on the main queue from the saved configuration.

Changes

Runtime reload flow

Layer / File(s) Summary
Reload API declarations
NativeScript/NativeScript.h, NativeScript/runtime/Runtime.h
NativeScriptRuntime gains reloadApplication overloads, and tns adds the reload hook type and declarations.
JS global hook wiring
NativeScript/runtime/Runtime.h, NativeScript/runtime/Runtime.mm
Runtime::Init calls DefineNativeScriptRuntime, and Runtime adds NativeScriptRuntime.reloadApplication(baseDir?) plus reload hook APIs.
Native reload restart
NativeScript/NativeScript.mm
The active runtime and copied config are stored during initialization, the JS hook is bridged to Objective-C, and reload restarts the app on the main queue from the saved config.

Sequence Diagram(s)

sequenceDiagram
  participant JS as global.NativeScriptRuntime.reloadApplication(baseDir?)
  participant InvokeHook as tns::InvokeReloadApplicationHook
  participant ObjC as +[NativeScriptRuntime reloadApplication:]
  participant MainQueue as dispatch_async(main queue)

  JS->>InvokeHook: pass optional baseDir
  InvokeHook->>ObjC: forward NSString* or nil
  ObjC->>MainQueue: schedule restart with copied Config
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

A bunny taps the reload drum,
Then hops to see the new app come.
With baseDir tucked in paw so neat,
The runtime spins on nimble feet.
Hooray—my whiskers twitch with glee! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the new reloadApplication support for restarting the JS bundle without restarting the app process.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/NativeScript/ios/issues/comments/4644319910","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- review_stack_entry_start -->\n\n[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/NativeScript/ios/pull/384?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)\n\n<!-- review_stack_entry_end -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> <details>\n> <summary>⚙️ Run configuration</summary>\n> \n> **Configuration used**: Repository UI\n> \n> **Review profile**: CHILL\n> \n> **Plan**: Pro\n> \n> **Run ID**: `7e5e1d22-c25d-42ab-b77f-3fcaea2ea84b`\n> \n> </details>\n> \n> <details>\n> <summary>📥 Commits</summary>\n> \n> Reviewing files that changed from the base of the PR and between debf7f8893e2cd5553cd70d5b866a697c10ed746 and 1d7f9d2a7a8d6fd0e046d725b7006a47f3ab3fc4.\n> \n> </details>\n> \n> <details>\n> <summary>📒 Files selected for processing (4)</summary>\n> \n> * `NativeScript/NativeScript.h`\n> * `NativeScript/NativeScript.mm`\n> * `NativeScript/runtime/Runtime.h`\n> * `NativeScript/runtime/Runtime.mm`\n> \n> </details>\n> \n> ```ascii\n>  ____________________________________________\n> < Your function signature is a cry for help. >\n>  --------------------------------------------\n>   \\\n>    \\   \\\n>         \\ /\\\n>         ( )\n>       .( o ).\n> ```\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>📝 Generate docstrings</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> Create stacked PR\n- [ ] <!-- {\"checkboxId\": \"3e1879ae-f29b-4d0d-8e06-d12b7ba33d98\"} --> Commit on current branch\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=NativeScript/ios&utm_content=384)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n\n<sub>Comment `@coderabbitai help` to get the list of available commands.</sub>\n\n<!-- tips_end -->"},"request":{"retryCount":3,"signal":{},"retries":3,"retryAfter":16}}}

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@NativeScript/NativeScript.mm`:
- Around line 182-184: The reload path in NativeScript’s restart flow still
carries over the process-global jsErrorOccurred flag, which can make the next
bundle start in the old debug error loop. Update the restart sequence around
currentNativeScript restartWithConfig: and runMainApplication to clear or
reinitialize jsErrorOccurred before launching the new isolate, so a fresh reload
starts from a clean JS error state.

In `@NativeScript/runtime/Runtime.mm`:
- Around line 577-588: Serialize access to the process-global
reloadApplicationHook_ used by SetReloadApplicationHook and
InvokeReloadApplicationHook: protect both reads and writes with synchronization
so initialization and concurrent JavaScript-thread calls cannot race. Update
InvokeReloadApplicationHook to copy the current hook under the lock, then
release the lock before invoking it so user code runs outside the critical
section and avoids deadlocks or lock contention.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7e5e1d22-c25d-42ab-b77f-3fcaea2ea84b

📥 Commits

Reviewing files that changed from the base of the PR and between debf7f8 and 1d7f9d2.

📒 Files selected for processing (4)
  • NativeScript/NativeScript.h
  • NativeScript/NativeScript.mm
  • NativeScript/runtime/Runtime.h
  • NativeScript/runtime/Runtime.mm

Comment on lines +182 to +184
dispatch_async(dispatch_get_main_queue(), ^{
[currentNativeScript restartWithConfig:config];
[currentNativeScript runMainApplication];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Reset stale JS error state before starting the new bundle.

jsErrorOccurred is process-global and survives reloads. After a previous debug error, the new runMainApplication can enter the debug error loop even if the reload was meant to provide a clean isolate restart.

Proposed fix
   dispatch_async(dispatch_get_main_queue(), ^{
+    tns::jsErrorOccurred = false;
     [currentNativeScript restartWithConfig:config];
     [currentNativeScript runMainApplication];
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
dispatch_async(dispatch_get_main_queue(), ^{
[currentNativeScript restartWithConfig:config];
[currentNativeScript runMainApplication];
dispatch_async(dispatch_get_main_queue(), ^{
tns::jsErrorOccurred = false;
[currentNativeScript restartWithConfig:config];
[currentNativeScript runMainApplication];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@NativeScript/NativeScript.mm` around lines 182 - 184, The reload path in
NativeScript’s restart flow still carries over the process-global
jsErrorOccurred flag, which can make the next bundle start in the old debug
error loop. Update the restart sequence around currentNativeScript
restartWithConfig: and runMainApplication to clear or reinitialize
jsErrorOccurred before launching the new isolate, so a fresh reload starts from
a clean JS error state.

Comment on lines +577 to +588
static ReloadApplicationHook reloadApplicationHook_;

void SetReloadApplicationHook(ReloadApplicationHook hook) {
reloadApplicationHook_ = std::move(hook);
}

bool InvokeReloadApplicationHook(const std::string& baseDir) {
if (!reloadApplicationHook_) {
return false;
}
return reloadApplicationHook_(baseDir);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all reload hook access sites and whether they can be reached from runtime initialization / JS callbacks.
rg -n -C4 '\b(SetReloadApplicationHook|InvokeReloadApplicationHook|DefineNativeScriptRuntime)\b' NativeScript

Repository: NativeScript/ios

Length of output: 5712


🏁 Script executed:

#!/bin/bash
# Check if <mutex> is included in Runtime.mm
head -50 NativeScript/runtime/Runtime.mm | rg "include.*mutex"

Repository: NativeScript/ios

Length of output: 171


Serialize access to the global reload hook.

reloadApplicationHook_ is a process-global std::function modified by SetReloadApplicationHook during initialization while InvokeReloadApplicationHook may be called concurrently from JavaScript execution threads. Read and write access must be synchronized, and the hook invocation must occur outside the lock to prevent deadlocks or holding locks during user code execution.

Proposed fix
 static ReloadApplicationHook reloadApplicationHook_;
+static std::mutex reloadApplicationHookMutex_;
 
 void SetReloadApplicationHook(ReloadApplicationHook hook) {
+  std::lock_guard<std::mutex> lock(reloadApplicationHookMutex_);
   reloadApplicationHook_ = std::move(hook);
 }
 
 bool InvokeReloadApplicationHook(const std::string& baseDir) {
-  if (!reloadApplicationHook_) {
+  ReloadApplicationHook hook;
+  {
+    std::lock_guard<std::mutex> lock(reloadApplicationHookMutex_);
+    hook = reloadApplicationHook_;
+  }
+  if (!hook) {
     return false;
   }
-  return reloadApplicationHook_(baseDir);
+  return hook(baseDir);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static ReloadApplicationHook reloadApplicationHook_;
void SetReloadApplicationHook(ReloadApplicationHook hook) {
reloadApplicationHook_ = std::move(hook);
}
bool InvokeReloadApplicationHook(const std::string& baseDir) {
if (!reloadApplicationHook_) {
return false;
}
return reloadApplicationHook_(baseDir);
}
static ReloadApplicationHook reloadApplicationHook_;
static std::mutex reloadApplicationHookMutex_;
void SetReloadApplicationHook(ReloadApplicationHook hook) {
std::lock_guard<std::mutex> lock(reloadApplicationHookMutex_);
reloadApplicationHook_ = std::move(hook);
}
bool InvokeReloadApplicationHook(const std::string& baseDir) {
ReloadApplicationHook hook;
{
std::lock_guard<std::mutex> lock(reloadApplicationHookMutex_);
hook = reloadApplicationHook_;
}
if (!hook) {
return false;
}
return hook(baseDir);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@NativeScript/runtime/Runtime.mm` around lines 577 - 588, Serialize access to
the process-global reloadApplicationHook_ used by SetReloadApplicationHook and
InvokeReloadApplicationHook: protect both reads and writes with synchronization
so initialization and concurrent JavaScript-thread calls cannot race. Update
InvokeReloadApplicationHook to copy the current hook under the lock, then
release the lock before invoking it so user code runs outside the critical
section and avoids deadlocks or lock contention.

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.

1 participant