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

155
README.md
View File

@@ -1,15 +1,17 @@
# PHX Frontend Plugin Demo
> [Deutsche Version](README.DE.md)
Example project showing how to build a **PHX ERP frontend plugin** as an Angular web component, using `@phx-erp/shared` and `@phx-erp/shared-ui`.
**Starting a new plugin?** Use [@phx-erp/create-phx-frontend-plugin](https://www.npmjs.com/package/@phx-erp/create-phx-frontend-plugin) to scaffold a project from the official template. This repository is a full demo you can explore, clone, or use as a reference.
The same codebase supports two workflows:
| Mode | Purpose | Typical command |
|------|---------|-----------------|
| **Plugin host** | Run inside PHX as a custom element | `yarn run plugin` |
| **Standalone client** | Develop locally like a normal Angular app | `yarn client` |
| Mode | Purpose | Typical command |
| --------------------- | ----------------------------------------- | ----------------- |
| **Plugin host** | Run inside PHX as a custom element | `yarn run plugin` |
| **Standalone client** | Develop locally like a normal Angular app | `yarn client` |
---
@@ -22,6 +24,7 @@ The same codebase supports two workflows:
- [Development modes](#development-modes)
- [Project structure](#project-structure)
- [Create your own plugin](#create-your-own-plugin)
- [Scaffold CLI (recommended)](#scaffold-cli-recommended)
- [1. Basic setup](#1-basic-setup)
- [2. Tailwind CSS](#2-tailwind-css)
- [3. GraphQL Codegen](#3-graphql-codegen)
@@ -77,26 +80,21 @@ For local standalone development you also need either:
## Quick start
These steps apply to **this demo repository**. To create your own plugin from scratch, use the scaffold CLI — see [Create your own plugin](#create-your-own-plugin).
1. **Install dependencies:**
```bash
```bash
yarn install
```
```
2. **Create a local development environment** (optional, for standalone mode):
```bash
```bash
cp src/environments/environment.example.ts src/environments/environment.development.ts
```
```
Adjust `apiUrl`, `wsUrl`, and optionally `apiKey` in that file. The file is gitignored.
3. **Generate GraphQL types** (requires PHX admin API at the schema URL configured in `codegen.ts`):
```bash
```bash
yarn codegen
```
```
4. **Run in one of the development modes** below.
---
@@ -106,10 +104,10 @@ For local standalone development you also need either:
To use this demo in your own instance, add a custom element in **Admin → Custom Elements** (`https://your.phx.instance/admin/customElements`) with this manifest URL:
```
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
```
The manifest resolves to the compiled `main.js` in the `latest/` directory of this repository.
The manifest's `path` field points at the package root; unpkg serves `main.js` via the `"."` export. For local development with `yarn run plugin`, register `http://localhost:3223/local.manifest.json` in Admin → Custom Elements instead.
---
@@ -124,7 +122,7 @@ yarn client
# equivalent: ng serve --port 4201 --watch --configuration development
```
Open **http://localhost:4201/**.
Open **[http://localhost:4201/](http://localhost:4201/)**.
### Plugin host mode (inside PHX)
@@ -136,18 +134,20 @@ yarn run plugin
This runs `yarn build` and `yarn serve` concurrently:
| Script | What it does |
|--------|----------------|
| `yarn build` | Watches production build (in this repo, also syncs output to `latest/` for the hosted demo) |
| `yarn serve` | Serves `dist/.../browser/` at **http://localhost:3223/** |
| Script | What it does |
| ------------ | ---------------------------------------------------------------------------------- |
| `yarn build` | Watches production build |
| `yarn serve` | Serves `dist/.../browser/` at **[http://localhost:3223/](http://localhost:3223/)** |
Point your PHX instance at the local manifest:
```
http://localhost:3223/manifest.json
http://localhost:3223/local.manifest.json
```
(`public/manifest.json` is copied into the served output.)
(`public/local.manifest.json` is copied into the served output.)
> **Note:** Use `yarn run plugin`, not `yarn plugin` — Yarn treats `plugin` as a built-in command.
@@ -166,16 +166,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 # Local dev manifest (copied into dist)
├── manifest.json # Published 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 development)
│ │ ├── login.ts # Auth callback route — redirect flow (standalone development)
│ │ ├── services/
│ │ │ ├── apollo.service.ts
│ │ │ └── phoenix-host-bridge.service.ts
@@ -198,7 +197,23 @@ phx-frontend-plugin-demo/
## Create your own plugin
The steps below walk through creating a project similar to this demo, using [Yarn v4](https://yarnpkg.com/getting-started/install), [Angular 20](https://angular.dev/), [PrimeNG 20](https://primeng.org/), and [Tailwind CSS](https://tailwindcss.com/).
### Scaffold CLI (recommended)
The fastest way to start is the official scaffold CLI, published as [@phx-erp/create-phx-frontend-plugin](https://www.npmjs.com/package/@phx-erp/create-phx-frontend-plugin):
```bash
# Yarn Berry — one-shot, no global install
yarn dlx @phx-erp/create-phx-frontend-plugin my-orders-plugin
# npm
npx @phx-erp/create-phx-frontend-plugin@latest my-orders-plugin
```
This copies the official plugin template, replaces placeholders (project name, custom element tag, API URLs), creates `environment.development.ts`, and can run `yarn install`. See the [package page](https://www.npmjs.com/package/@phx-erp/create-phx-frontend-plugin) for non-interactive flags (`--yes`, `--install`, `--api-url`, `--ui-url`, `--api-key`, etc.).
### Manual setup (step by step)
If you prefer to understand each piece or customize from scratch, the steps below walk through creating a project similar to this demo, using [Yarn v4](https://yarnpkg.com/getting-started/install), [Angular 20](https://angular.dev/), [PrimeNG 20](https://primeng.org/), and [Tailwind CSS](https://tailwindcss.com/).
Replace placeholders such as `*PROJECT-NAME*`, `*YOUR-TAG*`, and `*YOUR-TOKEN*` with your values.
@@ -307,7 +322,7 @@ This generates `src/app/schema-types.ts` and `src/app/generated.ts`.
Use separate environments so the same build runs as a PHX plugin (production) or as a standalone dev app (development).
**`src/environments/environment.interface.ts`**
`**src/environments/environment.interface.ts**`
```ts
export abstract class Environment {
@@ -319,7 +334,7 @@ export abstract class Environment {
}
```
**`src/environments/environment.ts`** (production — used when embedded in PHX)
`**src/environments/environment.ts**` (production — used when embedded in PHX)
```ts
import { Environment } from './environment.interface';
@@ -333,7 +348,7 @@ export const environment: Environment = {
};
```
**`src/environments/environment.development.ts`** (local development — add to `.gitignore`)
`**src/environments/environment.development.ts**` (local development — add to `.gitignore`)
```ts
import { Environment } from './environment.interface';
@@ -488,8 +503,8 @@ bootstrapPhoenixPluginCustomElement(App, '*YOUR-TAG*', appConfig).then((app) =>
});
```
- **`bootstrapPhoenixPluginCustomElement`** — creates the Angular application and registers the custom element for PHX.
- **`app.bootstrap(App)` in development** — additionally mounts the root component so `ng serve` / standalone mode works with routing.
- `bootstrapPhoenixPluginCustomElement` — creates the Angular application and registers the custom element for PHX.
- `app.bootstrap(App)` in development — additionally mounts the root component so `ng serve` / standalone mode works with routing.
The custom element tag must be **lowercase with hyphens** (e.g. `my-company-orders`). Use the same tag in your manifest.
@@ -510,12 +525,14 @@ PHX loads a JSON manifest that points to your entry script and declares the cust
}
```
| Field | Description |
|-------|-------------|
| `path` | Absolute URL to `main.js` (and base for chunk resolution) |
| `items[].tagName` | Custom element tag registered in `main.ts` |
**Local development example** (`public/manifest.json` in this repo):
| Field | Description |
| ----------------- | --------------------------------------------------------- |
| `path` | Absolute URL to `main.js` (and base for chunk resolution) |
| `items[].tagName` | Custom element tag registered in `main.ts` |
**Local development example** (`public/local.manifest.json` in this repo):
```json
{
@@ -524,11 +541,11 @@ PHX loads a JSON manifest that points to your entry script and declares the cust
}
```
**Hosted example** (`latest/manifest.json` in this repo):
**Published example** (root `manifest.json`, served from npm via unpkg):
```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 +555,7 @@ PHX loads a JSON manifest that points to your entry script and declares the cust
1. Host `main.js` (and any sibling chunks) at a URL reachable from your users' browsers — same network rules as your PHX instance.
2. Publish a manifest JSON at a stable URL.
3. In PHX: **Admin → Custom Elements** → add the manifest URL and choose a mount path or tag.
4. Log out and back in. The plugin is available at `https://your.phx.instance/customElements/*PATH*`.
4. Log out and back in. The plugin is available at `https://your.phx.instance/customElements/*PATH`*.
For local plugin-host development, see [Serving the plugin locally](#serving-the-plugin-locally).
@@ -554,7 +571,7 @@ Install the static server:
yarn add -D serve
```
**`scripts/serve-dist.mjs`**
`**scripts/serve-dist.mjs**`
```js
import { spawn } from 'node:child_process';
@@ -575,7 +592,7 @@ const child = spawn(serveBin, ['-l', port, '--cors', '--no-etag'], {
child.on('exit', (code) => process.exit(code ?? 0));
```
**`serve.json`** (replace `*PROJECT-NAME*` with your Angular project name from `angular.json`)
`**serve.json**` (replace `*PROJECT-NAME*` with your Angular project name from `angular.json`)
```json
{
@@ -601,8 +618,6 @@ Add to `package.json`:
Use a custom port: `PORT=8080 yarn serve`.
> **This repository only:** `scripts/copy-latest.mjs` copies built JS files into `latest/` so the [live demo](#live-demo) manifest can point at a stable path in git. You do not need this for local plugin-host development.
### Apollo, auth guard, and login
In **production** (embedded in PHX), authentication is handled by the host. Use the Apollo client from `IPluginServices` via `PhoenixHostBridgeService` — you do not need a separate login flow.
@@ -650,9 +665,9 @@ Apply the same pattern for other host services (e.g. notifications) when you nee
#### Login callback route
For development without a preset API key, add a `/login` route that acts as an **auth callback** — not a login form. When the user is unauthenticated, the auth guard sends them to the PHX login page (`environment.serverUrl`). After successful login, PHX redirects back to your plugin's `/login` route with an `authToken` query parameter and a base64-encoded `redirectTo` target.
For development without a preset API key, you need a way to obtain and store an API token. This demo uses a **redirect-based auth callback** on `/login` rather than an embedded login form, but either approach is valid — you can also build a login form in your plugin, call the GraphQL `login` mutation, and handle the token yourself.
The callback component stores the token in `localStorage` and navigates back to the original page:
With the redirect flow, when the user is unauthenticated, the auth guard sends them to the PHX login page (`environment.serverUrl`). After successful login, PHX redirects back to your plugin's `/login` route with an `authToken` query parameter and a base64-encoded `redirectTo` target. The callback component stores the token in `localStorage` and navigates back to the original page:
```ts
@Component({
@@ -730,32 +745,34 @@ Recommended scripts after following this guide:
}
```
| Script | Description |
|--------|-------------|
| `build` | Production watch build for PHX |
| `serve` | Serves compiled assets for PHX (default port 3223) |
| `plugin` | Runs `build` + `serve` together — use `yarn run plugin` |
| `client` | Standalone Angular dev server on port 4201 |
| `codegen` | Regenerates GraphQL TypeScript types |
This repository additionally runs `copy-latest.mjs` alongside `build` to publish artifacts into `latest/` for the hosted demo — that is not required for your own plugin.
| Script | Description |
| --------- | ------------------------------------------------------- |
| `build` | Production watch build for PHX |
| `serve` | Serves compiled assets for PHX (default port 3223) |
| `plugin` | Runs `build` + `serve` together — use `yarn run plugin` |
| `client` | Standalone Angular dev server on port 4201 |
| `codegen` | Regenerates GraphQL TypeScript types |
---
## Troubleshooting
| Symptom | Things to check |
|---------|-----------------|
| PHX shows an old version of the plugin | Hard-refresh; confirm `serve.json` sets `Cache-Control: no-store` for JS; restart `yarn run plugin` |
| Symptom | Things to check |
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| PHX shows an old version of the plugin | Hard-refresh; confirm `serve.json` sets `Cache-Control: no-store` for JS; restart `yarn run plugin` |
| `401` / GraphQL auth errors in standalone mode | Set `apiKey` in `environment.development.ts`, or ensure `serverUrl` points to your PHX instance so the login redirect works |
| `yarn add @phx-erp/shared` fails | Check network access to the public npm registry; retry `yarn install` |
| Routing broken inside PHX | Add route segments to `stripTrailingSegments` in `providePhoenixPluginWithPrimeNG` |
| Tailwind classes missing in a component | Add `@tailwind` directives to that component's `styles` |
| `yarn codegen` fails | Ensure PHX is running and the schema URL in `codegen.ts` is reachable |
| Custom element not found | Tag in manifest must exactly match `customElements.define` / `bootstrapPhoenixPluginCustomElement` |
| `yarn add @phx-erp/shared` fails | Check network access to the public npm registry; retry `yarn install` |
| Routing broken inside PHX | Add route segments to `stripTrailingSegments` in `providePhoenixPluginWithPrimeNG` |
| Tailwind classes missing in a component | Add `@tailwind` directives to that component's `styles` |
| `yarn codegen` fails | Ensure PHX is running and the schema URL in `codegen.ts` is reachable |
| Custom element not found | Tag in manifest must exactly match `customElements.define` / `bootstrapPhoenixPluginCustomElement` |
---
## Support
For integration questions or PHX-specific APIs, contact your PHX partner.
For integration questions or PHX-specific APIs, contact your PHX partner.