Skip to content

docs(electron): correct #winapp/bindings setup and ground Electron guides against 0.5.0 - #687

Draft
Nikola Metulev (nmetulev) wants to merge 2 commits into
mainfrom
audit-electron-dynwinrt-docs
Draft

docs(electron): correct #winapp/bindings setup and ground Electron guides against 0.5.0#687
Nikola Metulev (nmetulev) wants to merge 2 commits into
mainfrom
audit-electron-dynwinrt-docs

Conversation

@nmetulev

Copy link
Copy Markdown
Member

What & why

Audit + correction of the Electron dynwinrt / JS-bindings guides so they match what the current CLI (0.5.0) actually does. Grounded by building the CLI from source and running a real winapp init --add-js-bindings end-to-end, not just reading the docs.

The guides all import Windows APIs via the #winapp/bindings specifier, but the docs didn't explain how that specifier is wired (the package.json subpath imports map), and a few other steps had drifted from reality.

Changes

  • setup.md
    • Rewrote the create-electron-app step - the current CLI is non-interactive (flag-driven), not the old "when prompted, pick Bundler/Language/version" flow. Documents the real flags (--template, --electron-version, --skip-git) and the default (no bundler + JS). Dropped an inaccurate "latest stable" claim (the default resolves to the latest dist-tag).
    • Added an "Enable the #winapp/bindings import" section: explains that winapp init --add-js-bindings writes the imports map for you, shows the exact map, and gives a one-line confirm command + fallback.
    • Noted the imports-map write in the "What does winapp init do?" list.
  • index.md + js-notification.md / js-file-picker.md / js-phi-silica.md / js-winml.md - reframed the binding-import notes around init auto-wiring the map, with an ERR_MODULE_NOT_FOUND fallback (manual map or relative require).
  • js-winml.md - corrected Step 1's expected output to the six ExecutionProvider* classes actually emitted.
  • docs/fragments/skills/winapp-cli/setup.md - documented the #winapp/bindings specifier + imports map.

How it was verified

Built the CLI JS wrapper from this repo's source (identical to the v0.5.0 tag) and ran a real winapp init --add-js-bindings:

  • init prints Added "#winapp/bindings" package imports to package.json
  • package.json gets the exact imports map
  • require('#winapp/bindings') resolves out of the box (603 classes); subpath #winapp/bindings/FileOpenPicker works
  • create-electron-app flags confirmed via --help

Docs-only change; no source modified.

…nst 0.5.0

- setup.md: rewrite the create-electron-app step for the current non-interactive
  CLI (flags, templates); add an "Enable the #winapp/bindings import" section with
  the imports map + a confirm command; note that init writes the map
- index.md + js-notification/js-file-picker/js-phi-silica/js-winml: reframe the
  binding-import notes around winapp init auto-wiring the imports map, with an
  ERR_MODULE_NOT_FOUND fallback (manual map or relative require)
- js-winml.md: correct Step 1 expected output to the real six ExecutionProvider*
  classes emitted by the current Windows App SDK
- skill fragment (winapp-cli/setup.md): document the #winapp/bindings specifier
  and imports map

Grounded by building the CLI from source and running a real
winapp init --add-js-bindings, which emits the imports map so
require('#winapp/bindings') resolves out of the box.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e14cc41f-b05e-4e67-86d1-ff36e1e24086
Copilot AI review requested due to automatic review settings July 24, 2026 18:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates Electron JS-binding guides to match WinApp CLI 0.5.0 behavior.

Changes:

  • Documents non-interactive Electron scaffolding and package import mapping.
  • Updates binding troubleshooting across Electron guides.
  • Corrects expected WinML execution-provider classes.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
