fix(frontend): add Tauri environment detection and safe API wrappers#432
Conversation
- Add isTauriEnvironment() function for environment detection - Create safe wrapper functions for Tauri APIs (invoke, dialog, updater, etc.) - Update useUpdater hook to check environment before calling Tauri APIs - Update FolderPicker components to use safe wrappers instead of direct imports - Add graceful fallbacks and user messaging for browser development mode - Fix TypeError: Cannot read properties of undefined errors in browser mode This enables frontend development in browser mode without crashes while maintaining full functionality in desktop Tauri mode. Fixes console errors when running 'npm run dev' in browser mode.
WalkthroughEnvironment detection for Tauri was introduced using a new utility function. Update and download logic in the updater hook, as well as window event handling in the main entry, now check for Tauri before invoking platform-specific APIs. A browser warning component was added to inform users when running outside Tauri. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant MainApp
participant TauriAPI
participant BrowserWarning
User->>MainApp: Load application
MainApp->>MainApp: Check isTauriEnvironment()
alt Tauri environment
MainApp->>TauriAPI: Import and use Tauri APIs
MainApp->>MainApp: Render main app UI
else Browser environment
MainApp->>BrowserWarning: Render warning message
end
Assessment against linked issues
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
@varunchitre15 @saisankargochhayat @heychirag @raghavpuri31 |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
frontend/src/utils/tauriUtils.ts (1)
43-43: Improve type safety with more specific parameter typesThe
optionsparameter and return types useanywhich reduces type safety. Consider using more specific interfaces or generic types.For better type safety, consider defining specific interfaces:
interface DialogOpenOptions { directory?: boolean; multiple?: boolean; title?: string; filters?: Array<{ name: string; extensions: string[] }>; defaultPath?: string; } interface DialogSaveOptions { title?: string; defaultPath?: string; filters?: Array<{ name: string; extensions: string[] }>; } export const safeTauriDialogOpen = async (options: DialogOpenOptions): Promise<string[] | string | null> => { // ... implementation }; export const safeTauriDialogSave = async (options: DialogSaveOptions): Promise<string | null> => { // ... implementation };Also applies to: 77-77, 93-93
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
frontend/src/components/FolderPicker/AITaggingFolderPicker.tsx(2 hunks)frontend/src/components/FolderPicker/FolderPicker.tsx(2 hunks)frontend/src/hooks/useUpdater.ts(3 hunks)frontend/src/main.tsx(2 hunks)frontend/src/utils/tauriUtils.ts(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
frontend/src/components/FolderPicker/AITaggingFolderPicker.tsx (1)
frontend/src/utils/tauriUtils.ts (2)
isTauriEnvironment(6-8)safeTauriDialogOpen(43-57)
frontend/src/components/FolderPicker/FolderPicker.tsx (1)
frontend/src/utils/tauriUtils.ts (2)
isTauriEnvironment(6-8)safeTauriDialogOpen(43-57)
frontend/src/hooks/useUpdater.ts (1)
frontend/src/utils/tauriUtils.ts (2)
isTauriEnvironment(6-8)safeTauriUpdaterCheck(27-40)
🔇 Additional comments (4)
frontend/src/main.tsx (1)
6-6: Well-implemented environment-aware initializationThe changes properly integrate the new Tauri utilities:
- Environment check prevents errors in browser mode
- Dynamic import avoids bundling issues
- Production + Tauri condition ensures proper initialization context
The implementation follows the established pattern consistently.
Also applies to: 13-25, 73-73
frontend/src/components/FolderPicker/FolderPicker.tsx (1)
3-3: Excellent user experience improvements for development modeThe changes properly handle both environment detection and user communication:
- Clear import of safe utilities
- Informative alert message guides developers on proper usage
- Early return prevents errors in browser mode
- Safe wrapper handles the dialog operation
Also applies to: 16-22
frontend/src/components/FolderPicker/AITaggingFolderPicker.tsx (1)
3-3: Consistent implementation across FolderPicker componentsThe changes mirror those in
FolderPicker.tsxand maintain consistency:
- Proper import of safe utilities
- Same user-friendly alert message
- Correct environment check and early return
- Safe wrapper usage for dialog operations
Also applies to: 17-23
frontend/src/hooks/useUpdater.ts (1)
2-3: Proper environment-aware update functionality implementationThe changes correctly implement the safe Tauri pattern:
- Clean imports of necessary utilities and types
- Environment checks in both update check and download functions
- Safe wrapper usage with proper error handling
- Informative console logging for debugging
The implementation ensures update functionality is only available in the appropriate Tauri desktop environment.
Also applies to: 37-44, 71-74
frontend/src/utils/tauriUtils.ts
Outdated
| export const safeTauriInvoke = async (command: string, args?: any): Promise<any> => { | ||
| if (!isTauriEnvironment()) { | ||
| console.warn(`Tauri command "${command}" is not available in browser mode`); | ||
| return null; | ||
| } | ||
|
|
||
| try { | ||
| const { invoke } = await import('@tauri-apps/api/core'); | ||
| return await invoke(command, args); | ||
| } catch (error) { | ||
| console.error(`Error invoking Tauri command "${command}":`, error); | ||
| throw error; | ||
| } | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Inconsistent error handling pattern across safe wrapper functions
The safeTauriInvoke function throws errors while other safe wrapper functions (like safeTauriUpdaterCheck) return null on errors. This inconsistency could lead to confusion and different error handling requirements across the codebase.
Consider standardizing the error handling approach. For safe wrapper functions, returning null on errors (as done in other functions) is more appropriate:
- } catch (error) {
- console.error(`Error invoking Tauri command "${command}":`, error);
- throw error;
- }
+ } catch (error) {
+ console.error(`Error invoking Tauri command "${command}":`, error);
+ return null;
+ }📝 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.
| export const safeTauriInvoke = async (command: string, args?: any): Promise<any> => { | |
| if (!isTauriEnvironment()) { | |
| console.warn(`Tauri command "${command}" is not available in browser mode`); | |
| return null; | |
| } | |
| try { | |
| const { invoke } = await import('@tauri-apps/api/core'); | |
| return await invoke(command, args); | |
| } catch (error) { | |
| console.error(`Error invoking Tauri command "${command}":`, error); | |
| throw error; | |
| } | |
| }; | |
| export const safeTauriInvoke = async (command: string, args?: any): Promise<any> => { | |
| if (!isTauriEnvironment()) { | |
| console.warn(`Tauri command "${command}" is not available in browser mode`); | |
| return null; | |
| } | |
| try { | |
| const { invoke } = await import('@tauri-apps/api/core'); | |
| return await invoke(command, args); | |
| } catch (error) { | |
| console.error(`Error invoking Tauri command "${command}":`, error); | |
| return null; | |
| } | |
| }; |
🤖 Prompt for AI Agents
In frontend/src/utils/tauriUtils.ts between lines 11 and 24, the safeTauriInvoke
function currently throws errors on failure, unlike other safe wrapper functions
that return null. To standardize error handling, modify safeTauriInvoke so that
instead of throwing the error in the catch block, it logs the error and returns
null. This will align its behavior with other safe wrapper functions and
simplify error handling across the codebase.
frontend/src/utils/tauriUtils.ts
Outdated
| export const safeTauriConvertFileSrc = (src: string): string => { | ||
| if (!isTauriEnvironment()) { | ||
| // In browser mode, return the src as-is or provide a fallback | ||
| return src; | ||
| } | ||
|
|
||
| try { | ||
| // Dynamic import to avoid errors in browser mode | ||
| const { convertFileSrc } = require('@tauri-apps/api/core'); | ||
| return convertFileSrc(src); | ||
| } catch (error) { | ||
| console.error('Error converting file src:', error); | ||
| return src; | ||
| } | ||
| }; |
There was a problem hiding this comment.
Replace require() with dynamic import for consistency
The safeTauriConvertFileSrc function uses require() instead of dynamic import, which is inconsistent with other functions and could cause bundling issues in browser environments.
Apply this diff to use dynamic import consistently:
- try {
- // Dynamic import to avoid errors in browser mode
- const { convertFileSrc } = require('@tauri-apps/api/core');
- return convertFileSrc(src);
- } catch (error) {
- console.error('Error converting file src:', error);
- return src;
- }
+ try {
+ const { convertFileSrc } = await import('@tauri-apps/api/core');
+ return convertFileSrc(src);
+ } catch (error) {
+ console.error('Error converting file src:', error);
+ return src;
+ }Note: This change requires making the function async:
-export const safeTauriConvertFileSrc = (src: string): string => {
+export const safeTauriConvertFileSrc = async (src: string): Promise<string> => {📝 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.
| export const safeTauriConvertFileSrc = (src: string): string => { | |
| if (!isTauriEnvironment()) { | |
| // In browser mode, return the src as-is or provide a fallback | |
| return src; | |
| } | |
| try { | |
| // Dynamic import to avoid errors in browser mode | |
| const { convertFileSrc } = require('@tauri-apps/api/core'); | |
| return convertFileSrc(src); | |
| } catch (error) { | |
| console.error('Error converting file src:', error); | |
| return src; | |
| } | |
| }; | |
| export const safeTauriConvertFileSrc = async (src: string): Promise<string> => { | |
| if (!isTauriEnvironment()) { | |
| // In browser mode, return the src as-is or provide a fallback | |
| return src; | |
| } | |
| try { | |
| const { convertFileSrc } = await import('@tauri-apps/api/core'); | |
| return convertFileSrc(src); | |
| } catch (error) { | |
| console.error('Error converting file src:', error); | |
| return src; | |
| } | |
| }; |
🤖 Prompt for AI Agents
In frontend/src/utils/tauriUtils.ts around lines 60 to 74, replace the use of
require() with a dynamic import to maintain consistency and avoid bundling
issues in browser environments. To fix this, make the function async and use
await import('@tauri-apps/api/core') to dynamically load convertFileSrc, then
return the converted source. Adjust the function signature to async and update
all call sites accordingly.
|
Hi @Aditya30ag, thank you for the PR. We are grateful that you took the time to contribute to this repository. In the future, after opening an issue, first discuss it with the maintainers. Discuss possible alternatives and solutions. After that, you start working on the coding part. This saves everyone's effort and time. About the PR: Let's have a simple message show up when someone accidentally opens the app in a browser. We do not need the safe functions. One simple thing you can do is to render the component in the main.tsx file, you can check if we are running inside a browser, and render a big <div> stating that we need to run the command npm run tauri dev. The issue is legit, but your approach is complicated. Although I appreciate the effort 😊 |
|
I completely understand your point about discussing the approach before jumping into the code — I’ll make sure to follow that process moving forward. Thanks for the heads-up! |
Thanks for understanding. You can start working on the simpler fix. |
|
Sure!! |
|
@rahulharpal1603 I’ve completed a few beginner issues — is there a more complex task you’d recommend I take up next? |
Hi, did you make the changes I suggested? |
|
ok |
|
Done |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
frontend/src-tauri/tauri.conf.json (1)
10-10: Dropping thedmgtarget may limit macOS distribution optionsRemoving
"dmg"keeps only the.appbundle, which cannot be easily code-signed & notarised for Gatekeeper and is awkward for end-users to drag into/Applications.
Unless you have explicit release requirements that exclude DMG, consider restoring it:- "targets": ["nsis", "deb", "app"], + "targets": ["nsis", "deb", "app", "dmg"],
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
frontend/src-tauri/tauri.conf.json(4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Tauri Tests
- GitHub Check: Tauri Build Check (windows-latest)
- GitHub Check: Backend Tests
- GitHub Check: Tauri Build Check (ubuntu-22.04)
- GitHub Check: Tauri Build Check (macos-latest, --target aarch64-apple-darwin)
🔇 Additional comments (2)
frontend/src-tauri/tauri.conf.json (2)
32-32: Ensure version bump stays consistent across all manifestsThe app version is now
0.1.0. Verify that:
•package.json→version
•src-tauri/Cargo.toml→version
match this value; mismatches break auto-update diffing and installer metadata.
39-42: Updater key / endpoint pair must match the signing processYou swapped the public key and moved to an org-scoped release feed.
- Confirm this base64 string is the Ed25519 public key produced by
tauri signer generate.- Check that releases in
AOSSIE-Org/PictoPyare signed with the matching private key, or users will receive “Signature verification failed” and the updater will silently abort.If you’re uncertain, regenerate and re-encrypt the key pair, then push only the public key.
| "minWidth": 1280, | ||
| "minHeight": 720, |
There was a problem hiding this comment.
Initial window size is smaller than the enforced minimum – this will fail at runtime
width: 800 / height: 600 < minWidth: 1280 / minHeight: 720.
Tauri delegates to winit, which panics if the initial size violates the minimum constraint.
Quick fix:
- "width": 800,
- "height": 600,
+ "width": 1280,
+ "height": 720,Or lower the min values to preserve the smaller default window.
📝 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.
| "minWidth": 1280, | |
| "minHeight": 720, | |
| "width": 1280, | |
| "height": 720, | |
| "minWidth": 1280, | |
| "minHeight": 720, |
🤖 Prompt for AI Agents
In frontend/src-tauri/tauri.conf.json around lines 51 to 52, the initial window
size is set smaller than the minimum allowed size, causing runtime failure. To
fix this, either increase the initial window width and height to at least 1280
and 720 respectively, or reduce the minWidth and minHeight values to be equal to
or smaller than the initial window size to avoid conflicts.
|
@Aditya30ag Please join the discord channel, all the discussions happen there. I first post the new tasks on the channel and if anyone wants them I assign them. https://discord.com/channels/1022871757289422898/1311271974630330388 |
|
there is some issue not visible the screen and it was not a network issue |
|
Go to Projects->PictoPy |


FIXED: #433
Implemented environment detection and safe API wrappers to ensure the application works seamlessly in both desktop and browser modes.
This enables frontend development in browser mode without crashes while maintaining full functionality in desktop Tauri mode.
Fixes console errors when running 'npm run dev' in browser mode.
Summary by CodeRabbit
New Features
Improvements