feat: add support for custom router state serializer
This PR adds support for custom router state serializers to both provideGlobalRouterStore and provideLocalRouterStore, bringing feature parity with @ngrx/router-store.
Problem
As noted in the comparison documentation, Router Component Store previously used a serializer similar to MinimalRouterStateSerializer but did not support custom router state serializers, unlike NgRx Router Store which supports this through a serializer setting.
Solution
This implementation adds:
Core API
-
Generic
RouterStateSerializer<T>interface - Allows custom serializers with type safety -
ROUTER_STATE_SERIALIZERinjection token - Enables dependency injection of custom serializers -
RouterStoreConfig<T>interface - Configuration object for provider functions
Provider Updates
Both provider functions now accept an optional configuration parameter:
// Global router store with custom serializer
providers: [
provideGlobalRouterStore({ serializer: CustomRouterStateSerializer })
]
// Local router store with custom serializer
@Component({
providers: [provideLocalRouterStore({ serializer: CustomRouterStateSerializer })]
})
export class MyComponent { }
Example Custom Serializer
@Injectable()
export class CustomRouterStateSerializer implements RouterStateSerializer<MinimalRouterStateSnapshot> {
serialize(routerState: RouterStateSnapshot): MinimalRouterStateSnapshot {
return {
root: this.serializeRoute(routerState.root),
url: '/custom' + routerState.url, // Custom URL transformation
};
}
private serializeRoute(route: ActivatedRouteSnapshot): MinimalActivatedRouteSnapshot {
// Custom serialization logic
}
}
Backward Compatibility
✅ Zero breaking changes - All existing code continues to work unchanged. When no custom serializer is provided, the default MinimalRouterStateSerializer is used automatically.
Use Cases
This feature enables:
- URL Transformation: Modify URLs before storage (e.g., adding prefixes, normalization)
- Data Enrichment: Add timestamps, user context, or metadata to router state
- Filtering: Remove sensitive information from router state
- Custom State Structures: Create specialized state formats for specific needs
Testing
- Added comprehensive test suite with 7 new test cases covering all scenarios
- All existing tests continue to pass (264 total tests)
- Includes tests for both global and local router stores with custom serializers
- Verifies default behavior when no custom serializer is provided
Documentation
- Updated README with detailed examples and usage patterns
- Updated comparison documentation to reflect new feature parity with NgRx Router Store
- Added important notes about type safety and compatibility requirements
This brings Router Component Store to full feature parity with @ngrx/router-store regarding custom serialization while maintaining the lightweight, type-safe approach that makes it an excellent alternative to both NgRx Router Store and ActivatedRoute.
Original prompt
This section details on the original issue you should resolve
<issue_title>Add support for custom serializer and custom router state type</issue_title> <issue_description>The current ngrx router-store supports provofing a custom state serializer and working with a custom state type. router-component-store should support this too.</issue_description>
Comments on the Issue (you are @copilot in this section)
@LayZeeDK Thank you for your feature request. What's a use case for this?@LayZeeDK I'm not very familiar with `@ngrx/router-store` but from what I can read, a router state serializer is used to extract more slices of state from `RouterStateSnapshot`, correct?@LayZeeDK I'm not sure how adding this is better than subscribing to the `RouterState` through the `Router` and mapping using observable operators. That seems to be a lot easier than implementing a router serializer.In NgRx RouterStore this functionality was added to support Redux Dev Tools. Currently, NgRx ComponentStore doesn't have native support for Redux Dev Tools.</comment_new> <comment_new>
Even if we were to add it, I worry it would increase the bundle size significantly even for the xx% of applications never using this feature.</comment_new>@LayZeeDK
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.