docs/guides/electron/setup.md Revises setup and import-map guidance.
docs/guides/electron/index.md Updates JS-binding overview.
docs/guides/electron/js-notification.md Revises binding fallback note.
docs/guides/electron/js-file-picker.md Revises binding fallback note.
docs/guides/electron/js-phi-silica.md Revises binding fallback note.
docs/guides/electron/js-winml.md Updates fallback and expected classes.
docs/fragments/skills/winapp-cli/setup.md Adds import guidance to skill source.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/guides/electron/setup.md Outdated
const { FileOpenPicker } = require('#winapp/bindings');
```

That specifier only resolves if your `package.json` has a matching [subpath `imports`](https://nodejs.org/api/packages.html#subpath-imports) map. **`winapp init --add-js-bindings` writes this map for you** — you'll see `Added "#winapp/bindings" package imports to package.json` in the init output. If it's ever missing (for example, `require('#winapp/bindings')` fails with `ERR_MODULE_NOT_FOUND`), add it yourself:
The Windows App SDK transitively depends on `Microsoft.WindowsAppSDK.ML`, so the WinML APIs are already in your generated bindings. Verify:

> **Requires `@microsoft/dynwinrt-codegen` ≥ `0.1.0-preview.8`** — see [Get started with Electron](index.md#2-call-windows-apis-from-javascript) for older-project fallbacks.
> `winapp init --add-js-bindings` wires the `#winapp/bindings` specifier into `package.json`. If `require('#winapp/bindings')` fails with `ERR_MODULE_NOT_FOUND`, see [Enable the `#winapp/bindings` import](setup.md#enable-the-winappbindings-import).
Import the generated bindings through `#winapp/bindings`, create a `TextSummarizer`, and call it at the end of `createWindow()` to verify everything works:

