
Security News
/Research
Popular node-ipc npm Package Infected with Credential Stealer
Socket detected malicious node-ipc versions with obfuscated stealer/backdoor behavior in a developing npm supply chain attack.
@ecopages/browser-router
Advanced tools
Client-side router for Ecopages with view transitions support
Client-side navigation and view transitions for Ecopages. Intercepts same-origin link clicks to provide smooth page transitions without full page reloads.
<a> clicks for fast navigationdata-eco-persist are never recreated, preserving internal stateeco:before-swap, eco:after-swap, eco:page-loadThis package works with MPA-style rendering (KitaJS, Lit, vanilla JS) where the server returns full HTML pages.
Not compatible with React/Preact - These frameworks manage their own virtual DOM and component trees. Replacing the DOM breaks hydration, state, and event handlers. For React apps, use a framework-specific routing solution.
Component-level islands are a narrower case: small interactive roots emitted by another integration (for example a React island inside an otherwise MPA-style page) can work with @ecopages/browser-router, because ownership stays scoped to the island root instead of the full document.
bunx jsr add @ecopages/browser-router
Create and start the router in a global client-side script (e.g., src/layouts/base-layout.script.ts).
Important: Ensure the router script is injected in a consistent order within the
<head>across all pages. Inconsistent ordering (e.g. script between styles on one page but after on another) causesmorphdomto reload styles, leading to a "Flash of Unstyled Content" (FOUC).
import { createRouter } from '@ecopages/browser-router/client';
// Creates and starts the router with default options
const router = createRouter();
With custom options:
import { createRouter } from '@ecopages/browser-router/client';
const router = createRouter({
viewTransitions: true,
scrollBehavior: 'auto',
});
| Option | Type | Default | Description |
|---|---|---|---|
linkSelector | string | 'a[href]' | Selector for links to intercept |
persistAttribute | string | 'data-eco-persist' | Attribute to mark elements for DOM persistence |
reloadAttribute | string | 'data-eco-reload' | Attribute to force full page reload |
updateHistory | boolean | true | Whether to update browser history |
scrollBehavior | 'top' | 'preserve' | 'auto' | 'top' | Scroll behavior after navigation |
viewTransitions | boolean | false | Use View Transition API for animations |
smoothScroll | boolean | false | Use smooth scrolling during navigation |
Mark elements to preserve across navigations. These elements are never recreated during navigation, morphdom skips them entirely, preserving their internal state (event listeners, web component state, form values, etc.):
<!-- This counter keeps its state across all navigations -->
<radiant-counter data-eco-persist="counter"></radiant-counter>
To force a script to re-execute on every navigation (e.g. analytics, hydration), add data-eco-rerun and data-eco-script-id:
<script data-eco-rerun="true" data-eco-script-id="analytics">
// This runs on every navigation
trackPageview();
</script>
@ecopages/browser-routerWhen @ecopages/browser-router is used in an MPA-style app that also renders component-level React islands:
eco:after-swapdata-eco-script-id metadatadata-eco-rerun allows those bootstraps to be re-executed safely during head reconciliationThis note is specific to DOM-swapping navigation with @ecopages/browser-router. It does not apply to full React applications using @ecopages/react-router, where page routing and hydration are handled by the React router runtime itself.
Use data-eco-reload to force a full page reload:
<a href="/logout" data-eco-reload>Logout</a>
Listen to navigation lifecycle events:
document.addEventListener('eco:before-swap', (e) => {
console.log('Navigating to:', e.detail.url);
// Call e.detail.reload() to abort and do full reload
});
document.addEventListener('eco:after-swap', (e) => {
console.log('Swapped to:', e.detail.url);
});
document.addEventListener('eco:page-load', (e) => {
console.log('Page loaded:', e.detail.url);
});
import { createRouter } from '@ecopages/browser-router/client';
const router = createRouter();
// Navigate with pushState
await router.navigate('/new-page');
// Navigate with replaceState
await router.navigate('/new-page', { replace: true });
FAQs
Client-side router for Ecopages with view transitions support
The npm package @ecopages/browser-router receives a total of 990 weekly downloads. As such, @ecopages/browser-router popularity was classified as not popular.
We found that @ecopages/browser-router demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
/Research
Socket detected malicious node-ipc versions with obfuscated stealer/backdoor behavior in a developing npm supply chain attack.

Security News
TeamPCP and BreachForums are promoting a Shai-Hulud supply chain attack contest with a $1,000 prize for the biggest package compromise.

Security News
Packagist urges PHP projects to update Composer after a GitHub token format change exposed some GitHub Actions tokens in CI logs.