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

@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 -D

Afegeix .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 id del 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 storePlugins per copiar al sandbox.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 versions

Trampes 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 (un Cannot 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 per new 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 als polyfills: 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