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

@mnjs/adapters

v5.0.0-beta.6

Published

Optional data and DOM integrations for Marionette

Readme

@mnjs/adapters

First-party optional integrations for Marionette v5. The package intentionally has no root export: import only the adapter and optional peer your application uses. Installing this package does not install every provider. The adapters have separate module graphs and no import-time installation; unused integrations stay out of the application bundle. Source is grouped into data and dom, while each integration remains an explicit package subpath.

Adapter conventions

  • SomethingApi is an object implementing an existing runtime contract.
  • createSomethingApi(options) returns that object when configuration is required.

Imports do not configure Marionette. Use the existing setDomApi, setDataApi, and setStateApi methods before constructing instances. An integration may satisfy more than one contract: Backbone uses the same adapter object for both data and state. Setters overlay supplied methods; the last supplied version of a method wins. Configure content rendering after general DOM operations.

Adapters use public APIs and document source ownership and cleanup below.

Template evaluation is a function configured with View.setRenderer(). Projects can supply that function directly; it does not need a packaged adapter. Lit and Morphdom belong to DomApi because they apply template results to the DOM.

Backbone

npm install [email protected] @mnjs/[email protected] backbone

Configure DataApi before creating Views that consume Backbone models or collections. The example below covers model-backed Views. For a CollectionView, configure DataApi on both its parent CollectionView class and its child View class before construction. For a feature-specific integration, configure its View subclass:

import BackboneApi from '@mnjs/adapters/backbone';
import { View } from 'marionette';

const BackboneView = View.extend();
BackboneView.setDataApi(BackboneApi);

Use the top-level setDataApi(BackboneApi) when the whole application shares that data provider. Configure StateApi separately, only for owners whose state uses Backbone and needs subscriptions or owned-source cleanup:

BackboneView.setStateApi(BackboneApi);

The same adapter object can configure other state-owning classes, or the corresponding setters on an existing isolated runtime. Choosing Backbone data does not require choosing Backbone state or creating an isolated runtime.

The adapter uses Backbone's native events and does not modify Backbone objects or prototypes. Releasing an owned Backbone state source removes only the adapter-managed owner subscriptions. The adapter leaves the source and its caller-owned listeners intact; it does not call source-wide stopListening(), off(), or persistence-capable Model#destroy() methods.

XState actors

Use the XState actor adapter when a parent actor snapshot contains stable child actor references. Actor-reference identity associates each child actor with its View; stopping and respawning an actor creates a different model identity even when the actors share an id. The adapter supports XState ^5.32.6.

npm install [email protected] @mnjs/[email protected] xstate

This configuration fragment assumes an application-owned parentActor whose context.children contains stable child actor references. Create and start the actors in the application's XState setup.

import createXStateActorApi from '@mnjs/adapters/xstate';
import { CollectionView, View } from 'marionette';

const XStateActorApi = createXStateActorApi({
  select: snapshot => snapshot.context.children,
  snapshotEvent: 'actor:snapshot'
});

const ActorView = View.extend({
  template: context => context.label,
  modelEvents: {
    'actor:snapshot': 'render',
    announced: 'onAnnounced'
  },
  onAnnounced(event) {
    console.log(event.label);
  }
});
const ActorList = CollectionView.extend({ childView: ActorView });
ActorView.setDataApi(XStateActorApi);
ActorList.setDataApi(XStateActorApi);

const view = new ActorList({ collection: parentActor }).render();

For a CollectionView, the required selector receives the parent actor's synchronous snapshot and returns its ordered child actor references. Omit select when configuring only actor models or state. Templates receive each child actor's current snapshot.context. Configure snapshotEvent only when declarative modelEvents or stateEvents should observe actor snapshots; the chosen name is reserved by that adapter instance. Every other event-map name is passed to actor.on() and therefore observes an explicitly emitted actor event, not an event sent to the actor. Subscribing to an already-started actor does not replay its current snapshot, so initial rendering reads getSnapshot() directly.

Replace the selected array when membership or order changes. Reusing an unchanged array lets the adapter skip comparison; a newly allocated array requires a keyed scan per observer, even if its contents are identical.

