Skip to content

Feature: Electron Support with Path Routing #31

@webJose

Description

@webJose

🚀 Feature: Electron Support with Path Routing

Note

It seems that macOS might be working OK after the first navigation. Is Linux working OK-ish as well? Is the lingering of the drive letter only a problem on Windows?

Problem Description

Currently, @wjfe/n-savant works perfectly in Electron with hash routing, but path routing fails in production builds due to how Electron handles file:// protocol URLs.

Development (works fine):

  • URL: http://localhost:5173/about
  • Router matches: ✅ /about

Electron Production (fails):

  • Initial load: file:///C:/Users/.../app.asar/dist/index.html
  • After navigation: file:///C:/about
  • Router tries to match: ❌ /C:/about (should be /about)

Root Cause

When using file:// protocol, the History API retains OS-specific path segments:

  • Windows: /C:/about (drive letter persists)
  • macOS: file:///about (so, working OK?)
  • Linux: Unknown situation, but most likely same as macOS

Proposed Solution

Add two new configuration options to init():

init({
  implicitMode: 'path',
  fullHomePath: '/C:/Users/.../app.asar/dist/index.html', // Maps to "/"
  persistentRoot: '/C:' // Stripped from all other paths
})

Router Logic:

If location.pathname === fullHomePath → treat as "/"
For all other paths → strip persistentRoot prefix
Maybe: Internal navigation → prepend persistentRoot to maintain consistency

What's Needed Outside this Package

Use OS helper functions to determine the values that should be placed in fullHomePath and persistentRoot options.

Prototypes:

getPersistentPathRoot: () => {
  if (process.platform === 'win32') {
    // Use actual current directory to get real drive
    const drive = path.parse(process.cwd()).root
    return `/${drive.charAt(0)}:` // Extract just the drive letter
  } else {
    // Use actual home directory to detect the real path structure
    const homeRoot = path.parse(os.homedir()).dir.split('/')[1]
    return `/${homeRoot}` // Could be "/Users", "/home", or something else
  }
}
// For Electron file:// protocol support:
getInitialHomePath: () => {
  const basePath = window.location.pathname.substring(0, 
    window.location.pathname.lastIndexOf('/') + 1)
}

This probably warrants the creation of a companion NPM Package, @wjfe/n-savant-electron, which can be used in the preload secure context:

// preload.cts

// Say, we export a function that returns both pieces at the same time.
import { getElectronRoutingPaths } from '@wjfe/n-savant-electron'

contextBridge.exposeInMainWorld('electronAPI', {
  routing: getElectronRoutingPaths()
})

Then, in main.ts on the web side, we do:

init({
  implicitMode: 'path',
  ...window.electronAPI?.routing
})

Benefits
✅ Perfect DX - One-liner setup for Electron users
✅ Cross-platform - Works on Windows, Linux, macOS
✅ Zero breaking changes - Purely additive feature
✅ Clean separation - Core router stays framework agnostic
✅ Path routing in Electron - No need to fall back to hash routing

Alternative Considered

Using hash routing works, and since multi-hash routing would also work just fine, this is purely a superfluous need.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ElectronElectron-specificPriority: MediumMedium priority. Upvote to request a higher priority. Downvote to attempt to lower priority.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions