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

wu-framework

v1.1.4

Published

πŸš€ Universal Microfrontends Framework - 8 frameworks, zero config, Shadow DOM isolation

Readme

πŸš€ Wu Framework

Universal Microfrontends Made Simple

Wu Framework es una librerΓ­a de microfrontends con Shadow DOM nativo, aislamiento CSS avanzado, y comunicaciΓ³n cross-MFE integrada.


✨ ¿Por qué Wu Framework?

| CaracterΓ­stica | Module Federation | Single-SPA | Qiankun | Wu Framework | |---|---|---|---|---| | Shadow DOM nativo | ❌ | ❌ | Parcial | βœ… Completo | | CSS Isolation Modes | Manual | Manual | BΓ‘sico | βœ… 4 modos | | fully-isolated mode | ❌ | ❌ | ❌ | βœ… Único | | Bloquea CSS Variables | ❌ | ❌ | ❌ | βœ… Único | | Framework Agnostic | Webpack only | βœ… | Vue-first | βœ… Cualquiera | | Bundler Agnostic | Webpack 5 | βœ… | Webpack | βœ… Vite/Webpack | | Cross-MFE Events | Manual | Manual | Props | βœ… Event Bus | | Cross-MFE Store | ❌ | ❌ | Parcial | βœ… Reactive Store |


πŸ›‘οΈ CSS Isolation Modes (Feature Único)

Wu Framework ofrece 4 modos de aislamiento CSS. El modo fully-isolated es ΓΊnico - bloquea incluso las CSS variables del padre:

// header/wu.json - Aislamiento total (bloquea CSS vars del padre)
{
  "name": "header",
  "entry": "src/main.ts",
  "styleMode": "fully-isolated",
  "wu": {
    "permissions": ["events", "store"]
  }
}
// container/wu.json - Aislamiento normal (hereda CSS vars)
{
  "name": "content",
  "folder": "container",
  "entry": "src/main.tsx",
  "styleMode": "isolated",
  "wu": {
    "permissions": ["events", "store"]
  }
}

| Modo | CSS Variables | Estilos Padre | Caso de Uso | |------|--------------|---------------|-------------| | isolated | βœ… Heredadas | ❌ Bloqueados | MFE usa design system del host | | fully-isolated | ❌ Bloqueadas | ❌ Bloqueados | MFE de terceros con su propio theme | | shared | βœ… Heredadas | βœ… Compartidos | MFE necesita estilos del host | | auto | βœ… Heredadas | ⚑ Solo librerΓ­as | Compartir Element Plus, etc. |


πŸ”₯ Quick Start

1. Shell (React + Vite)

// shell/src/config/mfe.config.ts
const isDev = import.meta.env.DEV

const devUrls = {
  header: 'http://localhost:3001',
  content: 'http://localhost:3003'
}

const prodUrls = {
  header: import.meta.env.VITE_HEADER_URL || 'https://cdn.example.com/mfe/header',
  content: import.meta.env.VITE_CONTENT_URL || 'https://cdn.example.com/mfe/content'
}

export const urls = isDev ? devUrls : prodUrls

export const enabledApps = [
  { name: 'header', url: urls.header, enabled: true },
  { name: 'content', url: urls.content, enabled: true }
]
// shell/src/hooks/useWuFramework.ts
import { useEffect, useState, useRef } from 'react'
import { wu } from 'wu-framework'
import { createUseWuEvents, createUseWuStore } from 'wu-framework/adapters/react'
import React from 'react'
import { enabledApps } from '../config/mfe.config'

// Crear hooks reactivos para el shell
export const useWuEvents = createUseWuEvents(React)
export const useWuStore = createUseWuStore(React)

