# Micro Frontend App _Path: en/frontend/micro-frontends/micro-frontend-app_ ## Table of Contents - Micro Frontend App () ## Content # Micro Frontend App (`view.page`) A Wippy micro frontend app is a Vue 3 SPA bundled into a standalone HTML artifact and loaded by the host inside an iframe. The iframe has no knowledge of the surrounding page — it communicates with the host exclusively through `@wippy-fe/proxy`. > **Isolation is mandatory.** The bundle has zero hardcoded assumptions about where it is served. `vite.config.ts` sets `base: ''`, no `outDir` is hardcoded in config, and the serving path is declared in the BE-side `view.page` registry entry — not in the package itself. The same built artifact ships unchanged to any Wippy instance. ## Project structure ``` my-app/ ├── package.json ├── app.html # HTML entry point (Vite input) ├── vite.config.ts ├── tsconfig.json ├── tailwind.config.ts # If using Tailwind ├── postcss.config.js # Required when using Tailwind └── src/ ├── app.ts # Bootstrap — @wippy-fe/proxy, Vue setup, mount ├── constants.ts # InjectionKey symbols ├── types.ts # HostApi / ProxyApiInstance type aliases ├── styles.css # Base styles (html, body, #app) ├── tailwind.css # @tailwind directives (if using Tailwind) ├── app/ │ └── app.vue # Root component (layout, router-view) ├── router/ │ └── index.ts # createAppRouter factory ├── pages/ # Route-level components ├── components/ # Shared/reusable components ├── composables/ # useHost(), useApi() (or import from @wippy-fe/proxy directly) ├── stores/ # Pinia stores └── types/ # Additional TypeScript types ``` Use kebab-case for all file names (`recent-sessions.vue`, `user-profile.vue`). ## `package.json` — the `wippy` block ```json { "name": "@myorg/app-my-dashboard", "version": "1.0.0", "specification": "wippy-component-1.0", "title": "My Dashboard", "description": "Dashboard application", "files": ["dist/", "src/", "package.json"], "dependencies": { "@wippy-fe/theme": "^0.0.34" }, "devDependencies": { "@wippy-fe/shared": "^0.0.34", "@wippy-fe/vite-plugin": "^0.0.34", "@wippy-fe/types-global-proxy": "^0.0.34", "@vitejs/plugin-vue": "^5.0.0", "autoprefixer": "^10.4.0", "postcss": "^8.4.0", "primevue": "^4.3.3", "tailwindcss": "3", "typescript": "^5.0.0", "vite": "^6.0.0", "vue": "^3.5.0", "vue-router": "^4.0.0", "vue-tsc": "^2.0.0" }, "peerDependencies": { "@iconify/vue": "^5.0.0", "@wippy-fe/pinia-persist": "^0.0.34", "@wippy-fe/proxy": "^0.0.34", "@wippy-fe/router": "^0.0.34", "axios": "^1.0.0", "luxon": "^3.5.0", "pinia": "^2.1.0", "vue": "^3.5.0", "vue-router": "^4.0.0" }, "wippy": { "type": "page", "title": "My Dashboard", "icon": "tabler:chart-bar", "order": 200, "path": "dist/app.html", "proxy": { "enabled": true, "injections": { "css": { "themeConfig": true, "iframe": true, "primevue": true, "markdown": true, "customCss": true, "customVariables": true }, "tailwindConfig": false, "resizeObserver": false, "preventLinkClicks": false, "iconifyIcons": false, "refreshWhenVisible": false } }, "scripts": { "build": "build", "debug": "build:debug" } }, "scripts": { "build": "vite build", "build:debug": "vite build --mode development", "dev": "vite build --watch" } } ``` ### Field reference | Field | Required | Description | |---|---|---| | `specification` | Yes | Must be `"wippy-component-1.0"`. Tells the platform this is a Wippy package. | | `wippy.type` | Yes | Must be `"page"` for micro frontend apps. | | `wippy.title` | Recommended | Display name shown in the host navigation menu. | | `wippy.icon` | Recommended | Tabler icon name (e.g. `"tabler:chart-bar"`). Used in navigation. | | `wippy.order` | Optional | Sort position in the navigation menu (lower = earlier). | | `wippy.path` | Yes | Path to the built HTML entry file, relative to the package root. Typically `"dist/app.html"`. | | `wippy.proxy.enabled` | Yes | Must be `true` for the host's proxy system to activate for this iframe. | | `wippy.proxy.injections` | Yes | Controls which CSS and behaviours the host injects into the iframe. | | `wippy.scripts.build` | Yes | Maps to the npm script name for production builds. | | `wippy.scripts.debug` | Recommended | Maps to the npm script name for development builds (with source maps). | **Package naming convention:** `@/-` where type is `app` for pages. Examples: `@acme/app-analytics-dashboard`, `@myorg/app-user-settings`. **Peer dependencies:** Libraries provided by the host via import map must be in `peerDependencies` and marked external in the bundler. Never bundle `vue`, `pinia`, `vue-router`, `@wippy-fe/proxy`, `axios`, `@iconify/vue`, `luxon`, `nanoevents`, or `@tanstack/vue-query`. ### Proxy injections The iframe proxy enables most injections when a package omits explicit settings. Page packages should still declare the values below deliberately; the table shows recommended explicit values for a Vite micro frontend app, not the runtime fallback defaults. | Key | Effect | Recommended explicit value | |---|---|---| | `css.themeConfig` | Injects CSS custom properties (`--p-primary-*`, `--p-surface-*`, etc.) | `true` | | `css.iframe` | Scrollbar and iframe layout styles | `true` | | `css.primevue` | PrimeVue component styles (unstyled mode) | `true` | | `css.markdown` | Styles for rendered markdown | `true` | | `css.customCss` | Host-level custom CSS overrides | `true` | | `css.customVariables` | Host-level CSS variable overrides | `true` | | `tailwindConfig` | Tailwind Play CDN runtime config | `false` | | `resizeObserver` | Reports body-size changes to the parent frame | `false` | | `preventLinkClicks` | Intercept `` clicks and route through host | `false` — enable if you don't implement a custom router | | `iconifyIcons` | Iconify icon data from host | `false` — set `true` if using Iconify CDN web component | ## `app.html` — the entry point Vite takes `app.html` as its build input. The file serves two purposes: it is the production iframe document after build, and it boots the app standalone during local development via `dev-proxy.js`. ```html My App
``` **The `data-role="@wippy/scripts"` attribute is the switchpoint.** When the host loads this page, it strips the ` ``` ## Host API — common calls The `host` object exposes platform-level actions. Use these in preference to browser APIs or PrimeVue service equivalents: ```typescript // Show a toast notification (preferred over PrimeVue ToastService — // toast renders in the parent frame, not clipped by the iframe bounds) host.toast({ severity: 'success', summary: 'Saved', detail: 'Changes saved.' }) // Confirmation dialog (preferred over PrimeVue ConfirmationService) const confirmed = await host.confirm({ message: 'Delete this item?', header: 'Confirm', icon: 'tabler:trash', }) // Navigate to a different host-level page (outside this app's router) host.navigate('/c/other-page-id') // Open a chat session in the sidebar host.startChat(agentToken, { sidebar: true }) // Associate context data with the current or a specific chat session host.setContext({ currentPage: 'dashboard', selectedItems: [1, 2] }, sessionUUID) // Sign the user out host.logout() ``` ## Pinia and state persistence Install Pinia in `app.ts` as shown above. To persist store state across iframe reloads (the iframe is destroyed and recreated on navigation in some host configurations), use `@wippy-fe/pinia-persist`. `@wippy-fe/pinia-persist` is **not** in the host import map. Bundle it — do not add it to `rollupOptions.external`. ```typescript // src/stores/my-store.ts import { defineStore } from 'pinia' import { ref } from 'vue' export const useMyStore = defineStore('my-store', () => { const items = ref([]) const selectedId = ref(null) return { items, selectedId } }, { wippyPersist: true, // Persist all state, scoped to this page's UUID }) ``` Options for `wippyPersist`: | Value | Behaviour | |---|---| | `true` | Persist all state keys, scoped to the current page UUID | | `{ pick: ['key1', 'key2'] }` | Persist only the listed keys | | `{ debounce: 500 }` | Debounce saves by 500 ms (useful for high-frequency updates) | | `{ scope: 'my-key' }` | Override the scope key (auto-prefixed with `@custom:`) | State is saved on store mutation (debounced), on `@visibility:false`, and on `window.unload`. It is hydrated asynchronously on store creation via `preloadWippyState()` called in `app.ts`. ## Listening to platform events Import `on` from `@wippy-fe/proxy` and call `on(pattern, callback)` to subscribe to platform events. The return value is an unsubscribe function — always call it in `onUnmounted`. ```vue ``` ## Example page component A minimal page that fetches data from the backend and renders a list: ```vue ``` `` and `` are custom elements registered by the host's `loading.js` script. They render themed fullscreen states and require no import. ## `src/app/app.vue` — root component The root component provides the application shell. `` renders the active page component. ```vue ``` Note that micro frontend apps control their full viewport — root-level padding on `
` is acceptable here, unlike web components where the host controls outer spacing. ## `src/styles.css` ```css html, body { height: 100%; margin: 0; background: transparent; } #app { height: 100%; } /* Iconify inline icon fallback size */ svg.iconify { display: inline-block; width: 1em; height: 1em; } ``` ## `wippy-meta.json` `wippyPagePlugin()` in `vite.config.ts` emits `dist/wippy-meta.json` next to `dist/app.html` on every build. This file is the canonical source of identity and presentation metadata for the views API. Do not hand-author it — let the plugin generate it. For `wippy/views` ≥ 0.5.0, this file is required. Without it the host falls back to a deprecated synthesis path and emits a deprecation warning per process. ## Testing without the host To develop and test the app without a running Wippy instance, use host-less mode. The `dev-proxy.js` script (referenced in `app.html`) installs the proxy runtime so `@wippy-fe/proxy` imports resolve, letting the app boot normally in a plain browser tab. See [host-less-mode.md](./host-less-mode.md) for setup, the dev-proxy stub contract, and patterns for testing components in isolation. ## Navigation Previous: Quickstart (frontend/micro-frontends/quickstart) Next: Web Component (frontend/micro-frontends/web-component)