diff --git a/tko.io/public/agents/soul.md b/tko.io/public/agents/soul.md index 4cc092b11..268444c59 100644 --- a/tko.io/public/agents/soul.md +++ b/tko.io/public/agents/soul.md @@ -83,6 +83,36 @@ script tag, verify your tests pass, ship. From there, adopting modern features (TSX, native providers, modular packages) is incremental and optional. +The two builds wire the same core differently. Concretely, comparing +`builds/knockout/src/index.ts` and `builds/reference/src/index.ts`: + +- **Providers.** Both ship `Component`, `DataBind`, `Virtual`, and + `Attribute`. `reference` additionally enables `Native`, + `AttributeMustache`, and `TextMustache`. `knockout` does not. Provider + order is resolution precedence and differs too: + - `knockout`: `Component` -> `DataBind` -> `Virtual` -> `Attribute` + - `reference`: `Component` -> `Native` -> `AttributeMustache` -> + `TextMustache` -> `DataBind` -> `Virtual` -> `Attribute` +- **Equality.** `reference` sets `options.strictEquality = true`, so `==` + and `!=` in binding expressions evaluate as `===` / `!==`. `knockout` + leaves the legacy lax behavior on. +- **Globals in bindings.** `knockout` sets + `bindingGlobals: options.global`, exposing the global scope inside + binding expressions. `reference` does not. +- **Inline-function rewrite.** `knockout` registers + `functionRewrite` from `@tko/utils.functionrewrite` as a binding-string + preparser, so legacy inline `function (...) { ... }` expressions in + `data-bind` still work. `reference` has no `functionRewrite` preparser. +- **`foreach` binding target.** `knockout` resolves + `data-bind="foreach: ..."` to `TemplateForEachBindingHandler` (legacy + template-engine path), while `reference` resolves it to modern + `ForEachBinding` from `@tko/binding.foreach`. Both resolve + `data-bind="each: ..."` to `ForEachBinding`. +- **Legacy surface.** `knockout` exposes a + `ko.expressionRewriting.preProcessBindings` shim for KO 3 plugins. + `reference` exposes `ko.jsx = { createElement, Fragment, render }` for + TSX. Neither has the other. + TKO aims for stability, not strict backwards compatibility at all costs. If a change improves correctness, security, or maintainability and the migration path is clear, it's worth making. But gratuitous breakage is diff --git a/tko.io/src/content/docs/3to4.md b/tko.io/src/content/docs/3to4.md index 024cd6c10..d698f4161 100644 --- a/tko.io/src/content/docs/3to4.md +++ b/tko.io/src/content/docs/3to4.md @@ -12,9 +12,9 @@ TKO keeps the familiar Knockout programming model, but changes the packaging, bu ## Start with the right package - **`@tko/build.knockout`** - Recommended for most migrations. It is the compatibility-focused build and the closest match for a traditional Knockout application. + Recommended for most migrations. Closest to a traditional Knockout 3.x application: lax `==`/`!=` in expressions, globals visible inside bindings, the legacy `function (...) { ... }` rewrite for inline `data-bind` callbacks, and a `ko.expressionRewriting.preProcessBindings` shim for plugins that reach for it. - **`@tko/build.reference`** - Better for custom or modular setups where you want to compose providers and features more explicitly, and the build used by the TSX / `ko-*` docs path. + The modern, modular path used by the TSX / `ko-*` docs. Adds the native, text-mustache, and attribute-mustache providers; switches `==`/`!=` to strict equality (`options.strictEquality`); has no legacy `functionRewrite` preparser and no `expressionRewriting` shim; and exposes `ko.jsx` for TSX rendering. ## The biggest changes @@ -80,6 +80,53 @@ TKO is designed for stricter Content Security Policies and avoids the older `eva | CSP-friendly binding parser | No | Yes | Yes | | Legacy compatibility workarounds | More common | Reduced | Reduced | +### Build deltas in detail + +Both TKO builds share the same foundational packages (`@tko/builder`, +observables, computeds, core/template/if/component bindings, and the punches +filter syntax). They differ in provider order, which options default +differently, which `foreach` handler wins, and which surface APIs they expose. + +#### Providers (binding-resolution strategies) + +| Provider | What it recognizes | `@tko/build.knockout` | `@tko/build.reference` | +| --- | --- | --- | --- | +| `ComponentProvider` | `` components | Yes | Yes | +| `DataBindProvider` | `data-bind="..."` strings | Yes | Yes | +| `VirtualProvider` | `` comments | Yes | Yes | +| `AttributeProvider` | `ko-foo="expression"` string attributes | Yes | Yes | +| `NativeProvider` | `el.bindings = {...}` set in JS / TSX | No | Yes | +| `AttributeMustacheProvider` | `attr="prefix {{expr}} suffix"` interpolation | No | Yes | +| `TextMustacheProvider` | `{{ expr }}` in text nodes | No | Yes | + +Provider order is resolution precedence, and it differs: + +- `@tko/build.knockout`: `ComponentProvider` -> `DataBindProvider` -> `VirtualProvider` -> `AttributeProvider` +- `@tko/build.reference`: `ComponentProvider` -> `NativeProvider` -> `AttributeMustacheProvider` -> `TextMustacheProvider` -> `DataBindProvider` -> `VirtualProvider` -> `AttributeProvider` + +#### Binding-expression behavior + +| Behavior | `@tko/build.knockout` | `@tko/build.reference` | +| --- | --- | --- | +| `==` / `!=` evaluated as `===` / `!==` (`options.strictEquality`) | No | Yes | +| Bindings see globals (`options.bindingGlobals`) | Yes (`options.global`) | No | +| Inline `function (...) { ... }` rewritten in `data-bind` (`functionRewrite` preparser) | Yes | No | +| `ko.expressionRewriting.preProcessBindings(s)` legacy stub | Yes | No | +| `data-bind="foreach: ..."` resolves to | `TemplateForEachBindingHandler` (legacy template-engine path) | `ForEachBinding` (modern, from `@tko/binding.foreach`) | +| `data-bind="each: ..."` resolves to | `ForEachBinding` | `ForEachBinding` | + +#### Surface APIs + +| API | `@tko/build.knockout` | `@tko/build.reference` | +| --- | --- | --- | +| `ko.observable` / `ko.computed` / `ko.applyBindings` / components | Yes | Yes | +| `ko.expressionRewriting` (legacy KO 3 plugin shim) | Yes | No | +| `ko.jsx.createElement` / `Fragment` / `render(jsx)` | No | Yes | + +The reference build is what the TSX / `ko-*` examples in this docs set rely on, +because TSX needs `NativeProvider` (to read `el.bindings`) and the `ko.jsx` +render helper. + ## When not to migrate yet - Your templates rely heavily on legacy inline binding expressions you cannot easily change.