Skip to content

Hosted mode

A JOPS app starts in one of two modes, chosen by the attributes of the jops-core <script> tag.

Standalone mode Hosted mode
Script tag data-app (default ./src/App.js) data-host, no data-app
Who starts the app JOPS, as soon as the library loads the host page, by calling mount()
Renders into <body>, or the data-root element the element passed to mount()
Ending the app a page load unmount(), or leaving the app’s page
Used by regular SPAs, hybrid mobile, Electron Next.js (JopsApp), WordPress ([jops]), any other page

The app owns the page. JOPS imports the module named in data-app and creates its default export:

index.html
<script type="importmap">
{ "imports": { "jops-core": "https://cdn.jsdelivr.net/npm/jops-core@latest/lib/jops-core.min.js" } }
</script>
<script type="module" src="https://cdn.jsdelivr.net/npm/jops-core@latest/lib/jops-core.min.js"
data-app="./src/App.js"></script>

By default the app renders into <body>. To keep the rest of the page and render into one element, add data-root with the element’s id:

index.html
<div id="app"></div>
<script type="module" src="https://cdn.jsdelivr.net/npm/jops-core@latest/lib/jops-core.min.js"
data-app="./src/App.js" data-root="app"></script>

In hosted mode, the page is in charge. Load the library with data-host and no data-app: nothing starts automatically, and window.JOPS exposes mount() and unmount(). Then start the app yourself:

admin/users.html
<script type="importmap">
{ "imports": { "jops-core": "/lib/jops-core.min.js" } }
</script>
<script type="module" src="/lib/jops-core.min.js" data-host></script>
<div id="app" style="position: relative"></div>
<script type="module">
const start = () =>
window.JOPS.mount({ app: "/my-app/App.js", root: document.getElementById("app") });
window.JOPS ? start() : window.addEventListener("jops:ready", start, { once: true });
</script>
  • jops:ready fires once jops-core has fully loaded, so a listener may call mount() directly. If window.JOPS already exists, the library is ready.
  • One instance. The import map and the script src must be the same URL, so the page loads a single jops-core instance.
  • One app per page. There is one host root and one Router.
  • position: relative on the container keeps Router animations inside it.

mount({ app, root }) imports app, creates its default export, and makes the root view render into root (an HTMLElement) instead of <body>. It returns a promise of the App instance.

unmount() ends the app completely: it destroys the Router and every view, empties root, clears the Store and the EventBus, and restores the browser history methods that JOPS wrapped. It is safe to call more than once, and mount() can start an app again afterwards.

Modules on the same page can also import them directly; window.JOPS.mount and window.JOPS.unmount are the same functions:

import { mount, unmount } from "jops-core";
await mount({ app: "/my-app/App.js", root: document.getElementById("app") });
unmount();
  • A full page load ends the app anyway.
  • A host that removes the app’s element without a page load, or navigates with history.pushState(), calls unmount().
  • When browser history moves to another path, the Router ends the app by itself. Coming back starts it again at the route in the hash.

Anything that must outlive the app belongs on the server.

  • setStyle() has no effect: the host page provides the CSS. Load your styles with the host’s own mechanism, and scope them under the app’s root class so they don’t restyle the host page.
  • The Android back button integration is off.

Paths you give to JOPS (app in mount(), data-app, src=, layout=, loadLayout(), setStyle()) are resolved against the HTML page, not the file they are written in, and the right form depends on where the library comes from.

Library on the same origin (/lib/jops-core.min.js in both the import map and src): write root-absolute paths. They work on every page of the site.

<Users jops src="/my-app/Users.js" layout="/my-app/layout/users.html"></Users>

This is the convention for Next.js (files in public/) and WordPress (the app folder in the WordPress root).