Supplied parent, child, and state actors are borrowed. Destroying a Marionette owner releases its subscriptions and Views but does not stop those actors. An actor returned by an owner's createState() factory is owned; after releasing its subscriptions, Marionette calls this adapter's disposeOwned() and stops that actor. The keyed snapshot helper is private implementation only; there is no generic snapshot-source package export.

jQuery DomApi

npm install [email protected] @mnjs/[email protected] jquery
import { View } from 'marionette';
import JQueryDomApi from '@mnjs/adapters/dom/jquery';

const JQueryView = View.extend();
JQueryView.setDomApi(JQueryDomApi);

If application code needs $el, initialize it once:

import $ from 'jquery';
import { View } from 'marionette';
import JQueryDomApi from '@mnjs/adapters/dom/jquery';

const JQueryView = View.extend({
  initialize() { this.$el = $(this.el); }
});
JQueryView.setDomApi(JQueryDomApi);

Views, CollectionViews, and Behaviors keep their initial root. The application owns $el; no wrapper helper or extra package subpath is needed.

Importing an adapter subpath does not load any other adapter or optional peer.

DOM contents

The Morphdom and Lit DOM adapters update a View's contents synchronously and keep its el in place. Marionette still owns View events, attachment, destruction, and Regions. A parent render still destroys its Region children before updating the parent template; incremental rendering does not preserve those child Views. Keep Region placeholders empty in your templates so the adapter and Region do not both manage the same contents.

Configure these adapters through ViewClass.setDomApi(adapter) before creating instances. The adapter overlays only its supplied methods, so unrelated DOM operations remain in place. Configure jQuery first if you need its query and attachment operations alongside Morphdom or Lit.

Morphdom

npm install [email protected] @mnjs/[email protected] morphdom
import { View } from 'marionette';
import MorphdomDomApi from '@mnjs/adapters/dom/morphdom';

const MessageView = View.extend({
  template: () => '<p id="message">Hello again.</p>'
});
MessageView.setDomApi(MorphdomDomApi);

The template returns an HTML string containing the View's contents. Morphdom matches children using its normal rules, including element IDs. The adapter installs HTML directly into an empty root and morphs existing contents using childrenOnly, leaving the root's attributes under Marionette's control. Use renderAttributes() to refresh those attributes.

Lit HTML

npm install [email protected] @mnjs/[email protected] lit-html
import { View } from 'marionette';
import { html } from 'lit-html';
import LitDomApi from '@mnjs/adapters/dom/lit-html';

const MessageView = View.extend({
  template: ({ message }) => html`<p>${message}</p>`,
  templateContext: { message: 'Hello again.' }
});
MessageView.setDomApi(LitDomApi);

Configure a View subclass before creating its instances. Further subclasses inherit the adapter. Neither DOM adapter modifies View methods or needs a View reference: template evaluation stays in the renderer and the returned value goes to Dom.setContents(el, value).

Lit async directives can own subscriptions and other resources. Marionette calls Dom.notifyAttach(el) and Dom.notifyDetach(el) through its existing attachment monitoring. Lit translates these notifications to its directive connection API. Detaching and destroying a View disconnects its directives while preserving the View root. A View keeps its initial element for its lifetime. Destroying an already constructed View also disconnects resources created before an explicit render failed. Failed construction does not roll back initialization.

Keep monitorViewEvents enabled on the View and its ancestors and manage attachment through Regions. If you disable monitoring or remove its handlers with off(), the application must call the adapter's attachment methods itself. There is no separate hidden cleanup listener. Lifecycle overrides must call parent methods, as with other Marionette lifecycle overrides.

The first explicit render replaces preexisting contents; this is not hydration. Subsequent renders update Lit's marked range. A disconnected element can be adopted by another View using the same adapter without erasing its contents. Release the previous owner first; one element cannot have two active View owners. Lit event handlers use Lit's normal element receiver; use closures when a handler needs application or View state. Do not independently replace Lit's contents or switch content adapters after rendering.