npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@modular-vue/vue

v1.4.1

Published

Vue 3 bindings for @modular-frontend/core: store composables, scoped stores, and injection-key contexts for modules, navigation, and slots.

Readme

@modular-vue/vue

Vue 3 bindings for @modular-frontend/core: store composables, scoped stores, and injection-key contexts for modules, navigation, and slots. This is the Vue analog of @modular-react/react and the first package of the Vue support initiative (PR-10).

Status: 0.x, pre-1.0. The API tracks the React binding case-for-case and will stay 0.x until the parity audit (PR-42).

What's here (PR-10 scope: stores and context)

  • Shared-dependency composablescreateSharedComposables<TDeps>() returns useStore, useService, useReactiveService, and useOptional, the Vue analogs of the React binding's createSharedHooks. Reactive accessors return a Ref; plain services return the value directly.
  • Scoped storescreateScopedStore(initializer) with a useScoped composable, for per-entity state.
  • Contexts — typed InjectionKeys plus provide* helpers and use* composables for the modules list (useModules, getModuleMeta), the navigation manifest (useNavigation), and slot contributions (useSlots, useReactiveSlots, useRecalculateSlots, DynamicSlotsProvider, createSlotsSignal).
  • Subject-keyed panelsusePanels (a reactive computed over the slots source + subject), <PanelsOutlet> (renders every matching panel, ordered, subject injected as a prop and via provide, each in a ModuleErrorBoundary, with #empty / #wrap slots), and usePanelSubject / panelSubjectKey for reading the injected subject reactively in panel bodies. This is the Vue host over the framework-neutral engine (definePanelGroup / resolvePanels, re-exported from @modular-vue/core); mind the Vue reactivity caveat when a when predicate reads non-reactive state. See docs/subject-panels.md.

Slot evaluation: reactive vs signal

Two ways to read the resolved slots, chosen per source:

  • useReactiveSlots() returns the slots as a computed, re-evaluated automatically when the reactive state its factories/filter read changes. Use it when the gating inputs are Vue-reactive state the host owns (RBAC permissions, availability flags).
  • useSlots() + useRecalculateSlots() is the framework-neutral signal path: a Ref that re-evaluates only on an explicit recalculateSlots(). Use it for non-reactive/external sources, transactional recompute, or event-driven invalidation.

Full tradeoffs and the RBAC-gating shape: Reactive slots in Vue.

Rendering pieces (lazy entry resolution, module host/exit, error capture) land in PR-11; the runtime plugin that installs these contexts lands with the @modular-vue/* family.

Store bridge

Composables wrap a framework-neutral Store<T> (or ReactiveService<T>) in a shallowRef and push snapshots into it from the store's subscribe callback — the Vue analog of React's useSyncExternalStore. Subscriptions are torn down on onScopeDispose (component unmount), so there is no listener leak. shallowRef dedupes by Object.is, which gives selector equality: re-selecting the same value from an unrelated update does not wake watchers.

Pinia interop — createPiniaStoreAdapter

createPiniaStoreAdapter(store) presents a Pinia store behind the neutral Store<T> contract (getState / getInitialState / setState / subscribe), so a Pinia store can fill a registry-owned store / reactive-service DI slot — the same slot a zustand or built-in createStore store fills — instead of running a parallel state layer. It caches a shallow snapshot and refreshes it from a synchronous $subscribe, so consumers see a fresh snapshot identity per change (the signal useSyncExternalStore / storeRef need). Structural store shape — no pinia dependency; you pass the store in.

Example

// In @myorg/app-shared:
import { createSharedComposables } from "@modular-vue/vue";
import type { AppDependencies } from "@myorg/app-shared";

export const { useStore, useService, useReactiveService, useOptional } =
  createSharedComposables<AppDependencies>();
<script setup lang="ts">
import { useStore, useService } from "@myorg/app-shared";

const user = useStore("auth", (s) => s.user); // Ref → reactive
const api = useService("httpClient"); // plain service → static
</script>

<template>
  <p>Signed in as {{ user }}</p>
</template>

Troubleshooting

  • Duplicate vue-router instances — if vue-tsc reports RouteRecordRaw "not assignable to" RouteRecordRaw (same version, different import path), your app resolved two copies of vue-router. That doc explains why (vue-router 5's optional vite peer) and how to dedupe with a one-line override.