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

@ticatec/uniface-micro-frame

v5.0.2

Published

A powerful micro-frontend framework built on Svelte 5 for developing modular web applications with iframe-based architecture

Readme

Uniface Micro Frame

npm version License: MIT

A micro-frontend framework built on Svelte 5, designed for modular web applications with an iframe-based architecture. Runs inside an iframe and provides hash routing, a stack-based page manager, an optional multi-tab shell, and pre-built page layouts.

Requires Svelte ^5.0.0, @ticatec/uniface-element ^5.0.0, and @ticatec/i18n ^0.5.0 (see Peer dependencies).

Overview

  • Iframe-based runtime — each sub-app is isolated in its own frame
  • Hash routinglocation.hash → lazy-loaded Svelte component
  • Stack-based pages — modal-style push/pop via AppModule.showPage / closeActivePage
  • Multi-tab shell — parallel sub-apps under a tab strip (each tab is its own iframe)
  • Pre-built page shellsCommonPage / CommonFormPage wrapping the lower-level Page
  • Global UI singletonsDialog, MessageBox and Indicator are self-mounting: each controller lazily mounts its own panel into document.body the first time you call show()/showInfo(), so HomePage doesn't need to render a board for any of them. Tooltip is the one exception — it has no controller of its own (just a global mouseover listener), so HomePage still renders <Tooltip/> once
  • TypeScript-first — full type definitions for every public API

Installation

pnpm add @ticatec/uniface-micro-frame

Quick Start

1. Define routes and (optional) module initialization

import HomePage from '@ticatec/uniface-micro-frame';
import type { ModuleInitialize } from '@ticatec/uniface-micro-frame';

const routes = {
  '/':            () => import('./components/Dashboard.svelte'),
  '/users':       () => import('./components/UserList.svelte'),
  '/users/:id':   () => import('./components/UserDetail.svelte'),
  '/settings':    () => import('./components/Settings.svelte'),
};

const initializeModule: ModuleInitialize = async () => {
  // one-time setup: API clients, stores, etc.
};

2. Mount HomePage in your iframe entry

<script lang="ts">
  import HomePage from '@ticatec/uniface-micro-frame';
  import { routes, initializeModule } from './app';
</script>

<HomePage {routes} {initializeModule} />

HomePage gates on window.self !== window.top. If it's not inside an iframe, it refuses to mount and surfaces a MessageBox instead.

Architecture

Two operating modes

| Mode | Container | Use when | | --- | --- | --- | | Single module (stack) | HomePageModuleHome | One sub-app per iframe; navigation is push/pop overlays. | | Multiple modules (tabs) | TabModules | Several sub-apps in parallel, each in its own iframe; switching via tabs. |

Both modes share the same page shells, global UI singletons, and routing primitives — they differ only in how the top-level navigation surface is rendered.

Layered architecture

┌─────────────────────────────────────────────────────────────────┐
│ HomePage.svelte                                                 │
│  • gates on window.self !== window.top                          │
│  • mounts ModuleHome + Tooltip (Dialog/MessageBox/Indicator      │
│    self-mount on first use)                                     │
└──────────────────────┬──────────────────────────────────────────┘
                       │ routes, initializeModule
                       ▼
┌─────────────────────────────────────────────────────────────────┐
│ ModuleHome.svelte                            (src/lib/module/)   │
│  • parses location.hash → { path, query }                       │
│  • resolves path against routes map → Component                 │
│  • renders the active page                                      │
│  • renders the AppModule page stack on top (with fade)          │
└──────────────────────┬──────────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────────┐
│ Page components (consumer-supplied or pre-built)                │
│  • CommonPage / CommonFormPage    (src/lib/pages/)              │
│  • AppModule.showPage(...) pushes overlays onto the stack       │
└─────────────────────────────────────────────────────────────────┘

For the tab-based variant, HomePage/ModuleHome are replaced (or augmented) by TabModules, which keeps every tab's iframe mounted and toggles display to preserve session state.

Directory map

