the package is now served from npm; removed copy-latest related code

This commit is contained in:
2026-06-12 16:35:42 +02:00
parent 09c75c3f6b
commit d6fa61ccef
9 changed files with 196 additions and 4054 deletions

View File

@@ -4,12 +4,16 @@
Beispielprojekt, das zeigt, wie ein **PHX-ERP-Frontend-Plugin** als Angular-Web-Component mit `@phx-erp/shared` und `@phx-erp/shared-ui` erstellt wird.
**Neues Plugin starten?** Nutzen Sie [@phx-erp/create-phx-frontend-plugin](https://www.npmjs.com/package/@phx-erp/create-phx-frontend-plugin), um ein Projekt aus dem offiziellen Template zu erzeugen. Dieses Repository ist eine vollständige Demo zum Erkunden, Klonen oder als Referenz.
Dieselbe Codebasis unterstützt zwei Arbeitsweisen:
| Modus | Zweck | Typischer Befehl |
|-------|-------|------------------|
| **Plugin host** | Ausführung in PHX als Custom Element | `yarn run plugin` |
| **Standalone client** | Lokale Entwicklung wie eine normale Angular-App | `yarn client` |
| Modus | Zweck | Typischer Befehl |
| --------------------- | ----------------------------------------------- | ----------------- |
| **Plugin host** | Ausführung in PHX als Custom Element | `yarn run plugin` |
| **Standalone client** | Lokale Entwicklung wie eine normale Angular-App | `yarn client` |
---
@@ -22,6 +26,7 @@ Dieselbe Codebasis unterstützt zwei Arbeitsweisen:
- [Entwicklungsmodi](#entwicklungsmodi)
- [Projektstruktur](#projektstruktur)
- [Eigenes Plugin erstellen](#eigenes-plugin-erstellen)
- [Scaffold-CLI (empfohlen)](#scaffold-cli-empfohlen)
- [1. Grundsetup](#1-grundsetup)
- [2. Tailwind CSS](#2-tailwind-css)
- [3. GraphQL Codegen](#3-graphql-codegen)
@@ -42,10 +47,10 @@ Dieselbe Codebasis unterstützt zwei Arbeitsweisen:
Ein PHX-Frontend-Plugin ist eine Angular-Anwendung, die als **Custom Element** (Web Component) verpackt wird. PHX lädt es über ein **Manifest**, das auf die kompilierte `main.js` verweist und den Element-Tag-Namen deklariert.
```
┌─────────────────┐ manifest.json ┌──────────────────┐
┌─────────────────┐ manifest.json ┌──────────────────
│ PHX host │ ─────────────────────► │ main.js (+ deps) │
│ (ERP shell) │ loads & registers │ custom element │
└────────┬────────┘ └────────┬─────────┘
└────────┬────────┘ └────────┬─────────
│ │
│ pluginServices (Apollo, notifications…) │
│ hostInjector │
@@ -77,26 +82,21 @@ Für die lokale eigenständige Entwicklung benötigen Sie außerdem eines der fo
## Schnellstart
Diese Schritte gelten für **dieses Demo-Repository**. Um ein eigenes Plugin von Grund auf zu erstellen, nutzen Sie die Scaffold-CLI — siehe [Eigenes Plugin erstellen](#eigenes-plugin-erstellen).
1. **Abhängigkeiten installieren:**
```bash
```bash
yarn install
```
```
2. **Lokale Development-Umgebung anlegen** (optional, für den Standalone-Modus):
```bash
```bash
cp src/environments/environment.example.ts src/environments/environment.development.ts
```
```
Passen Sie `apiUrl`, `wsUrl` und optional `apiKey` in dieser Datei an. Die Datei ist gitignored.
3. **GraphQL-Typen generieren** (erfordert PHX Admin API unter der in `codegen.ts` konfigurierten Schema-URL):
```bash
```bash
yarn codegen
```
```
4. **In einem der Entwicklungsmodi** unten starten.
---
@@ -106,10 +106,10 @@ Für die lokale eigenständige Entwicklung benötigen Sie außerdem eines der fo
Um diese Demo in Ihrer eigenen Instanz zu nutzen, fügen Sie unter **Admin → Custom Elements** (`https://your.phx.instance/admin/customElements`) ein Custom Element mit folgender Manifest-URL hinzu:
```
https://gitea.phx-erp.de/api/v1/repos/PHXGMBH/phx-frontend-plugin-webcomponent-demo/raw/master/latest/manifest.json
https://unpkg.com/@phx-erp/phx-frontend-plugin-demo/manifest.json
```
Das Manifest verweist auf die kompilierte `main.js` im Verzeichnis `latest/` dieses Repositorys.
Das `path`-Feld des Manifests verweist auf die Paketwurzel; unpkg liefert `main.js` über den `"."`-Export. Für die lokale Entwicklung mit `yarn run plugin` registrieren Sie stattdessen `http://localhost:3223/local.manifest.json` unter Admin → Custom Elements.
---
@@ -124,7 +124,7 @@ yarn client
# equivalent: ng serve --port 4201 --watch --configuration development
```
Öffnen Sie **http://localhost:4201/**.
Öffnen Sie **[http://localhost:4201/](http://localhost:4201/)**.
### Plugin-Host-Modus (innerhalb von PHX)
@@ -136,18 +136,20 @@ yarn run plugin
Dies führt `yarn build` und `yarn serve` parallel aus:
| Skript | Funktion |
|--------|----------|
| `yarn build` | Production-Watch-Build (in diesem Repo zusätzlich Sync nach `latest/` für die gehostete Demo) |
| `yarn serve` | Stellt `dist/.../browser/` unter **http://localhost:3223/** bereit |
| Skript | Funktion |
| ------------ | -------------------------------------------------------------------------------------------- |
| `yarn build` | Production-Watch-Build |
| `yarn serve` | Stellt `dist/.../browser/` unter **[http://localhost:3223/](http://localhost:3223/)** bereit |
Verweisen Sie Ihre PHX-Instanz auf das lokale Manifest:
```
http://localhost:3223/manifest.json
http://localhost:3223/local.manifest.json
```
(`public/manifest.json` wird in die bereitgestellte Ausgabe kopiert.)
(`public/local.manifest.json` wird in die bereitgestellte Ausgabe kopiert.)
> **Hinweis:** Verwenden Sie `yarn run plugin`, nicht `yarn plugin` — Yarn behandelt `plugin` als eingebauten Befehl.
@@ -166,16 +168,15 @@ yarn codegen # Regenerate GraphQL types
```
phx-frontend-plugin-demo/
├── latest/ # Published build output (main.js, manifest.json)
├── public/
│ └── manifest.json # Local manifest (path → localhost:3223)
│ └── local.manifest.json # Lokales Dev-Manifest (in dist kopiert)
├── manifest.json # Veröffentlichtes Manifest (npm/unpkg)
├── scripts/
│ ├── copy-latest.mjs # (this repo only) Sync dist/*.js → latest/ for hosted demo
│ └── serve-dist.mjs # Static server for plugin-host dev
├── src/
│ ├── app/
│ │ ├── components/ # Demo pages (hello-world, product-view, …)
│ │ ├── login.ts # Auth-Callback-Route (Standalone-Entwicklung)
│ │ ├── login.ts # Auth-Callback-Route — Weiterleitungsflow (Standalone-Entwicklung)
│ │ ├── services/
│ │ │ ├── apollo.service.ts
│ │ │ └── phoenix-host-bridge.service.ts
@@ -198,7 +199,23 @@ phx-frontend-plugin-demo/
## Eigenes Plugin erstellen
Die folgenden Schritte führen durch die Erstellung eines Projekts, das dieser Demo ähnelt, mit [Yarn v4](https://yarnpkg.com/getting-started/install), [Angular 20](https://angular.dev/), [PrimeNG 20](https://primeng.org/) und [Tailwind CSS](https://tailwindcss.com/).
### Scaffold-CLI (empfohlen)
Der schnellste Weg ist die offizielle Scaffold-CLI, veröffentlicht als [@phx-erp/create-phx-frontend-plugin](https://www.npmjs.com/package/@phx-erp/create-phx-frontend-plugin):
```bash
# Yarn Berry — einmalig, ohne globale Installation
yarn dlx @phx-erp/create-phx-frontend-plugin
# npm
npx @phx-erp/create-phx-frontend-plugin@latest
```
Dabei wird das offizielle Plugin-Template kopiert, Platzhalter ersetzt (Projektname, Custom-Element-Tag, API-URLs), `environment.development.ts` angelegt und optional `yarn install` ausgeführt. Nicht-interaktive Flags (`--yes`, `--install`, `--api-url`, `--ui-url`, `--api-key` usw.) sind auf der [Paketseite](https://www.npmjs.com/package/@phx-erp/create-phx-frontend-plugin) dokumentiert.
### Manuelles Setup (Schritt für Schritt)
Wenn Sie jeden Schritt nachvollziehen oder von Grund auf anpassen möchten, führen die folgenden Abschnitte durch die Erstellung eines Projekts, das dieser Demo ähnelt, mit [Yarn v4](https://yarnpkg.com/getting-started/install), [Angular 20](https://angular.dev/), [PrimeNG 20](https://primeng.org/) und [Tailwind CSS](https://tailwindcss.com/).
Ersetzen Sie Platzhalter wie `*PROJECT-NAME*`, `*YOUR-TAG*` und `*YOUR-TOKEN*` durch Ihre Werte.
@@ -246,7 +263,7 @@ module.exports = {
};
```
Aufgrund eines bekannten Problems müssen diese Direktiven in den **`styles` jeder Komponente** (und in `src/styles.scss` für die lokale Entwicklung) ergänzt werden:
Aufgrund eines bekannten Problems müssen diese Direktiven in den `**styles` jeder Komponente** (und in `src/styles.scss` für die lokale Entwicklung) ergänzt werden:
```css
@tailwind base;
@@ -307,7 +324,7 @@ Dies erzeugt `src/app/schema-types.ts` und `src/app/generated.ts`.
Verwenden Sie getrennte Environments, damit derselbe Build als PHX-Plugin (Production) oder als eigenständige Dev-App (Development) läuft.
**`src/environments/environment.interface.ts`**
`**src/environments/environment.interface.ts**`
```ts
export abstract class Environment {
@@ -319,7 +336,7 @@ export abstract class Environment {
}
```
**`src/environments/environment.ts`** (Production — verwendet bei Einbettung in PHX)
`**src/environments/environment.ts**` (Production — verwendet bei Einbettung in PHX)
```ts
import { Environment } from './environment.interface';
@@ -333,7 +350,7 @@ export const environment: Environment = {
};
```
**`src/environments/environment.development.ts`** (lokale Entwicklung — in `.gitignore` aufnehmen)
`**src/environments/environment.development.ts**` (lokale Entwicklung — in `.gitignore` aufnehmen)
```ts
import { Environment } from './environment.interface';
@@ -488,8 +505,8 @@ bootstrapPhoenixPluginCustomElement(App, '*YOUR-TAG*', appConfig).then((app) =>
});
```
- **`bootstrapPhoenixPluginCustomElement`** — erstellt die Angular-Anwendung und registriert das Custom Element für PHX.
- **`app.bootstrap(App)` in Development** — mountet zusätzlich die Root-Komponente, damit `ng serve` / der Standalone-Modus mit Routing funktioniert.
- `bootstrapPhoenixPluginCustomElement` — erstellt die Angular-Anwendung und registriert das Custom Element für PHX.
- `app.bootstrap(App)` in Development — mountet zusätzlich die Root-Komponente, damit `ng serve` / der Standalone-Modus mit Routing funktioniert.
Der Custom-Element-Tag muss **kleingeschrieben mit Bindestrichen** sein (z. B. `my-company-orders`). Verwenden Sie denselben Tag in Ihrem Manifest.
@@ -510,12 +527,14 @@ PHX lädt ein JSON-Manifest, das auf Ihr Entry-Skript verweist und den Custom-El
}
```
| Feld | Beschreibung |
|------|--------------|
| `path` | Absolute URL zu `main.js` (und Basis für Chunk-Auflösung) |
| `items[].tagName` | In `main.ts` registrierter Custom-Element-Tag |
**Beispiel lokale Entwicklung** (`public/manifest.json` in diesem Repo):
| Feld | Beschreibung |
| ----------------- | --------------------------------------------------------- |
| `path` | Absolute URL zu `main.js` (und Basis für Chunk-Auflösung) |
| `items[].tagName` | In `main.ts` registrierter Custom-Element-Tag |
**Beispiel lokale Entwicklung** (`public/local.manifest.json` in diesem Repo):
```json
{
@@ -524,11 +543,11 @@ PHX lädt ein JSON-Manifest, das auf Ihr Entry-Skript verweist und den Custom-El
}
```
**Gehostetes Beispiel** (`latest/manifest.json` in diesem Repo):
**Veröffentlichtes Beispiel** (Root-`manifest.json`, über npm/unpkg bereitgestellt):
```json
{
"path": "https://gitea.phx-erp.de/api/v1/repos/PHXGMBH/phx-frontend-plugin-webcomponent-demo/raw/master/latest/main.js",
"path": "https://unpkg.com/@phx-erp/phx-frontend-plugin-demo",
"items": [{ "tagName": "frontend-plugin-demo" }]
}
```
@@ -538,7 +557,7 @@ PHX lädt ein JSON-Manifest, das auf Ihr Entry-Skript verweist und den Custom-El
1. Hosten Sie `main.js` (und ggf. weitere Chunks) unter einer URL, die aus den Browsern Ihrer Nutzer erreichbar ist — dieselben Netzwerkregeln wie für Ihre PHX-Instanz.
2. Veröffentlichen Sie ein Manifest-JSON unter einer stabilen URL.
3. In PHX: **Admin → Custom Elements** → Manifest-URL hinzufügen und Mount-Pfad oder Tag wählen.
4. Ab- und wieder anmelden. Das Plugin ist verfügbar unter `https://your.phx.instance/customElements/*PATH*`.
4. Ab- und wieder anmelden. Das Plugin ist verfügbar unter `https://your.phx.instance/customElements/*PATH`*.
Für die lokale Plugin-Host-Entwicklung siehe [Plugin lokal bereitstellen](#plugin-lokal-bereitstellen).
@@ -554,7 +573,7 @@ Statischen Server installieren:
yarn add -D serve
```
**`scripts/serve-dist.mjs`**
`**scripts/serve-dist.mjs**`
```js
import { spawn } from 'node:child_process';
@@ -575,7 +594,7 @@ const child = spawn(serveBin, ['-l', port, '--cors', '--no-etag'], {
child.on('exit', (code) => process.exit(code ?? 0));
```
**`serve.json`** (ersetzen Sie `*PROJECT-NAME*` durch Ihren Angular-Projektnamen aus `angular.json`)
`**serve.json**` (ersetzen Sie `*PROJECT-NAME*` durch Ihren Angular-Projektnamen aus `angular.json`)
```json
{
@@ -601,8 +620,6 @@ In `package.json` ergänzen:
Eigener Port: `PORT=8080 yarn serve`.
> **Nur in diesem Repository:** `scripts/copy-latest.mjs` kopiert gebaute JS-Dateien nach `latest/`, damit das [Live-Demo](#live-demo)-Manifest auf einen stabilen Pfad in Git verweisen kann. Für die lokale Plugin-Host-Entwicklung ist das nicht erforderlich.
### Apollo, Auth Guard und Login
Im **Production**-Modus (eingebettet in PHX) übernimmt der Host die Authentifizierung. Nutzen Sie den Apollo Client aus `IPluginServices` über `PhoenixHostBridgeService` — ein separater Login-Flow ist nicht nötig.
@@ -650,9 +667,9 @@ Wenden Sie dasselbe Muster auf andere Host-Services an (z. B. Notifications), we
#### Login-Callback-Route
Für die Entwicklung ohne voreingestellten API-Key gen Sie eine `/login`-Route hinzu, die als **Auth-Callback** dient — nicht als Login-Formular. Ist der Nutzer nicht authentifiziert, leitet der Auth Guard zur PHX-Login-Seite (`environment.serverUrl`) weiter. Nach erfolgreichem Login leitet PHX zurück auf die `/login`-Route Ihres Plugins mit einem `authToken`-Query-Parameter und einem base64-kodierten `redirectTo`-Ziel.
Für die Entwicklung ohne voreingestellten API-Key benötigen Sie einen Weg, einen API-Token zu erhalten und zu speichern. Dieses Demo nutzt einen **weiterleitungsbasierten Auth-Callback** auf `/login` statt eines eingebetteten Login-Formulars — beide Ansätze sind jedoch möglich: Sie können auch ein eigenes Login-Formular bauen, die GraphQL-`login`-Mutation aufrufen und den Token selbst verwalten.
Die Callback-Komponente speichert den Token in `localStorage` und navigiert zurück zur ursprünglichen Seite:
Bei der Weiterleitungsvariante leitet der Auth Guard nicht authentifizierte Nutzer zur PHX-Login-Seite (`environment.serverUrl`) weiter. Nach erfolgreichem Login leitet PHX zurück auf die `/login`-Route Ihres Plugins mit einem `authToken`-Query-Parameter und einem base64-kodierten `redirectTo`-Ziel. Die Callback-Komponente speichert den Token in `localStorage` und navigiert zurück zur ursprünglichen Seite:
```ts
@Component({
@@ -730,32 +747,34 @@ Empfohlene Skripte nach dieser Anleitung:
}
```
| Skript | Beschreibung |
|--------|--------------|
| `build` | Production-Watch-Build für PHX |
| `serve` | Stellt kompilierte Assets für PHX bereit (Standard-Port 3223) |
| `plugin` | Führt `build` + `serve` zusammen aus — verwenden Sie `yarn run plugin` |
| `client` | Eigenständiger Angular-Dev-Server auf Port 4201 |
| `codegen` | Generiert GraphQL-TypeScript-Typen neu |
Dieses Repository führt zusätzlich `copy-latest.mjs` parallel zu `build` aus, um Artefakte nach `latest/` für die gehostete Demo zu veröffentlichen — das ist für Ihr eigenes Plugin nicht erforderlich.
| Skript | Beschreibung |
| --------- | ---------------------------------------------------------------------- |
| `build` | Production-Watch-Build für PHX |
| `serve` | Stellt kompilierte Assets für PHX bereit (Standard-Port 3223) |
| `plugin` | Führt `build` + `serve` zusammen aus — verwenden Sie `yarn run plugin` |
| `client` | Eigenständiger Angular-Dev-Server auf Port 4201 |
| `codegen` | Generiert GraphQL-TypeScript-Typen neu |
---
## Fehlerbehebung
| Symptom | Zu prüfen |
|---------|-----------|
| PHX zeigt eine alte Plugin-Version | Hard-Refresh; prüfen, ob `serve.json` `Cache-Control: no-store` für JS setzt; `yarn run plugin` neu starten |
| Symptom | Zu prüfen |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| PHX zeigt eine alte Plugin-Version | Hard-Refresh; prüfen, ob `serve.json` `Cache-Control: no-store` für JS setzt; `yarn run plugin` neu starten |
| `401` / GraphQL-Auth-Fehler im Standalone-Modus | `apiKey` in `environment.development.ts` setzen, oder sicherstellen, dass `serverUrl` auf Ihre PHX-Instanz zeigt, damit die Login-Weiterleitung funktioniert |
| `yarn add @phx-erp/shared` schlägt fehl | Netzwerkzugriff auf die öffentliche npm-Registry prüfen; `yarn install` erneut ausführen |
| Routing in PHX funktioniert nicht | Routen-Segmente zu `stripTrailingSegments` in `providePhoenixPluginWithPrimeNG` hinzufügen |
| Tailwind-Klassen fehlen in einer Komponente | `@tailwind`-Direktiven in den `styles` der Komponente ergänzen |
| `yarn codegen` schlägt fehl | PHX muss laufen und die Schema-URL in `codegen.ts` erreichbar sein |
| Custom Element nicht gefunden | Tag im Manifest muss exakt mit `customElements.define` / `bootstrapPhoenixPluginCustomElement` übereinstimmen |
| `yarn add @phx-erp/shared` schlägt fehl | Netzwerkzugriff auf die öffentliche npm-Registry prüfen; `yarn install` erneut ausführen |
| Routing in PHX funktioniert nicht | Routen-Segmente zu `stripTrailingSegments` in `providePhoenixPluginWithPrimeNG` hinzufügen |
| Tailwind-Klassen fehlen in einer Komponente | `@tailwind`-Direktiven in den `styles` der Komponente ergänzen |
| `yarn codegen` schlägt fehl | PHX muss laufen und die Schema-URL in `codegen.ts` erreichbar sein |
| Custom Element nicht gefunden | Tag im Manifest muss exakt mit `customElements.define` / `bootstrapPhoenixPluginCustomElement` übereinstimmen |
---
## Support
Bei Integrationsfragen oder PHX-spezifischen APIs wenden Sie sich an Ihren PHX-Partner.
Bei Integrationsfragen oder PHX-spezifischen APIs wenden Sie sich an Ihren PHX-Partner.