1.0.1 • Published 8 months ago
@riogz/router-plugin-browser v1.0.1
@riogz/router-plugin-browser
Browser integration plugin for @riogz/router. Provides seamless integration between the router and browser navigation, supporting both HTML5 history API and hash-based routing.
Features
- HTML5 History API Support - Modern pushState/replaceState navigation
- Hash-based Routing - Fallback for older browsers or specific requirements
- Base Path Support - Deploy apps in subdirectories
- State Preservation - Maintain router state in browser history
- SSR Compatible - Safe fallbacks for server-side rendering
- TypeScript Support - Full type definitions included
Installation
npm install @riogz/router-plugin-browserBasic Usage
import { createRouter } from '@riogz/router'
import browserPlugin from '@riogz/router-plugin-browser'
const routes = [
{ name: 'home', path: '/' },
{ name: 'users', path: '/users/:id' }
]
const router = createRouter(routes)
// Use the browser plugin
router.usePlugin(browserPlugin())
// Start the router
router.start()Configuration Options
BrowserPluginOptions
interface BrowserPluginOptions {
forceDeactivate?: boolean // Force route deactivation during transitions (default: true)
useHash?: boolean // Use hash-based routing (default: false)
hashPrefix?: string // Prefix after hash symbol (default: '')
base?: string | null // Base path for the application (default: '')
mergeState?: boolean // Merge with existing browser state (default: false)
preserveHash?: boolean // Preserve URL hash during navigation (default: true)
}Usage Examples
HTML5 History Mode (Default)
// URLs: /users/123, /profile, /settings
router.usePlugin(browserPlugin({
useHash: false
}))Hash-based Routing
// URLs: #/users/123, #/profile, #/settings
router.usePlugin(browserPlugin({
useHash: true
}))
// With prefix: #!/users/123, #!/profile, #!/settings
router.usePlugin(browserPlugin({
useHash: true,
hashPrefix: '!'
}))Application in Subdirectory
// URLs: /myapp/users/123, /myapp/profile
router.usePlugin(browserPlugin({
base: '/myapp'
}))State Merging
// Preserve additional properties in history.state
router.usePlugin(browserPlugin({
mergeState: true
}))
// Now you can add custom data to history
history.replaceState({
...history.state,
scrollPosition: window.scrollY,
customData: 'value'
}, '', location.href)Extended Router Methods
The plugin adds several methods to the router instance:
buildUrl(name, params)
Build a complete URL for a route:
// With base path and hash prefix
const url = router.buildUrl('users.profile', { id: '123' })
// Result: /myapp#!/users/123/profile (depending on config)matchUrl(url)
Match a complete URL against routes:
const state = router.matchUrl('https://example.com/users/123')
if (state) {
console.log(state.name) // 'users'
console.log(state.params) // { id: '123' }
}replaceHistoryState(name, params, title)
Update browser history without navigation:
// Update URL and history state without triggering route change
router.replaceHistoryState('users.profile', { id: '456' }, 'User Profile')Browser Abstraction
The plugin uses a browser abstraction layer that provides safe fallbacks for non-browser environments:
import browser from '@riogz/router-plugin-browser/browser'
// Safe to use in any environment
const currentPath = browser.getLocation({ useHash: false, base: '' })
browser.pushState({ name: 'home' }, 'Home', '/home')Testing
For testing, you can provide a mock browser implementation:
import browserPlugin from '@riogz/router-plugin-browser'
const mockBrowser = {
getBase: () => '/test',
pushState: jest.fn(),
replaceState: jest.fn(),
addPopstateListener: jest.fn(() => () => {}),
getLocation: () => '/current/path',
getState: () => null,
getHash: () => ''
}
router.usePlugin(browserPlugin({}, mockBrowser))Advanced Configuration
Custom Hash Prefix
// Google-style hash routing: #!/users/123
router.usePlugin(browserPlugin({
useHash: true,
hashPrefix: '!'
}))Preserve Hash Fragments
// Maintain #section anchors during navigation
router.usePlugin(browserPlugin({
preserveHash: true // default
}))
// Navigate from /page1#section1 to /page2#section1
router.navigate('page2')Force Route Deactivation
// Control route lifecycle during transitions
router.usePlugin(browserPlugin({
forceDeactivate: false // Allow routes to stay active when possible
}))Browser Compatibility
- Modern Browsers: Full HTML5 history API support
- Legacy Browsers: Automatic fallback to hash-based routing
- Internet Explorer: Special handling for hashchange events
- Server-Side Rendering: Safe no-op implementations
Error Handling
The plugin handles various error scenarios:
- Navigation Blocking: Respects route guards and canDeactivate hooks
- Invalid URLs: Graceful fallback to default routes
- State Conflicts: Prevents duplicate history entries
- Browser Limitations: Automatic detection and workarounds
Integration with Other Plugins
The browser plugin works seamlessly with other router plugins:
import browserPlugin from '@riogz/router-plugin-browser'
import loggerPlugin from '@riogz/router-plugin-logger'
router.usePlugin(browserPlugin())
router.usePlugin(loggerPlugin())TypeScript Support
Full TypeScript definitions are included:
import { BrowserPluginOptions, Browser, HistoryState } from '@riogz/router-plugin-browser'
const options: BrowserPluginOptions = {
useHash: true,
hashPrefix: '!'
}
const customBrowser: Browser = {
// Implementation
}API Reference
Types
- BrowserPluginOptions - Configuration options for the plugin
- Browser - Browser abstraction interface
- HistoryState - Extended router state with browser history data
Functions
- browserPluginFactory(options?, browser?) - Create a browser plugin instance
- default export - The browserPluginFactory function
License
MIT © Vyacheslav Krasnyanskiy