| Path | Contents | Deep dive | | --- | --- | --- | | src/lib/HomePage.svelte | Root component. Gates on iframe context, mounts Tooltip, defers to ModuleHome. | — | | src/lib/common/ | Shared types: PageAttrs, CloseConfirm, ModuleInitialize, PageInitialize. | — | | src/lib/i18nRes/ | i18n resource proxy — exposes i18nRes.microFrame.* strings (btnClose, moduleError, …). | — | | src/lib/module/ | Stack-based runtime: hash routing + AppModule singleton + ModuleHome container. | README | | src/lib/multiple-modules/ | Tab-based runtime: TabModules with parallel iframes. | README | | src/lib/pages/ | Pre-built page shells: CommonPage, CommonFormPage. | README | | src/lib/index.ts | Public barrel — exports HomePage (default) + ModuleInitialize type. | — |

Core Features

Page management

The framework provides a stack-based page manager through the AppModule singleton:

import { AppModule } from '@ticatec/uniface-micro-frame/module';

AppModule.showPage(EditForm, { id: 42 });   // pushes; ModuleHome renders it as an overlay
AppModule.closeActivePage();                // pops the top entry

AppModule is initialized once by ModuleHome.onMount; every push fires an onPagesChange callback that re-renders the stack with a fade transition. The active hash page stays mounted underneath.

Page components

CommonPage

General-purpose page shell with optional sidebar and header extension:

<script lang="ts">
  import CommonPage from '@ticatec/uniface-micro-frame/CommonPage';
  import type { PageAttrs } from '@ticatec/uniface-micro-frame/common';

  const page$attrs: PageAttrs = {
    title: 'My Page',
    comment: 'Page description',
  };
</script>