export function useWuFramework() {
  const [state, setState] = useState({
    initialized: false,
    loading: true,
    error: null as Error | null
  })
  const initRef = useRef(false)

  useEffect(() => {
    if (initRef.current) return
    initRef.current = true

    const initWu = async () => {
      try {
        await wu.init({
          apps: enabledApps.map(({ name, url }) => ({ name, url }))
        })
        setState({ initialized: true, loading: false, error: null })
      } catch (error) {
        setState({ initialized: false, loading: false, error: error as Error })
      }
    }

    initWu()
  }, [])

  return { ...state, wu }
}
// shell/src/App.tsx
import { useWuFramework, useWuEvents } from './hooks/useWuFramework'
import WuSlot from './components/WuSlot'
import ToastContainer from './components/ToastContainer'

function App() {
  const { initialized, loading, error } = useWuFramework()
  const { emit } = useWuEvents()

  useEffect(() => {
    if (initialized) {
      emit('shell:ready', { timestamp: Date.now() })
    }
  }, [initialized, emit])

  if (loading) return <div>Loading Wu Framework...</div>
  if (error) return <div>Error: {error.message}</div>

  return (
    <>
      <ToastContainer />
      <WuSlot name="header" url={urls.header} />
      <WuSlot name="content" url={urls.content} />
    </>
  )
}

2. MFE Header (Vue 3)

// header/wu.json
{
  "name": "header",
  "entry": "src/main.ts",
  "styleMode": "fully-isolated",
  "wu": {
    "exports": {
      "NavBar": "src/components/NavBar.vue"
    },
    "permissions": ["events", "store"]
  }
}
// header/src/main.ts
import { createApp } from 'vue'
import { wuVue } from 'wu-framework/adapters/vue'
import App from './App.vue'

// Registrar con Wu Framework
wuVue.register('header', App, {
  standalone: true,
  standaloneContainer: '#app',
  onMount: (container) => console.log('[Header] Mounted:', container),
  onUnmount: (container) => console.log('[Header] Unmounted:', container)
})
<!-- header/src/components/NavBar.vue -->
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { useWuEvents, useWuStore } from 'wu-framework/adapters/vue'

const { emit, on } = useWuEvents()
const { state: notificationState, setState } = useWuStore('notifications')

const notificationCount = ref(0)
let unsubscribe: (() => void) | null = null

onMounted(() => {
  // Inicializar store compartido
  if (!notificationState.value) {
    setState({ count: 0, items: [] })
  }

  // Escuchar notificaciones desde CUALQUIER MFE (React, Angular, etc.)
  unsubscribe = on('notification:new', (event) => {
    notificationCount.value++

    // Actualizar store compartido
    const current = notificationState.value || { count: 0, items: [] }
    setState({
      count: current.count + 1,
      items: [...current.items, {
        id: Date.now(),
        message: event.data?.message,
        type: event.data?.type || 'info'
      }]
    })
  })
})

onUnmounted(() => {
  if (unsubscribe) unsubscribe()
})

const handleNavClick = (item: { id: string, label: string }) => {
  emit('header:nav:click', { id: item.id, label: item.label })
}
</script>

<template>
  <nav class="navbar">
    <button class="navbar__notifications" @click="emit('header:notifications:open')">
      πŸ””
      <span v-if="notificationCount > 0" class="navbar__badge">
        {{ notificationCount > 99 ? '99+' : notificationCount }}
      </span>
    </button>
  </nav>
</template>

3. MFE Content (React)

// container/wu.json
{
  "name": "content",
  "folder": "container",
  "entry": "src/main.tsx",
  "styleMode": "isolated",
  "wu": {
    "exports": {
      "Dashboard": "src/components/Dashboard.tsx"
    },
    "permissions": ["events", "store"]
  }
}
// container/src/main.tsx
import { wuReact } from 'wu-framework/adapters/react'
import App from './App'

wuReact.register('content', App, {
  strictMode: true,
  standalone: true,
  standaloneContainer: '#root',
  onMount: (container) => console.log('[Content] Mounted:', container),
  onUnmount: (container) => console.log('[Content] Unmounted:', container)
})
// container/src/components/Dashboard.tsx
import { useState } from 'react'
import { useWuEvents } from '../hooks/useWu'

