msm-components, WebSocket, REST, SSR und Web-Komponenten.
Nach dem Laden von msm-framework-js wird eine gemeinsame Client-Instanz erstellt:
const app = new MSM2.App("wss://example.com");
Backend-Service aufrufen
import { callService } from "msm-components/dist/services.js";
const response = await callService(
"searchManagerServiceImpl", "PROTOTYPE", "search",
[{ query: { isPublishedForSale: true }, offset: 0, limit: 10 }]
);
const items = response.result?.data?.content ?? [];
JSON.stringify(request).
Repository und Bean
import { callRepository, updateBean } from "msm-components/dist/services.js";
const response = await callRepository("blogCategoryRepository", {
query: { _id: categoryId }, skip: 0, limit: 1,
});
// Aktualisiert Werte einer mit @Component oder @Service registrierten Bean.
await updateBean(
"dummyBean", "PROTOTYPE",
{ description: "Updated description" }
);
React mit WebSocket-Daten
import { useEffect, useState } from "react";
const app = new MSM2.App("wss://example.com");
export function ProductList() {
const [items, setItems] = useState([]);
useEffect(() => {
const subscription = app.invokeAndGetJson$(
"searchManagerServiceImpl", "PROTOTYPE", "search",
[{ type: "SellerSKU", query: {}, offset: 0, limit: 10 }], null, "USER"
).subscribe((response) => setItems(response.result?.data?.content ?? []));
return () => subscription.unsubscribe();
}, []);
return <ul>{items.map((item) => <li key={item.id}>{item.name}</li>)}</ul>;
}
SSR und eigene Events
app.renderPage();
app.renderElement(
[{ elementId: "cart-container", path: "/components/cart", payload: {} }],
{ userId }
);
const subscription = app.registerJsonWebSocket("jobs", (event) => {
console.log("Job-Ereignis", event);
});
Übersetzungen und Routing
import { setLocalesPath, translate, loadManyTranslations } from "msm-components/dist/services.js";
import { routeManager } from "msm-components/dist/services.js";
setLocalesPath("/assets/locales/{{lng}}.json");
document.title = await translate("DashboardTitle");
const texts = await loadManyTranslations("SaveButton", "CancelButton");
routeManager.init("My application");
routeManager.addRoute("/", "home", "HomeTitle");
routeManager.addRoute("/products/:id.html", "product", "ProductTitle");
routeManager.loadRouteByCurrentUrl();
routeManager.navigate("product", "42.html");
Web-Komponenten
<msc-header></msc-header>
<msm-button type="OUTLINE" variant="emphasis" href="/catalog">
Katalog öffnen
</msm-button>
<msm-login-form></msm-login-form>
Authentifizierung
MSM2.App.AuthHelper.authenticate$(
"/api/v1/authenticate", "username=user@example.com&password=secret"
).subscribe({
next: (response) => console.log(response),
error: (error) => console.error("Login fehlgeschlagen", error),
});
MSM2.App.AuthHelper.logout$("/api/v1/logout", "role=user")
.subscribe(() => { window.location.href = "/user/login.html"; });
REST und Datei-Upload
const response = await fetch("/api/v1/bean/request", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Site-Context": "my-site",
"Lang-Context": "de",
},
body: JSON.stringify({
beanId: "frameworkOperationServiceImpl",
scope: "PROTOTYPE", functionName: "getLangCode", args: [],
}),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const formData = new FormData();
formData.append("file", file);
formData.append("payload", JSON.stringify({ destination: `${sellerId}/images` }));
formData.append("command", "UPLOAD_IMAGE");
await fetch("/api/v1/uploadImage", { method: "POST", body: formData });
Formular-Payload
import { getPayloadOfForm } from "msm-components/dist/services.js";
const payload = getPayloadOfForm(document.querySelector("form[data-profile]"));
console.log(payload);
Cookies und sprachabhängige URLs
import { setCookie, getCookie, languageAwareUrl } from "msm-components/dist/services.js";
setCookie("promo", "spring", null, null, "/");
console.log(getCookie("i18next"));
console.log(await languageAwareUrl("/catalog"));
Eigene Topic-Subscription
const subscription = app.registerJsonWebSocket("orders", (event) => {
console.log("Bestellereignis", event);
});
subscription.unsubscribe();
Teilweises HTML-Rendering
app.renderElement(
[{ elementId: "profile", path: "/components/profile", payload: {} }],
{ userId }
);
Wiederholung fehlgeschlagener Aufrufe
async function callWithRetry(task, attempts = 3) {
let lastError;
for (let attempt = 1; attempt <= attempts; attempt += 1) {
try { return await task(); }
catch (error) {
lastError = error;
await new Promise((resolve) => setTimeout(resolve, attempt * 500));
}
}
throw lastError;
}
const response = await callWithRetry(() => callService(
"frameworkOperationServiceImpl", "PROTOTYPE", "getLangCode", []
));
JSON-Antwort prüfen
const response = await callService(
"frameworkOperationServiceImpl", "PROTOTYPE", "getLangCode", []
);
if (response.result == null) throw new Error("Leeres Ergebnis");
Minimale HTML-Seite
<script src="https://cdn.jsdelivr.net/npm/msm-framework-js@0.0.7/index.js"></script>
<main id="app"></main>
<script>
const app = new MSM2.App("wss://example.com");
app.renderPage();
</script>
Gemeinsame Client-Instanz
// Nur eine Instanz pro Anwendung erzeugen.
export const MSM2App = window.app || (window.app = new MSM2.App());
MSM2App.renderPage();