@khester/create-dynamics-app
v3.4.2
Published
Unified CLI to scaffold Dynamics 365 / Power Platform artifacts
Downloads
1,280
Maintainers
Readme
create-dynamics-app
Unified CLI to scaffold Dynamics 365 / Power Platform artifacts — one tool, per-artifact templates, a Fluent v8/v9 choice, integrated dev-tools, and an optional from-design mode.
create-dynamics-app <project-name> --artifact <id> [--v8|--v9]Quick start
Prerequisite: Node 20+ (engines.node >= 20). Every package is public on npm — no login, no auth, no private registry.
Scaffold a Dynamics custom page and run it (the scaffold step runs npm install for you):
npx @khester/create-dynamics-app my-custom-page --artifact react-custom-page --v8
cd my-custom-page
npm run dev # webpack dev server + mock Xrm — open in the browser
npm run build # production bundle → dist/ (deployable web resource)- Run with no flags (
npx @khester/create-dynamics-app my-custom-page) for an interactive picker. - Use
--v9for Fluent UI v9 (default is v8 — the safe choice for Power Pages / Dynamics). - Add
--with-componentsto also install the@khester/reusable-componentsFluent v8 set (see Flags). - Pin a version (
@khester/[email protected]) for reproducible builds.
Connect to a live Dataverse org (optional)
The scaffold ships dev-tools that pull real metadata. Needs the Azure CLI (az login into the tenant) or DYNAMICS_* env vars:
npm run auth:token # az → token written to .env (git-ignored)
npm run metadata:pull -- --entities account,contact # live metadata → typed src/constants + src/modelsArtifacts (--artifact)
| id | What it scaffolds | Fluent |
|----|-------------------|--------|
| react-custom-page | React SPA for a model-driven custom page | v8 |
| host-swap | One component, three hosts — one host-agnostic Component.tsx (coded against an injected IApiService) + a thin per-host wrapper; pick PCF, a custom page, or a web resource with --host (see below) | v8 |
| grid-starter | React custom page rendering a grid-kit <DataGrid> over a cell-renderer registry | v8 |
| starter-page | Dynamics page built on a selectable @dataverse-kit/surface-kit surface (--surface) | v8 |
| power-pages-island | React island mounted into an existing traditional (Liquid) Power Pages portal — a webpack bundle uploaded as a web file that injects PortalSeamService (portal /_api/); the same host-swap Component runs here (see below) | v8 |
| pcf-field | PCF field control (property-type aware: text/number/boolean/date) | v8 |
| pcf-dataset | PCF dataset/grid control — grid-kit <ReadOnlyGrid> (sort/filter/columns/search), model-driven, React 16.14.0 | v8 |
| grid-customizer | PowerAppsOneGrid cell-renderer customizer — a virtual PCF control that registers cellRendererOverrides via factory.fireEvent (status badges, signed currency, yes/no ticks, per-column progress) | v8 |
| web-resource | React web resource (webpack bundle) | v8 or v9 |
| dialog-form | Single React form host (opened as a dialog) | v8 or v9 |
| static-web-app | Azure SWA — React frontend + Functions api/ | v8 or v9 |
| teams-app | Teams tab (React + teams-js) — basic, SSO, dashboard, or in-meeting side panel/stage (--tab-kind), optional Graph (--graph) | v9 |
| teams-bot | Teams bot / message extension (Bot Framework SDK v4 + Express, mock mode) — echo, proactive notifications, or compose-box search/action/link (--bot-kind) | — |
Run with no flags for an interactive picker.
Host-swap — write once, switch host
The host-swap artifact is the host-portability story: you write one src/Component.tsx
against the injected IApiService data-access seam, and a thin per-host wrapper supplies the
service and mounts it. The component source never changes — only the wrapper does. Pick the
host with --host:
npx @khester/create-dynamics-app my-control --artifact host-swap --host pcf
# --host custom-page → Vite app mounted as a Dynamics custom page (ServiceFactory ladder)
# --host pcf → pcf-scripts virtual ReactControl (same-origin FetchApiService, React 18)
# --host web-resource → webpack-bundled web resource (same-origin FetchApiService)Each host builds the same component under its own toolchain (Vite / pcf-scripts / webpack);
all three are exercised by CI build gates. To retarget, scaffold with another --host and copy
your src/Component.tsx across.
Power Pages island — React into an existing traditional portal
The power-pages-island artifact is the delta Microsoft's Power Pages tooling doesn't cover: the
pac/plugin code-site scaffolder builds a whole-page React SPA that is the site. It cannot drop
a React widget into an existing traditional (Liquid) portal. This artifact does — it's a webpack
bundle you upload as a web file and mount into Liquid-placed nodes:
<div data-dvkit-island="accounts"></div>
<script src="/my-widget.js"></script>src/islands.tsx hydrates React into every [data-dvkit-island] node (partial hydration — the rest of
the Liquid page is untouched). Data access is the same injected IApiService seam as host-swap:
in the browser it's given PortalSeamService from
@dataverse-kit/portal-api-service
(portal /_api/ + anti-forgery), on localhost the in-memory mock. The src/Component.tsx is
byte-identical to host-swap's, so the same widget also runs as a PCF control / custom page / web
resource. Fluent v8 (v9 is broken on portals); React 18. See the generated README.md for the
web-file upload + per-table Web API gating (Webapi/<table>/enabled + /fields + table permission).
Flags
-a, --artifact <id>— artifact to scaffold (see table).--v8/--v9(or-l, --library fluent-v8|fluent-v9) — Fluent version for artifacts that support a choice. Only the chosen library is installed.-n, --namespace,--component-name,--property-type— PCF options.--host <custom-page|pcf|web-resource>— host target for thehost-swapartifact (defaultcustom-page).--surface <form|panel|dashboard|master-detail>— surface for thestarter-pageartifact.--graph— include Microsoft Graph (teams-app).--tab-kind <basic|sso|dashboard|meeting>— tab kind for theteams-appartifact (defaultbasic).meetingis an in-meeting app (side panel + shared stage viashareAppContentToStage).--bot-kind <echo|notification|message-extension>— bot kind for theteams-botartifact (defaultecho).message-extensionis a Bot-Framework-backed compose-box search / action / link-unfurling extension.--with-components— install@khester/reusable-components(a curated Fluent v8 React set:ReusableCard,CustomSection,FileUploadField,SearchComponent,DetailsListComponent, the localhost-gatedlogger, …) plus its@fluentui/reactv8 peer. Opt-in for the v8 React hosts that don't already bundle it —web-resource,dialog-form(react-custom-page,grid-starter,host-swap, andpower-pages-islandship it as a base/transitive dependency already); warned-and-ignored elsewhere; errors if combined with--v9.--from-design <file>— generate from a form-builder export (aFormBuilderProjectJSON, e.g. from/generate-form). Wraps@dataverse-kit/export-engineto produce a deployable project (host + form code + a design-derived data layer). Supported targets:web-resource,pcf,static-web-app. From-design output is generated by the export engine and is structurally different from a blank starter (it ships its own token tooling);package.json.dynamicsKit.artifactrecords which.--skip-git,--skip-install.
Dev-tools (in generated projects)
Blank starters get package.json scripts for: auth:token (Azure CLI → .env), metadata:pull (typed entities via dvgen), smoke:live (live-org retrieve), plus a mock-Xrm helper for local serve.
Breaking changes in 3.0.0
See CHANGELOG.md. The fictional power-pages artifact (a placeholder that imported an unpublished API client and never worked) is removed and replaced by the real power-pages-island. --template power-pages now hard-deprecates (errors with guidance) like --template dynamics-365|pcf-control — use --artifact power-pages-island.
Breaking changes in 2.0.0
See CHANGELOG.md. In short: removed the consulting flags (-c/-e/-p/-d/--generate-sample); --template dynamics-365|pcf-control are removed (use --artifact react-custom-page / --artifact pcf-field).
Testing & coverage boundaries
- Unit + smoke tests (
npm test) run the scaffold pipeline for all 13 artifacts (zero-residual-token + variant/prune checks) but do notnpm installor build the generated projects, except the build gates below. - Build gates (
npm run test:e2e) scaffold +npm install+ build the React custom-page templates (Vite), the PCF templates (pcf-scripts), and all threehost-swaphosts (custom-page → Vite, pcf → pcf-scripts, web-resource → webpack) — the host-swap gates prove oneComponent.tsxbuilds under every host toolchain. - React artifacts are verified to
tsc --noEmitclean for v8 and v9 via manual installs; PCF type-correctness (against generatedManifestTypesfrompcf-scripts refreshTypes) is verified manually, not in CI. - The
--from-designgenerated-project build is verified manually.