export function Dashboard() {
  const { emit } = useWuEvents()
  const [sent, setSent] = useState(0)

  // Enviar notificaciΓ³n que el Header (Vue) y Shell (React) recibirΓ‘n
  const sendNotification = (type: 'success' | 'warning' | 'error' | 'info', message: string) => {
    emit('notification:new', { message, type })
    setSent(prev => prev + 1)
  }

  return (
    <div className="dashboard">
      <h2>Cross-MFE Communication Demo</h2>
      <p>Notifications sent: <strong>{sent}</strong></p>

      <div className="notification-buttons">
        <button onClick={() => sendNotification('success', 'Operation completed!')}>
          βœ… Success
        </button>
        <button onClick={() => sendNotification('warning', 'Check your settings')}>
          ⚠️ Warning
        </button>
        <button onClick={() => sendNotification('error', 'Something went wrong!')}>
          ❌ Error
        </button>
        <button onClick={() => sendNotification('info', 'New message received')}>
          πŸ’¬ Info
        </button>
      </div>
    </div>
  )
}

4. Toast Container (Shell - escucha eventos de MFEs)

// shell/src/components/ToastContainer.tsx
import { useState, useEffect, useCallback } from 'react'
import { useWuEvents } from '../hooks/useWuFramework'

interface Toast {
  id: string
  message: string
  type: 'success' | 'warning' | 'error' | 'info'
}

export function ToastContainer() {
  const [toasts, setToasts] = useState<Toast[]>([])
  const { on } = useWuEvents()

  const addToast = useCallback((message: string, type: Toast['type']) => {
    const id = `toast-${Date.now()}`
    setToasts(prev => [...prev, { id, message, type }])
    setTimeout(() => setToasts(prev => prev.filter(t => t.id !== id)), 5000)
  }, [])

  useEffect(() => {
    // Escuchar notificaciones de CUALQUIER MFE
    const unsubscribe = on('notification:new', (event) => {
      const { message, type } = event.data || {}
      if (message) addToast(message, type || 'info')
    })
    return () => unsubscribe?.()
  }, [on, addToast])

  return (
    <div className="toast-container">
      {toasts.map(toast => (
        <div key={toast.id} className={`toast toast--${toast.type}`}>
          {toast.message}
        </div>
      ))}
    </div>
  )
}

πŸ“‘ Cross-MFE Communication

Event Bus

import { emit, on, once, off } from 'wu-framework'

// React MFE emite
emit('notification:new', { message: 'Hello!', type: 'success' })

// Vue MFE escucha
const unsubscribe = on('notification:new', (event) => {
  console.log(event.data.message) // 'Hello!'
})

// Wildcards - escuchar todos los eventos de notificaciΓ³n
on('notification:*', (event) => {
  console.log('Event:', event.name, event.data)
})

// Una sola vez
once('app:ready', () => console.log('Ready!'))

// Limpiar
unsubscribe()

Store Reactivo

import { getState, setState, onStateChange, batchState } from 'wu-framework'

// Vue MFE escribe
setState('notifications.count', 5)
setState('user.theme', 'dark')

// React MFE lee
const count = getState('notifications.count') // 5

// Angular MFE se suscribe
const unsub = onStateChange('notifications.*', (value, path) => {
  console.log(`${path} changed:`, value)
})

// Batch updates
batchState({
  'user.name': 'John',
  'notifications.count': 0
})

Hooks por Framework

React:

import { createUseWuEvents, createUseWuStore } from 'wu-framework/adapters/react'

const useWuEvents = createUseWuEvents(React)
const useWuStore = createUseWuStore(React)

function MyComponent() {
  const { emit, on } = useWuEvents()
  const { state, setState } = useWuStore('notifications')

  useEffect(() => {
    return on('user:login', (e) => console.log(e.data))
  }, [])

  return <span>Count: {state?.count || 0}</span>
}