<CommonPage {page$attrs} canBeClosed round shadow>
  {#snippet sidebar()}
    <nav style="width: 240px; height: 100%">...</nav>
  {/snippet}

  {#snippet headerExt()}
    <button onclick={reload}>Refresh</button>
  {/snippet}

  <!-- default snippet becomes the main content -->
  <div>Page content goes here</div>
</CommonPage>

CommonFormPage

Form-oriented shell with a built-in ActionBar and an auto-appended Close button:

<script lang="ts">
  import CommonFormPage from '@ticatec/uniface-micro-frame/CommonFormPage';
  import type { ButtonActions } from '@ticatec/uniface-element/ActionBar';

  const actions: ButtonActions = [
    { label: 'Save',   type: 'primary',   handler: save },
    { label: 'Reset',  type: 'secondary', handler: reset },
  ];
</script>

<CommonFormPage page$attrs={{ title: 'Edit Form' }} {actions} canBeClosed>
  <form>...</form>
</CommonFormPage>

Routing system

Hash-based with :param capture:

const routes = {
  '/users/:id':              () => import('./UserDetail.svelte'),
  '/posts/:category/:slug':  () => import('./PostView.svelte'),
};
// UserDetail receives `id` as a prop; PostView receives `category` and `slug`.
// Query string params (?key=value) are also spread onto the component as props.

Query parameters are decoded exactly once: key=value pairs are split from the hash first, and only then is each key/value individually run through decodeURIComponent. Values are expected to be URL-encoded on the way in — encode any =, &, or % that's actually part of the value itself (e.g. %3D, %26, %25), rather than relying on the router to figure out delimiters vs. content. A key with no = (or with = but nothing after it) still comes through, with an empty-string value.

Module initialization

import type { ModuleInitialize } from '@ticatec/uniface-micro-frame';

const initializeModule: ModuleInitialize = async () => {
  await setupApiClient();
  initializeGlobalStores();
  configureLibraries();
};

Runs once before the first page renders.

Page lifecycle hooks

  • ModuleInitialize — async, runs once before the first page renders.
  • PageInitialize — async, per-page hook (consumer-defined).
  • CloseConfirm — async guard () => Promise<boolean> consulted by CommonPage.closePage before AppModule.closeActivePage fires.

Internationalization

The framework ships with built-in English strings baked into src/lib/i18nRes/i18nRes.ts. The strings it owns:

| Key | Used by | | --- | --- | | uniface.microFrame.btnClose | Close button label in CommonFormPage | | uniface.microFrame.moduleError | Error fallback page | | uniface.microFrame.pageNotInFrame | MessageBox shown by HomePage when not in an iframe | | uniface.microFrame.indicatorLoadModule | Loading indicator while the module boots |

To switch language, the consumer configures the shared @ticatec/i18n context before (or inside) HomePage mount:

1. Set the active language

import { i18n } from '@ticatec/i18n';

i18n.language = 'zh-CN';

2. Load translation resources

import { i18nUtils } from '@ticatec/i18n';

await i18nUtils.loadResources('/assets/uniface_zh-CN.json');

Multiple URLs are merged in order — pass additional files to layer your app's strings on top of the framework's.

3. JSON file shape

Framework strings live under the uniface.microFrame.* namespace. A typical localized file:

{
  "uniface": {
    "microFrame": {
      "btnClose": "关闭",
      "moduleError": "无法加载模块。",
      "pageNotInFrame": "无法显示不在 iframe 中的页面。",
      "indicatorLoadModule": "正在加载模块..."
    }
  }
}

If a key is missing from the loaded resources, the framework falls back to the English defaults — so you only need to ship the keys you actually want to override.

4. Real-world wiring

Typically done in initializeModule so the resources are ready before the first page renders:

import { i18n, i18nUtils } from '@ticatec/i18n';
import type { ModuleInitialize } from '@ticatec/uniface-micro-frame';

const initializeModule: ModuleInitialize = async () => {
    const lang = navigator.language;             // e.g. "zh-CN"
    i18n.language = lang;
    await i18nUtils.loadResources(`/assets/uniface_${lang}.json`);
    // ...other one-time setup
};

5. Your own app strings

Create a parallel namespaced proxy for app-level text. Anything missing from loaded resources falls back to the default object:

import { i18nUtils } from '@ticatec/i18n';

const appRes = i18nUtils.createResourceProxy({
    welcome: 'Hello {{name}}',
}, 'myApp');

appRes.welcome({ name: 'World' });               // "Hello World"

Public API surface

// Root — main component + module init type
import HomePage from '@ticatec/uniface-micro-frame';
import type { ModuleInitialize } from '@ticatec/uniface-micro-frame';

// Stack runtime internals
import { AppModule } from '@ticatec/uniface-micro-frame/module';
import ModuleHome from '@ticatec/uniface-micro-frame/module/ModuleHome';

// Tab runtime
import TabModules from '@ticatec/uniface-micro-frame/multiple-modules';

// Pre-built page shells
import CommonPage from '@ticatec/uniface-micro-frame/CommonPage';
import CommonFormPage from '@ticatec/uniface-micro-frame/CommonFormPage';

// Shared types
import type { PageAttrs, CloseConfirm, PageInitialize } from '@ticatec/uniface-micro-frame/common';

See package.json exports field for the authoritative list of subpaths.

Svelte 5 conventions

Every .svelte file in this package follows the same patterns:

  • Propsinterface Props { ... } + let { ... }: Props = $props();. No export let.
  • Statelet x = $state(...) for anything read in the template and mutated from event handlers.
  • Derivedlet y = $derived(...) instead of $: y = ....
  • SlotsSnippet props + {#snippet name()} blocks. No <slot> / slot="...".
  • Dynamic components — capitalized alias inside {#if}/{#each} ({#if comp}{@const C = comp}<C/>{/if}), no <svelte:component>.
  • Refs — plain let x: T; when only used in methods; let x: T | undefined = $state(undefined); when read in the template.

Styling

Import the framework's CSS for proper styling:

@import '@ticatec/uniface-micro-frame/uniface-micro-frame.css';

The same file is also available via the ./styles subpath:

@import '@ticatec/uniface-micro-frame/styles';

Peer dependencies

uniface-micro-frame 5.0.0 requires:

  • svelte ^5.0.0
  • @ticatec/uniface-element ^5.0.0 — UI boards, Page, ActionBar, Tabs, MessageBox, Indicator
  • @ticatec/i18n ^0.5.0i18nUtils.createResourceProxy

These are declared as peerDependencies in package.json — install them alongside this package rather than relying on a transitive install.

Development

pnpm run dev          # start the dev server
pnpm run build        # build the package (CSS + svelte-package)
pnpm run check        # svelte-check type checking
pnpm run test         # run the vitest suite (tests/**/*.test.ts)
pnpm run package      # full publish gate: check && test && svelte-package && copy:css && publint

License

MIT

Author

Henry Feng


For deeper dives into each subsystem, see: