diff --git a/docs/cordis-tutorial/01-first-plugin.md b/docs/cordis-tutorial/01-first-plugin.md index cd4f060b03..084f9964e1 100644 --- a/docs/cordis-tutorial/01-first-plugin.md +++ b/docs/cordis-tutorial/01-first-plugin.md @@ -26,7 +26,7 @@ This tutorial's launcher assembles the application from configuration. Create `c - name: './hello.ts' ``` -The file is a list of plugin entries. `name` is a module specifier — a relative path or an npm package name — and the loader mounts each entry in order. +The file is a list of plugin entries. `name` is a module specifier — a relative path or an npm package name — and the loader mounts every entry. Entries start concurrently, so list position guarantees nothing about which plugin loads first; ordering comes from service dependencies (`inject`, [chapter 3](03-services.md)), not from position in the file. ## Run it diff --git a/docs/cordis-tutorial/02-lifecycle-and-effects.md b/docs/cordis-tutorial/02-lifecycle-and-effects.md index 4f3534a0eb..68a0f12ec8 100644 --- a/docs/cordis-tutorial/02-lifecycle-and-effects.md +++ b/docs/cordis-tutorial/02-lifecycle-and-effects.md @@ -27,11 +27,16 @@ function heartbeat(ctx: Context) { export function apply(ctx: Context) { // Mount a child plugin and keep its fiber to dispose it later. const fiber = ctx.plugin(heartbeat) - setTimeout(async () => { - await fiber.dispose() - console.log('disposed') - process.exit(0) - }, 700) + // The demo timer is itself an effect: if THIS plugin is unloaded first, + // the pending callback is cancelled instead of firing on a dead app. + ctx.effect(() => { + const timer = setTimeout(async () => { + await fiber.dispose() + console.log('disposed') + process.exit(0) + }, 700) + return () => clearTimeout(timer) + }) } ``` diff --git a/docs/cordis-tutorial/06-composition-and-hmr.md b/docs/cordis-tutorial/06-composition-and-hmr.md index dd5020db0a..b11fdbe45c 100644 --- a/docs/cordis-tutorial/06-composition-and-hmr.md +++ b/docs/cordis-tutorial/06-composition-and-hmr.md @@ -25,12 +25,16 @@ Because unloading releases effects ([chapter 2](02-lifecycle-and-effects.md)) an In `tmp/cordis-tutorial`, write `cordis.yml`: ```yaml -- name: '@cordisjs/plugin-logger-console' -- name: '@cordisjs/plugin-timer' -- name: '@cordisjs/plugin-hmr' +- id: logger + name: '@cordisjs/plugin-logger-console' +- id: timer + name: '@cordisjs/plugin-timer' +- id: hmr + name: '@cordisjs/plugin-hmr' config: root: ['.'] -- name: './hello.ts' +- id: hello + name: './hello.ts' ``` Two support plugins joined the list: HMR logs through the Cordis logger service, so without a console exporter you would not see its messages, and it `inject`s the `timer` service for debouncing — without `@cordisjs/plugin-timer` it sits in PENDING forever, silently. That silence is the subject of the next section. @@ -50,7 +54,7 @@ hello from my first plugin hello from my EDITED plugin ``` -The old instance unloaded (all its effects unwound), the new code loaded, `apply` ran again. Stop the process with Ctrl-C. Editing `cordis.yml` itself is also picked up: the loader diffs entries by `id` and mounts, unmounts, or reconfigures only what changed. +The old instance unloaded (all its effects unwound), the new code loaded, `apply` ran again. Stop the process with Ctrl-C. Editing `cordis.yml` itself is also picked up: the loader diffs entries by `id` and mounts, unmounts, or reconfigures only what changed. This is why the entries above carry explicit `id`s — an entry without one gets a generated id on every read, so after any config-file edit it counts as removed-plus-added and remounts even if its own lines did not change. ## Diagnosing a plugin that never loads