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

pict-microapp

v1.0.0

Published

Present a large pict application as a small, focused one: a declarative manifest gates the host's routes, swaps its navigation graph and re-points its landing page, so a micro app reuses every view, provider and style the host already has.

Downloads

241

Readme

pict-microapp

Present a large pict application as a small, focused one.

A micro app is not a fork and not a rebuild: it is the same application, booted the same way, with a smaller surface. You keep every view, provider, template, style and bug fix the host app already has — and an enhancement to the host lands in every micro app on its next build — but the routes, the navigation and the landing page are the micro app's own.

const libHostApplication = require('../../some-big-app/source/Big-Application-Web.js');
const libMicroApp = require('pict-microapp');

class WidgetInspection extends libMicroApp.composeMicroApp(libHostApplication, require('./Widget-MicroApp-Manifest.js'),
	{
		HostRouterProviderHash: 'BigApplicationRouter',
		NavigationGateMethod: '_applyCustomerNavGate',
		HostPermittedMethod: '_navItemPermitted',
		IsPrivilegedMethod: '_isSuperUser'
	}) {}

module.exports = WidgetInspection;
module.exports.default_configuration = libHostApplication.default_configuration;

The seam

A pict application registers every route it owns through one funnel: PictRouter.addRoute. That is true of the application's own routes, of routes contributed by modules like pict-section-workspace, and of the wildcard record-set routes from pict-section-recordset.

pict-microapp wraps that funnel with an allow list. The host's registration code runs completely unmodified — it just finds that some of what it registered did not stick. Nothing else about the boot sequence changes, which is what keeps a micro app cheap to build and cheap to keep working as the host evolves.

Three seams, in order of how much they matter:

| Seam | What it does | | --- | --- | | gateRouter() | Wraps addRoute with the manifest's allow / deny / guard decision | | applyNavigationGraph() / applyNavigationGate() | Swaps the navigation graph and its visibility filter | | applyDefaultRoute() | Re-points the landing route |

What this does not do

It does not make the JavaScript bundle smaller. The host's module graph is still bundled whole, because the micro app extends the host's application class and that class requires everything. A micro app slims the app the user sees, not the bytes the browser downloads.

That is usually the right trade. The alternative — composing an app out of deep subpath requires into the host — genuinely shrinks the bundle, but it means reimplementing the host's boot sequence and re-deciding it every time the host changes, which is exactly the coupling a micro app is trying to avoid. Reach for it when download size becomes a real constraint, not before.

The manifest

Everything a micro app declares lives in one plain object.

module.exports =
{
	Name: 'Widget Inspection',
	Hash: 'WidgetInspection',

	// Where the app lands, and where a blocked route bounces to.
	DefaultRoute: '/WidgetDashboard',

	Routes:
	{
		// Route patterns exactly as the host registers them. A trailing '*' is a prefix glob.
		// An EMPTY list exposes everything — useful when you only want different navigation.
		Allow:
			[
				'/WidgetDashboard',
				'/WidgetDashboard/:View',
				'/Widget/Workspace/:ID',
				'/Widget/Workspace/:ID/:Tab',
				'/Gadget/*'
			],

		// Removed even when Allow would admit them. Deny wins.
		Deny: [],

		// Wildcard record-set routes ('/PSRS/:RecordSet/List') are registered ONCE by the host and
		// fan out over every entity it knows, so they cannot be refused per-entity at registration
		// time. They are GUARDED instead: the route registers, but its handler bounces to Fallback
		// when the resolved entity is not listed here. An empty list exposes every entity.
		EntityParameter: 'RecordSet',
		Entities: [ 'Widget', 'Gadget' ],

		// A hash matching no surviving route lands on Fallback rather than on a blank page.
		CatchUnmatched: true,
		Fallback: '',

		// Always admitted, whatever Allow says — the boot and logout plumbing.
		AlwaysAllow: [ '/', '/Logout' ]
	},

	Navigation:
	{
		// The graph this micro app renders, in the host navigation module's own shape.
		Sections: [ /* … */ ],

		// Keep the host's capability / module / session gates …
		HonorHostGates: true,
		// … but drop its audience short-circuit. See below.
		SuperUserSeesEverything: true
	},

	Branding: { Title: 'Widget Inspection' }
};

Why SuperUserSeesEverything defaults to true

A host that serves many audiences usually trims its own large graph hard. The platform application this module was extracted from, for example, shows platform super-users only the handful of cross-customer destinations, because the full menu is meaningless without a customer context.

Applied to a micro app graph — which is already the slimmed surface — that trim empties the menu completely, for exactly the staff building and demoing the app. So the default keeps the host's real gates (session, module, capability) and drops only the audience short-circuit. A privileged session holds no entitlements in a customer's own tenancy, so it skips the capability test too; otherwise the menu blanks a second way the moment the capability map finishes loading.

Compose options

composeMicroApp(pHostApplicationClass, pManifest, pComposeOptions) binds the manifest to one host's naming. Every option is a service hash or a method name on the host.

| Option | Default | Meaning | | --- | --- | --- | | ProviderHash | 'MicroApp' | Where the provider registers on the host's pict instance | | RouterProviderHash | 'PictRouter' | The pict-router provider — the route funnel | | NavigationProviderHash | 'Pict-Navigation' | The pict-section-navigation provider | | HostRouterProviderHash | RouterProviderHash | The provider that owns defaultRoute (often an application router wrapping pict-router) | | AttachOn | 'onAfterInitializeAsync' | The lifecycle hook the gate installs from | | NavigationGateMethod | '' | Host method that installs the nav filter; overridden when named | | HostPermittedMethod | '' | Host method answering "may this session see this item?" | | IsPrivilegedMethod | '' | Host method answering "is this a privileged platform session?" |

Getting AttachOn right

The gate must be installed after the router provider exists and before the host registers its routes. In a typical pict application the router provider is created during onInitializeAsync and routes are registered during the login / data-load cycle, which makes onAfterInitializeAsync the correct hook — the composed override runs the gate, then calls the host's implementation.

If routes come up ungated, the hook fired too late. MicroApp.routeTally tells you immediately:

_Pict.providers.MicroApp.routeTally;
// { Name: 'Widget Inspection', Allowed: 24, Guarded: 7, Blocked: 96 }
_Pict.providers.MicroApp.blockedRoutes;   // every pattern that did not survive

blockedRoutes is the first place to look when a screen is missing: a route you expected to keep but spelled differently than the host registers it shows up there.

Sharing the host's DOM shell

Reused views render into the host's container addresses, which are baked into each view's configuration. A micro app's index.html therefore has to reproduce the host's DOM contract — the application container id, the loading-splash element, the dynamic-CSS <style> tag, and any wrapper class the host's layout modes toggle. Only the chrome around that contract (the top bar, the branding, the panels) is the micro app's to redesign.

This is the one place a micro app is genuinely coupled to its host. Keep the host's ids; change the chrome.

Installation

npm install pict-microapp

License

MIT