Vue:

<script setup>
import { useWuEvents, useWuStore } from 'wu-framework/adapters/vue'

const { emit, on } = useWuEvents()
const { state, setState } = useWuStore('cart')

onMounted(() => {
  on('cart:updated', (data) => console.log(data))
})
</script>

πŸ—οΈ Arquitectura

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     SHELL (React)                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  ToastContainer (escucha notification:new)           β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚  #shadow-root   β”‚            β”‚  #shadow-root       β”‚    β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚            β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚    β”‚
β”‚  β”‚  β”‚  Header   β”‚  β”‚  ──────▢   β”‚  β”‚   Content     β”‚  β”‚    β”‚
β”‚  β”‚  β”‚  (Vue)    β”‚  β”‚  events    β”‚  β”‚   (React)     β”‚  β”‚    β”‚
β”‚  β”‚  β”‚           β”‚  β”‚  ◀──────   β”‚  β”‚               β”‚  β”‚    β”‚
β”‚  β”‚  β”‚ πŸ”” badge  β”‚  β”‚  store     β”‚  β”‚ [Send Notif]  β”‚  β”‚    β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚            β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚    β”‚
β”‚  β”‚ fully-isolated  β”‚            β”‚  isolated           β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                      WU FRAMEWORK CORE                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚ EventBus β”‚ β”‚  Store   β”‚ β”‚StyleBridgeβ”‚ β”‚ Sandbox Pool β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Flujo de datos:

  1. React Dashboard (content) llama emit('notification:new', {...})
  2. Wu EventBus propaga a todos los suscriptores
  3. Vue NavBar (header) incrementa badge
  4. React ToastContainer (shell) muestra toast flotante
  5. Store compartido actualiza notifications.count

🎨 Adapters

| Framework | Adapter | Registro | |-----------|---------|----------| | βš›οΈ React | wuReact | wuReact.register('app', App) | | πŸ’š Vue 3 | wuVue | wuVue.register('app', App) | | πŸ…°οΈ Angular | wuAngular | wuAngular.register('app', AppModule) | | 🧑 Svelte | wuSvelte | wuSvelte.register('app', App) | | ⚑ Preact | wuPreact | wuPreact.register('app', App) | | πŸ’Ž Solid.js | wuSolid | wuSolid.register('app', App) | | πŸ”₯ Lit | wuLit | wuLit.register('app', MyElement) | | πŸ“¦ Vanilla | wuVanilla | wuVanilla.register('app', config) |


βš™οΈ Core Systems

| Sistema | DescripciΓ³n | |---------|-------------| | WuStyleBridge | Detecta estilos por puerto/carpeta, inyecta en Shadow DOM, genera reset de CSS vars | | WuSandbox | Proxy Sandbox para JS isolation, cleanup automΓ‘tico | | WuEventBus | Wildcards, replay, mΓ©tricas | | WuStore | Dot notation, wildcard subscriptions, batch | | WuCache | Cache de manifests y mΓ³dulos | | WuPerformance | Tiempos de mount/unmount, reportes | | WuErrorBoundary | Auto-retry, fallback UI | | WuPluginSystem | Lifecycle hooks, middleware |


πŸ“‹ API Reference

// Core
import { wu, init, mount, unmount, destroy } from 'wu-framework'

// Events
import { emit, on, once, off, replayEvents } from 'wu-framework'

// Store
import { getState, setState, onStateChange, batchState } from 'wu-framework'

// Performance
import { startMeasure, endMeasure, generatePerformanceReport } from 'wu-framework'

// Plugins
import { usePlugin, createPlugin, useHook } from 'wu-framework'

// Adapters
import { wuReact } from 'wu-framework/adapters/react'
import { wuVue } from 'wu-framework/adapters/vue'

πŸ“„ License

MIT License - Copyright (c) 2025 Wu Framework Team