Embedding in any page
A JOPS app can run inside any page that is not a React component: a plain HTML page, or a page rendered by another server framework (PHP, ASP.NET, Rails, Django, …). The page keeps its own header, content and scripts, and your code decides when the app starts and ends.
This is hosted mode, the same mechanism JopsApp uses in Next.js and the JOPS plugin uses in WordPress. On those platforms, use their integration instead:
- Inside a Next.js page: use
JopsApp(see Next.js). - On a WordPress site: use the
[jops]shortcode (see WordPress).
Quick start
Section titled “Quick start”-
Load the library with
data-hostand nodata-app. Nothing starts automatically, andwindow.JOPSexposesmount()andunmount(). Put the import map before it, with the same URL as the scriptsrc:<script type="importmap">{ "imports": { "jops-core": "/lib/jops-core.min.js" } }</script><script type="module" src="/lib/jops-core.min.js" data-host></script> -
Add the element the app renders into.
position: relativeis needed by the Router’s slide and fade animations:<div id="app" style="position: relative"></div> -
Mount the app once jops-core is ready:
<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>
App.js is the same entry module as in a standalone app: its default export is created, and the root view renders into root instead of <body>.
import { View } from "jops-core";
export default class App { constructor() { const root = new View(); root.loadLayout("/my-app/layout/main.html").then(() => root.render()); }}The hosted-mode API
Section titled “The hosted-mode API”| Function | Description |
|---|---|
mount({ app, root }) |
Imports app and creates its default export; the root view renders into root (an HTMLElement) instead of <body>. Returns a promise of the App instance |
unmount() |
Ends the app completely: destroys the Router and every view, empties root, clears Store and EventBus, and restores the history methods JOPS wrapped. Safe to call more than once; mount() can start an app again afterwards |
-
jops:readyfires onwindowonce jops-core has fully loaded, so a listener may callmount()directly. Ifwindow.JOPSalready exists, the library has loaded and you can callmount()at once. -
Module form.
mountandunmountare also exported by the module, for modules running on the same page:import { mount, unmount } from "jops-core";await mount({ app: "/my-app/App.js", root: document.getElementById("app") });unmount();
See the mount() reference and Hosted mode for the concepts behind it.
Ending the app
Section titled “Ending the app”- A full page load ends the app anyway.
- A host that removes the app’s element without a page load, or that navigates with
history.pushState(), callsunmount()first. - When history moves to another path, the Router ends the app by itself.
Paths depend on where the library comes from.
With the 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:
window.JOPS.mount({ app: "/my-app/App.js", root: document.getElementById("app") });<Router jops> <Users jops path="/users" src="/my-app/Users.js" layout="/my-app/layout/users.html"></Users></Router>With the library from the CDN, JOPS resolves paths relative to the hosting page. ./my-app/App.js on example.com/admin/users means example.com/admin/my-app/App.js, and root-absolute /my-app/... paths are turned page-relative too:
<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-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>This works when the app is used from pages at one level of the site. For pages at different depths, vendor the library.
ES module import statements inside your .js files resolve relative to the file as usual; the rules above apply to paths JOPS loads (app, src=, layout=, loadLayout()).
Rules for a hosted app
Section titled “Rules for a hosted app”- One JOPS app per page.
Router,StoreandEventBusare page-wide singletons. - One library URL per page. The import map and the script
srcmust be the same URL, so the page has a single jops-core instance. - The host page owns the CSS. In hosted mode
setStyle()has no effect. Link the app’s stylesheet from the page or from the app’s layout, and scope every rule under the app’s root class (.my-app .card { … }). The stylesheet applies to the whole page, so avoid global rules such asbody,*,:rootor bare tag selectors. - The page owns the path, JOPS owns the hash (
/admin/users#details?id=7). - No Android back button integration. It is off in hosted mode.