> **Requires `@microsoft/dynwinrt-codegen` ≥ `0.1.0-preview.8`** — see [Get started with Electron](index.md#2-call-windows-apis-from-javascript) for older-project fallbacks.
> `winapp init --add-js-bindings` wires the `#winapp/bindings` specifier into `package.json`. If `require('#winapp/bindings')` fails with `ERR_MODULE_NOT_FOUND`, see [Enable the `#winapp/bindings` import](setup.md#enable-the-winappbindings-import).
Import the generated bindings through the `#winapp/bindings` package import, build an app notification, and show it with the default notification manager:

> **Requires `@microsoft/dynwinrt-codegen` ≥ `0.1.0-preview.8`.** Older projects can either upgrade with `npm i -D @microsoft/dynwinrt-codegen@latest && npx winapp init --add-js-bindings` to have `winapp init` wire the `#winapp/bindings` imports map, or keep the relative form `require('../.winapp/bindings/index.js')` (path is relative to `src/index.js`; adjust it if your entry file lives elsewhere).
> `winapp init --add-js-bindings` wires the `#winapp/bindings` specifier into `package.json`. If `require('#winapp/bindings')` fails with `ERR_MODULE_NOT_FOUND`, see [Enable the `#winapp/bindings` import](setup.md#enable-the-winappbindings-import) — or use the relative form `require('../.winapp/bindings/index.js')` (path relative to `src/index.js`; adjust it if your entry file lives elsewhere).
All generated classes are exported through `#winapp/bindings`:

> **Requires `@microsoft/dynwinrt-codegen` ≥ `0.1.0-preview.8`** — see [Get started with Electron](index.md#2-call-windows-apis-from-javascript) for older-project fallbacks.
> `winapp init --add-js-bindings` wires the `#winapp/bindings` specifier into `package.json`. If `require('#winapp/bindings')` fails with `ERR_MODULE_NOT_FOUND`, see [Enable the `#winapp/bindings` import](setup.md#enable-the-winappbindings-import).
Comment thread docs/guides/electron/index.md Outdated
### 2. Call Windows APIs from JavaScript

If you enabled JS bindings during setup, `.winapp/bindings/` contains generated `.js` wrapper classes and matching `.d.ts` declarations for Windows App SDK APIs. Import `#winapp/bindings` to access all exported classes. The `#winapp/bindings` package import requires `@microsoft/dynwinrt-codegen` ≥ `0.1.0-preview.8`; older projects can keep a path relative to the importing file (for example, `require('../.winapp/bindings/index.js')` from `src/index.js`) or upgrade with `npm i -D @microsoft/dynwinrt-codegen@latest && npx winapp init --add-js-bindings`.
If you enabled JS bindings during setup, `.winapp/bindings/` contains generated `.js` wrapper classes and matching `.d.ts` declarations for Windows App SDK APIs. Import `#winapp/bindings` to access all exported classes. `winapp init --add-js-bindings` wires this specifier into your `package.json` `imports` map. If `require('#winapp/bindings')` ever fails with `ERR_MODULE_NOT_FOUND`, follow [Enable the `#winapp/bindings` import](setup.md#enable-the-winappbindings-import) to add it, or import the generated `index.js` by a path relative to the importing file (for example `require('../.winapp/bindings/index.js')` from `src/index.js`).
- `.winapp/bindings/` — generated JS bindings for Windows App SDK APIs (npm-only, Node / Electron)
- `package.json` update — adds the `winapp.jsBindings` namespace and `@microsoft/dynwinrt` dependency (npm-only)

Import the generated classes with the `#winapp/bindings` specifier (e.g. `require('#winapp/bindings')`). `winapp init --add-js-bindings` adds the matching subpath `imports` map to `package.json`. If `require('#winapp/bindings')` fails with `ERR_MODULE_NOT_FOUND`, add the map manually (or import `.winapp/bindings/index.js` by a relative path). See [Enable the `#winapp/bindings` import](https://github.com/microsoft/WinAppCli/blob/main/docs/guides/electron/setup.md#enable-the-winappbindings-import).
- `.winapp/bindings/` — generated JS bindings for Windows App SDK APIs (npm-only, Node / Electron)
- `package.json` update — adds the `winapp.jsBindings` namespace and `@microsoft/dynwinrt` dependency (npm-only)

Import the generated classes with the `#winapp/bindings` specifier (e.g. `require('#winapp/bindings')`). `winapp init --add-js-bindings` adds the matching subpath `imports` map to `package.json`. If `require('#winapp/bindings')` fails with `ERR_MODULE_NOT_FOUND`, add the map manually (or import `.winapp/bindings/index.js` by a relative path). See [Enable the `#winapp/bindings` import](https://github.com/microsoft/WinAppCli/blob/main/docs/guides/electron/setup.md#enable-the-winappbindings-import).
Lead Step 3 with a single opinionated command (winapp init --add-js-bindings --use-defaults) plus a grounded expected-output/confirm check, and collapse the interactive prompts, the 'what init did' list, and troubleshooting into <details>. Reframe Step 1 to state the default template up front with alternatives collapsed. De-conditionalize index.md so JS bindings read as the primary path. Preserves the #enable-the-winappbindings-import anchor referenced across the guides.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: e14cc41f-b05e-4e67-86d1-ff36e1e24086
Copilot AI review requested due to automatic review settings July 24, 2026 18:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (7)

docs/guides/electron/setup.md:125

  • This recovery path conflates a missing imports map with bindings that were never generated. Adding the JSON map after skipping bindings leaves every target under .winapp/bindings/ absent, so require still fails. It also names the wrong missing-alias error: Node reports ERR_PACKAGE_IMPORT_NOT_DEFINED for an undefined # package import.
<summary><code>require('#winapp/bindings')</code> fails with <code>ERR_MODULE_NOT_FOUND</code>, or you skipped bindings during init?</summary>

The specifier resolves through a [subpath `imports`](https://nodejs.org/api/packages.html#subpath-imports) map in `package.json`. If it's missing, add it:

docs/guides/electron/js-winml.md:24

  • This removes a still-required compatibility condition. For an existing project whose declared, installed @microsoft/dynwinrt-codegen predates 0.1.0-preview.8, ensureCodegenInstalledForInit intentionally keeps that version and handleInit skips the imports map because the old generator lacks package-shaped dual output. Also, a missing # alias is reported as ERR_PACKAGE_IMPORT_NOT_DEFINED, not ERR_MODULE_NOT_FOUND. Restore the upgrade fallback instead of claiming every init run wires the alias.
> `winapp init --add-js-bindings` wires the `#winapp/bindings` specifier into `package.json`. If `require('#winapp/bindings')` fails with `ERR_MODULE_NOT_FOUND`, see [Enable the `#winapp/bindings` import](setup.md#enable-the-winappbindings-import).

docs/guides/electron/js-phi-silica.md:33

  • This removes a still-required compatibility condition. For an existing project whose declared, installed @microsoft/dynwinrt-codegen predates 0.1.0-preview.8, init preserves that version and deliberately skips the imports map because its output is incompatible. The missing-alias error is also ERR_PACKAGE_IMPORT_NOT_DEFINED, not ERR_MODULE_NOT_FOUND. Restore the upgrade fallback.
> `winapp init --add-js-bindings` wires the `#winapp/bindings` specifier into `package.json`. If `require('#winapp/bindings')` fails with `ERR_MODULE_NOT_FOUND`, see [Enable the `#winapp/bindings` import](setup.md#enable-the-winappbindings-import).

docs/guides/electron/js-notification.md:15

  • This removes a still-required compatibility condition. Existing projects with a declared, installed codegen older than 0.1.0-preview.8 keep that version during init, and the wrapper deliberately skips the imports map because those outputs are incompatible. The undefined-alias error is also ERR_PACKAGE_IMPORT_NOT_DEFINED. Keep the relative fallback, but restore the upgrade instruction.
> `winapp init --add-js-bindings` wires the `#winapp/bindings` specifier into `package.json`. If `require('#winapp/bindings')` fails with `ERR_MODULE_NOT_FOUND`, see [Enable the `#winapp/bindings` import](setup.md#enable-the-winappbindings-import) — or use the relative form `require('../.winapp/bindings/index.js')` (path relative to `src/index.js`; adjust it if your entry file lives elsewhere).

docs/guides/electron/js-file-picker.md:64

  • This removes a still-required compatibility condition. Existing projects with a declared, installed @microsoft/dynwinrt-codegen older than 0.1.0-preview.8 retain it during init, and the wrapper skips map generation because that version lacks compatible dual output. Node also reports an undefined # alias as ERR_PACKAGE_IMPORT_NOT_DEFINED. Restore the upgrade fallback.
> `winapp init --add-js-bindings` wires the `#winapp/bindings` specifier into `package.json`. If `require('#winapp/bindings')` fails with `ERR_MODULE_NOT_FOUND`, see [Enable the `#winapp/bindings` import](setup.md#enable-the-winappbindings-import).

docs/guides/electron/index.md:47

  • Node's package-import resolver reports a missing #winapp/bindings entry as ERR_PACKAGE_IMPORT_NOT_DEFINED; ERR_MODULE_NOT_FOUND generally means the map resolved to a target that is absent. Pointing the wrong error at the imports-map fix makes this troubleshooting instruction misleading.
If `require('#winapp/bindings')` ever fails with `ERR_MODULE_NOT_FOUND`, see [Enable the `#winapp/bindings` import](setup.md#enable-the-winappbindings-import).

docs/fragments/skills/winapp-cli/setup.md:65

  • The shipped setup skill now tells older projects to add a map that init deliberately withholds when their declared codegen predates 0.1.0-preview.8; those generators do not provide the package-shaped dual output the map assumes. It also checks for the wrong missing-alias error (ERR_PACKAGE_IMPORT_NOT_DEFINED is the relevant code). Preserve the upgrade path so agent-generated guidance remains safe for existing projects.
Import the generated classes with the `#winapp/bindings` specifier (e.g. `require('#winapp/bindings')`). `winapp init --add-js-bindings` adds the matching subpath `imports` map to `package.json`. If `require('#winapp/bindings')` fails with `ERR_MODULE_NOT_FOUND`, add the map manually (or import `.winapp/bindings/index.js` by a relative path). See [Enable the `#winapp/bindings` import](https://github.com/microsoft/WinAppCli/blob/main/docs/guides/electron/setup.md#enable-the-winappbindings-import).
3. **`Assets/`** — app icons and visual assets
4. **`winapp.yaml`** — tracks SDK versions and project configuration
5. **Windows App SDK runtime** — required runtime components for modern APIs
6. **Developer Mode** — enabled in Windows for debugging
@github-actions

Copy link
Copy Markdown
Contributor

Build Metrics Report

Binary Sizes

Artifact Baseline Current Delta
CLI (ARM64) 32.43 MB 32.43 MB ✅ 0.0 KB (0.00%)
CLI (x64) 32.74 MB 32.74 MB 📉 -0.5 KB (-0.00%)
MSIX (ARM64) 13.58 MB 13.58 MB 📉 -0.1 KB (-0.00%)
MSIX (x64) 14.44 MB 14.44 MB 📉 -0.1 KB (-0.00%)
NPM Package 28.35 MB 28.35 MB 📉 -0.3 KB (-0.00%)
NuGet Package 28.36 MB 28.36 MB 📉 -0.2 KB (-0.00%)

Test Results

3616 passed, 4 skipped out of 3620 tests in 760.3s (+116.7s vs. baseline)

Test Coverage

95.2% line coverage, 89.4% branch coverage · ✅ no change vs. baseline

CLI Startup Time

33ms median (x64, winapp --version) · 📉 -11ms vs. baseline


Updated 2026-07-24 19:04:34 UTC · commit 54288b3 · workflow run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants