Skip to content

Commit

Permalink
v0.17 blog post and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
dgeb committed Jan 31, 2022
1 parent ff96899 commit a038ec5
Show file tree
Hide file tree
Showing 13 changed files with 875 additions and 210 deletions.
2 changes: 1 addition & 1 deletion website/blog/2021-07-16-welcome-to-the-new-orbitjs.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ with code, preferably even in the same PRs.
I'm especially excited to announce that we are finally publishing API reference
docs, generated with [TypeDoc](https://typedoc.org/), alongside the Orbit
guides. The first API docs available are for the upcoming v0.17, which can be
accessed directly [here](/docs/next/api) or by choosing `Next` from the
accessed directly [here](/docs/api/index.md) or by choosing `Next` from the
documentation version selector in the upper right.

While the current API docs are much better than nothing, the prose and examples
Expand Down
136 changes: 136 additions & 0 deletions website/blog/2022-01-31-v0-17-released.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
---
title: v0.17 is finally final!
author: Dan Gebhardt
author_title: Orbit.js Creator
author_url: https://github.com/dgeb
author_image_url: https://avatars.githubusercontent.com/u/29122?v=4
tags: [release]
---

After two years, 28 beta releases, and over 400 commits, Orbit v0.17 is finally
ready! 🎉

Orbit's docs have been updated to reflect all the changes. If you are upgrading
from v0.16, the place to start is the overview of [what's
new](/docs/whats-new).

Some highlights of this release include:

* **New API reference docs** — At long last, Orbit v0.17 has [API
docs](/docs/api) for all its packages. These docs are generated by
[TypeDoc](https://typedoc.org/) from Orbit's typings and code annotations.
Although a bit sparse for now, this reference should only improve with time
and help from the community.

* **Improved, strict typings throughout** — By improving the quality of
Orbit's TypeScript, we have been able to refactor more confidently, provide
better documentation, and make for a better developer experience all around.

* **Extraction of `@orbit/records` from `@orbit/data`** — As part of the
push to improve typings, it became clear that [`@orbit/data`](/docs/api/data)
contains a number of interfaces and classes that could prove useful for _any_
type of data, not just records. Thus, record-specific types and classes
were extracted into a new package: [`@orbit/records`](/docs/api/records).
Apologies for the breaking changes with module imports. We wanted to get this
churn out of the way before the semver constraints that will come with v1.0.

* **Multi-expression queries** — Just as transforms can contain multiple
operations, queries can now contain multiple expressions. This allows sources,
such as `JSONAPISource`, to optionally perform these expressions in parallel.

* **Per-expression/operation options** — Along with the move to
multi-expression queries, we've introduced per-expression options. This can be
useful if, for instance, you want to specify a different target `url` per
expression. Similarly, transform operations can also each have their own
options.

* **Full vs. data-only responses** — All requests (queries and updates)
can now be made with the `{ fullResponse: true }` option to receive responses
in the form `{ data, details, transforms, sources }`. `data` will include the
primary data that would be returned without the `fullResponse` option.
`details` includes response details particular to the source, and `sources`
includes a named map of all the responses from downstream sources that
participated in this request. This allows you to access full response
documents, inverse operations, etc. _from the initial request call point_.

* **Deprecation of `Pullable` and `Pushable` interfaces** — Now that
responses can include full processing details, everything that was unique to
the `push` and `pull` methods on source is redundant. The `Pullable` and
`Pushable` interfaces have been deprecated to focus on the more capable
`Queryable` and `Updatable` interfaces for making requests.

* **Transform buffers for faster cache processing** — Record-cache-based
sources that interact with browser storage have had performance issues when
dealing with large datasets, especially when paired with read/write heavy
processors that ensure relationship tracking and correctness. A new paradigm
has been developed, the `RecordTransformBuffer`, that acts as a memory buffer
for these operations. For now, using this buffer is opt-in, with the `{
useBuffer: true }` option. You'll be reminded to explicitly set this option to
either `true` or `false` until you do. Early users are reporting promising
results with IndexedDB, such as [performance boosts of > 20x with large
numbers of
operations](https://github.com/orbitjs/orbit/issues/798#issuecomment-800544909).

* **New serializers** — Concepts of serialization have, up until now, been
very specific to usage by the `JSONAPISource`, and particularly the
`JSONAPISerializer` class. This class has been deprecated and replaced with a
series of composable serializers all built upon a simple and flexible
[`Serializer`](/docs/api/serializers/interfaces/Serializer) interface. This
interface, as well as some serializers for primitives (booleans, dates,
date-times, etc.) have been published in a new package,
[`@orbit/serializers`](/docs/api/serializers). And of course, new serializers
particular to JSON:API have been added to
[`@orbit/jsonapi`](/docs/api/jsonapi).

* **New validators** — A common source of problems for Orbit developers
has been using data that is malformed or doesn't align with a schema's
expectations. This can cause confusing errors during processing by a cache or
downstream source. To address this problem, we're introducing "validators",
which are shipped in a new package [`@orbit/validators`](/docs/api/validators)
that includes some validators for primitive types. Validators that are
record-specific have also been included in
[`@orbit/records`](/docs/api/records). By default, each source will build its
own set of validators and use them automatically. You can instead share a
common set of validators via the `validatorFor` settings. And you can opt-out
of using validators entirely by configuring your sources with `{ autoValidate:
false }`.

* **Record normalizers** — When building queries and transforms, some
scenarios have been more tedious than necessary: identifying records by a key
instead of `id`, for instance, or using a model class from a lib like
ember-orbit to reference a record instead of its json identity. A new
abstraction has been added to make query and transform builders more flexible:
record normalizers. Record normalizers implement the
[`RecordNormalizer`](/docs/api/records/interfaces/RecordNormalizer) interface
and convert record identities and/or data into a normalized form. The new base
normalizer now allows `{ type, key, value }` to be used anywhere that `{ type,
id }` identities can be used, which significantly reduces the annoyance of
working with remote keys. Other normalizers,

* **Synchronous change tracking in memory forks** — Previously, memory
source forks behaved precisely like other memory sources: every trackable
update applied at the source level (and thus async). Now, the default (but
overrideable) behavior is to track changes at the cache level in forks. Thus
synchronous changes can be made to a forked cache and then merged back into
the base source. This better accomodates the most common use case for forks:
editing form data in isolation before merging coalesced changes back to the
base.

* **Debug mode** — A new `debug` setting has been added to the `Orbit`
global, that toggles between using a more verbose, developer-friendly "debug"
mode of Orbit vs. a leaner, more performant production mode. Since debug mode
is enabled by default, you'll need to set `Orbit.debug = false` in order to
eliminate deprecation warnings and other debug-friendly messaging.

* **Increased reliance on The Platform™** — Orbit's codebase continues to
evolve with the web, adopting new ES language and web platform features as
they are released. Custom utilities have been gradually deprecated and phased
out of the codebase (e.g. `isArray` -> `Array.isArray`), new language features
such as nullish coalescing and optional chaining have been adopted, and
platform features such as `crypto.randomUUID` have been adopted (with a
fallback implementation if unavailable).

Thanks for your patience with this release. We expect that v0.18 will not take
nearly as long as v0.17 did. In fact, we plan to use this next release primarily
to remove deprecated interfaces in preparation for a lean and focused v1.0
release.
103 changes: 52 additions & 51 deletions website/docs/coordination.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ title: Coordination strategies
---

Orbit provides another layer of abstraction on top of direct event observation
and handling: a `Coordinator`. A coordinator manages a set of sources to which
it applies a set of coordination strategies.
and handling: a [`Coordinator`](./api/coordinator/classes/Coordinator.md). A
coordinator manages a set of sources to which it applies a set of coordination
strategies.

## Why use a coordinator?

Expand All @@ -31,8 +32,8 @@ coordination strategies between sources.

A coordinator can be created with sources and strategies:

```javascript
import Coordinator from "@orbit/coordinator";
```typescript
import Coordinator from '@orbit/coordinator';

const coordinator = new Coordinator({
sources: [memory, backup],
Expand All @@ -43,8 +44,8 @@ const coordinator = new Coordinator({
Or sources and strategies can be added / removed any time the coordinator is
inactive:

```javascript
import Coordinator from "@orbit/coordinator";
```typescript
import Coordinator from '@orbit/coordinator';

const coordinator = new Coordinator();

Expand All @@ -58,20 +59,20 @@ coordinator.addStrategy(backupMemorySync);
A coordinator won't actually do anything until it's been "activated", which is
an async process that activates all of the coordinator's strategies:

```javascript
```typescript
coordinator.activate().then(() => {
console.log("Coordinator is active");
console.log('Coordinator is active');
});
```

Note that you can assign a log-level when activating a coordinator, and it
will be applied to all of the coordinator's strategies:

```javascript
import { LogLevel } from "@orbit/coordinator";
```typescript
import { LogLevel } from '@orbit/coordinator';

coordinator.activate({ logLevel: LogLevel.Info }).then(() => {
console.log("Coordinator will be chatty");
console.log('Coordinator will be chatty');
});
```

Expand All @@ -82,9 +83,9 @@ Possible log levels include `None`, `Errors`, `Warnings`, and `Info`.
If you want to temporarily disable a coordinator or change its settings, you
can deactivate it:

```javascript
```typescript
coordinator.deactivate().then(() => {
console.log("Coordinator is inactive");
console.log('Coordinator is inactive');
});
```

Expand Down Expand Up @@ -114,17 +115,17 @@ request strategy should be defined with:
Here are some example strategies that query / update a remote server
pessimistically whenever a memory source is queried / updated:

```javascript
import { RequestStrategy } from "@orbit/coordinator";
```typescript
import { RequestStrategy } from '@orbit/coordinator';

// Query the remote server whenever the memory source is queried
coordinator.addStrategy(
new RequestStrategy({
source: "memory",
on: "beforeQuery",
source: 'memory',
on: 'beforeQuery',

target: "remote",
action: "pull",
target: 'remote',
action: 'query',

blocking: true
})
Expand All @@ -133,11 +134,11 @@ coordinator.addStrategy(
// Update the remote server whenever the memory source is updated
coordinator.addStrategy(
new RequestStrategy({
source: "memory",
on: "beforeUpdate",
source: 'memory',
on: 'beforeUpdate',

target: "remote",
action: "push",
target: 'remote',
action: 'update',

blocking: true
})
Expand All @@ -148,24 +149,24 @@ It's possible to apply a filter function to a strategy so that it only applies
to certain data. For instance, the following filter limits which queries should
be handled by a remote server:

```javascript
import { RequestStrategy } from "@orbit/coordinator";
```typescript
import { RequestStrategy } from '@orbit/coordinator';

// Only forward requests for planets on to the remote server
coordinator.addStrategy(
new RequestStrategy({
source: "memory",
on: "beforeQuery",
source: 'memory',
on: 'beforeQuery',

target: "remote",
action: "pull",
target: 'remote',
action: 'pull',

blocking: true,

filter(query) {
return (
query.expressions.op === "findRecords" &&
query.expressions.type === "planet"
query.expressions.op === 'findRecords' &&
query.expressions.type === 'planet'
);
}
})
Expand All @@ -188,14 +189,14 @@ on the `target`.
The following strategy synchronizes any changes to the `remote` source with a
`memory` source:

```javascript
import { SyncStrategy } from "@orbit/coordinator";
```typescript
import { SyncStrategy } from '@orbit/coordinator';

// Sync all changes received from the remote server to the memory source
coordinator.addStrategy(
new SyncStrategy({
source: "remote",
target: "memory",
source: 'remote',
target: 'memory',
blocking: true
})
);
Expand All @@ -211,19 +212,19 @@ An event logging strategy can be applied to log events on all sources to the
console. By default, all events will be logged on all sources registered to a
coordinator:

```javascript
import { EventLoggingStrategy } from "@orbit/coordinator";
```typescript
import { EventLoggingStrategy } from '@orbit/coordinator';

coordinator.addStrategy(new EventLoggingStrategy());
```

You may wish to only observe events on certain interfaces, which can be
specified as follows:

```javascript
```typescript
coordinator.addStrategy(
new EventLoggingStrategy({
interfaces: ["updatable", "pushable", "syncable"]
interfaces: ['updatable', 'pushable', 'syncable']
})
);
```
Expand All @@ -234,10 +235,10 @@ Valid interfaces include `updatable`, `queryable`, `pushable`, `pullable`, and
Furthermore, you may wish to only observe certain sources, which can be
specified by name:

```javascript
```typescript
coordinator.addStrategy(
new EventLoggingStrategy({
sources: ["remote", "memory"]
sources: ['remote', 'memory']
})
);
```
Expand All @@ -256,18 +257,18 @@ all.

To add a log truncation strategy that applies to all sources:

```javascript
import { LogTruncationStrategy } from "@orbit/coordinator";
```typescript
import { LogTruncationStrategy } from '@orbit/coordinator';

coordinator.addStrategy(new LogTruncationStrategy());
```

To limit the strategy to apply to only specific sources:

```javascript
```typescript
coordinator.addStrategy(
new LogTruncationStrategy({
sources: ["backup", "memory"]
sources: ['backup', 'memory']
})
);
```
Expand Down Expand Up @@ -305,10 +306,10 @@ be too:
```ts
coordinator.addStrategy(
new RequestStrategy({
source: "memory",
target: "remote",
on: "beforeQuery",
action: "query",
source: 'memory',
target: 'remote',
on: 'beforeQuery',
action: 'query',
blocking: true,
passHints: true
})
Expand All @@ -326,8 +327,8 @@ You'll also want to create a blocking `SyncStrategy` that syncs any transforms a
```ts
coordinator.addStrategy(
new SyncStrategy({
source: "remote",
target: "memory",
source: 'remote',
target: 'memory',
blocking: true
})
);
Expand Down
Loading

0 comments on commit a038ec5

Please sign in to comment.