@uxland/etc-hes-plugins-sandbox
v1.0.0
Published
Sandbox per desenvolupar plugins de Harmonix (React, Lit o Angular) i provar-los al costat dels plugins del plugin store de PRE, dins del mateix shell que fa servir l'aplicació.
Readme
@uxland/etc-hes-plugins-sandbox
Sandbox per desenvolupar un plugin de Harmonix —amb React, Lit o Angular— i provar-lo al costat dels plugins del plugin store de PRE, dins del mateix shell que fa servir l'aplicació real.
- Sense token, el sandbox arrenca només amb el teu plugin.
- Amb token, hi afegeix els plugins del store de PRE. Cal VPN i obrir el sandbox amb el
token PDS a la URL, com l'ECAP obre l'aplicació:
http://localhost:5200/?access_token=…&refresh_token=….
📘 Guia pas a pas: Entorn de desenvolupament: crear un plugin amb el sandbox.
Per començar un plugin nou amb tot configurat: npm create @uxland/etc-hes-plugin@latest.
Afegir-lo al teu repo
Al teu repo hi queda el teu plugin, el teu build i la teva configuració. La dependència porta la resta: la pàgina amb l'import map de l'aplicació, el client del feed, el proxy cap a PRE i la sincronització del shell.
pnpm add -D @uxland/etc-hes-plugins-sandbox # o npm i -D, o yarn add -DAfegeix .sandbox al .gitignore: és on etc-hes-sandbox-sync hi deixa el shell.
sandbox.config.ts (tots els frameworks)
A l'arrel del projecte:
import { defineSandboxConfig } from "@uxland/etc-hes-plugins-sandbox";
export default defineSandboxConfig({
// El teu plugin, compilat des del codi font. És el que arrenca visible.
plugin: { pluginId: "el-meu-plugin", importer: () => import("./src/plugin") },
// Quins plugins del store de PRE es carreguen al costat del teu, pel seu id.
// Amb les dues llistes buides, tots. La consola llista els disponibles.
storePlugins: { only: [], except: [] },
});React i Lit (Vite)
// vite.config.ts
import { harmonixPlugin } from "@uxland/etc-hes-plugins-sandbox/vite";
export default harmonixPlugin({
// El que posa l'aplicació i el bundle ha de demanar pel nom.
external: ["@uxland/primary-shell", "react", "react-dom", "react-dom/client"], // Lit: ["@uxland/primary-shell", "lit"]
port: 5200,
});// package.json
"scripts": {
"dev": "etc-hes-sandbox-sync && vite", // el sandbox amb el teu plugin
"build": "vite build" // només el plugin: dist/index.js
}vite build fa el mateix build que els plugins del monorepo de harmonix: mode llibreria,
entrada src/plugin.ts, un sol dist/index.js en ES. Si ja tens el teu build, pots fer
servir harmonixPlugin només per al dev.
A React funciona tant el JSX automàtic ("jsx": "react-jsx") com el clàssic: ho decideix el
tsconfig.json.
Angular (Angular CLI)
El build del plugin (ng-packagr + postbuild) no canvia. Només l'aplicació que serveix
ng serve, a angular.json:
"build": {
"options": {
"browser": "src/main.ts",
"index": "node_modules/@uxland/etc-hes-plugins-sandbox/host/index.html",
"polyfills": [], // Zone.js ja el porta la pàgina, com a l'aplicació
"assets": [{ "glob": "**/*", "input": ".sandbox", "output": "/" }],
"externalDependencies": [ /* les claus de l'import map: veure l'exemple */ ]
}
},
"serve": {
"options": {
"proxyConfig": "node_modules/@uxland/etc-hes-plugins-sandbox/proxy.config.mjs",
"prebundle": { "exclude": ["@uxland/etc-hes-plugins-sandbox"] }
}
}La llista completa d'externalDependencies és a l'apartat 7.3 de la guia, i als projectes
d'Angular que crea npm create @uxland/etc-hes-plugin: Angular, rxjs, Lit, React i el shell es resolen per l'import map, com a
l'aplicació real.
// src/main.ts
import { startSandbox } from "@uxland/etc-hes-plugins-sandbox";
import config from "../sandbox.config";
startSandbox(config);Afegeix sandbox.config.ts a l'include de tsconfig.app.json, i al package.json:
"start": "etc-hes-sandbox-sync && ng serve".
Venint d'un dels repos demo antics
| Esborra | Canvia | Afegeix |
|---|---|---|
| src/sandbox.ts (o src/main.ts d'Angular), src/plugins.ts, src/clinical-monitoring.js, src/admin-clinical-monitoring.js, l'index.html | vite.config.ts o angular.json, l'script dev/start | sandbox.config.ts, .sandbox al .gitignore |
El codi del plugin (src/plugin.ts i la resta) no es toca. Els plugins del store que abans
es copiaven a src ara surten del feed: posa'ls a storePlugins.only.
El panell d'informació
A baix a la dreta del sandbox hi ha un botó (i) que obre un panell lateral. És del sandbox, no
de l'aplicació: només existeix en desenvolupament i no va mai al bundle del plugin.
- Estat: el teu plugin, si hi ha token i quants minuts li queden, les versions del shell i del sandbox (i si n'hi ha una de nova a npm).
- Plugins del store: tots els
iddel feed de PRE, amb si s'han carregat, no s'han seleccionat o han fallat (i per què). Si en falla algun, el botó té un punt vermell. - Combinacions: conjunts de plugins habituals (seguiment clínic, seguiment administratiu,
tot el feed, tot menys els que fallen) i el bloc
storePluginsper copiar alsandbox.config.ts. - Versions i diagnòstic: les versions que no coincideixen amb les de l'aplicació (amb la comanda que les alinea), la comprovació d'un sol shell i les vistes registrades a cada regió.
Les combinacions són a src/devtools/presets.ts.
Ressaltar les regions
A sobre del botó d'informació n'hi ha un altre («▦ Mostrar regions») que, activat, dibuixa en
vermell cada regió que hi ha a la pantalla amb el seu nom i quantes vistes actives té: les del
shell i les dels plugins, també les scoped i les d'una altra còpia de @uxland/regions. Les regions buides (sense cap vista,
on es poden injectar) es dibuixen amb línia discontínua. Segueix els canvis: si canvies de
vista, obres un menú o apareixen regions noves, el dibuix s'actualitza sol. Es recorda en
recarregar la pàgina.
Versions
Un plugin no s'executa amb el React, el Lit o l'Angular amb què compila, sinó amb els de
l'import map de l'aplicació (host/index.html, copiat de primary/app). En arrencar, el
sandbox avisa si els que tens instal·lats no hi coincideixen.
El shell que serveix el sandbox és el @uxland/primary-shell que tingui instal·lat el teu
projecte. Per provar un shell encara no publicat del monorepo de harmonix:
HARMONIX_REPO=../harmonix pnpm dev.
Com funciona per dins
Un plugin publicat és un mòdul ES que demana els seus mòduls pel nom
(@uxland/primary-shell, react…). El navegador no els sap resoldre, i si el sandbox se'ls
empaqueta pel seu compte hi ha dues còpies del shell, cada una amb el seu regionManager
i el seu broker: el plugin registra les vistes en la que no es pinta. El sandbox ho resol
com l'aplicació real: un import map i el shell servit per URL (/shell/index.js).
El plugin en desenvolupament, el sandbox i els plugins del store resolen el mateix mòdul.
host/index.html la pàgina: import map + Zone.js + full del shell, sense script d'entrada
src/start.ts startSandbox(config): shell + el teu plugin + plugins del store
src/feed.ts client del feed de PRE (només si la URL porta access_token)
src/vite.ts harmonixPlugin(): dev = sandbox, build = només el plugin
proxy.config.mjs /store-proxy → PRE, per a Vite i per a l'Angular CLI
scripts/sync-shell.mjs etc-hes-sandbox-sync: shell a .sandbox/shell + avís de versionsTrampes que s'hi han resolt:
- El runtime de JSX automàtic, en dev, és del sandbox. El de React és CommonJS i fa
require("react"): Vite no el pot servir sense pre-empaquetar-lo, i pre-empaquetat portaria un segon React. El sandbox en dona un d'equivalent fet amb el React de l'import map; al build va el de React, com sempre. - Marcar un mòdul com a extern no és prou (Vite). En dev, Vite reescriu els externs a
/@id/<especificador>i el navegador acaba amb dos registres del mateix mòdul (unCannot read properties of null (reading 'useMemo')sense motiu aparent). Es reescriu l'especificador directament a la URL de l'import map. Per la mateixa raó, el sandbox no es pot pre-empaquetar: s'enduria una còpia del shell. - L'
import()dels bundles del store no l'ha de veure el bundler (Vite hi enganxa un?import): passa pernew Function("url", "return import(url)"), amb URL absoluta. - El feed i els bundles van pel proxy: CORS, i un
import()no pot portar capçaleres. Els bundles són públics; el token només el demana el feed. - Sense token no es demana el feed: el shell intentaria refrescar un token inexistent i tancaria la sessió, plugin en desenvolupament inclòs.
- L'import map ha de ser complet, amb tot el que demanen els plugins de PRE, i Zone.js va
amb un
<script>abans de tot (sense ell,NG0908). Per això Angular no el porta alspolyfills: en tindria dos.
Comprovació des de la consola, si alguna cosa no es pinta:
(await import("@uxland/primary-shell")).shellApi === window.__sandbox.shellApi // → true: un sol shell