Skip to content

Commit 733ae0f

Browse files
committed
ci: update coverage badges
1 parent af67bf5 commit 733ae0f

5 files changed

Lines changed: 155 additions & 14 deletions

File tree

.github/workflows/build.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,12 @@ jobs:
2929
- name: Test 🧪
3030
run: npm run test:ci
3131

32-
- name: Coveralls 🎉
33-
uses: coverallsapp/github-action@v2
34-
with:
35-
github-token: ${{ secrets.GITHUB_TOKEN }}
36-
3732
- name: Build Docs 📖
3833
run: npm run docs
3934

35+
- name: Create Coverage Badge 🏷️
36+
run: npx coverage-badge-svg
37+
4038
- name: Deploy 🚀
4139
uses: JamesIves/github-pages-deploy-action@v4
4240
with:

README.md

Lines changed: 148 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,128 @@
77
[![Docs](https://img.shields.io/badge/Docs-read-%23fdf9f5)](https://embrajs.github.io/reactivity)
88
[![Build Status](https://github.com/embrajs/reactivity/actions/workflows/build.yml/badge.svg)](https://github.com/embrajs/reactivity/actions/workflows/build.yml)
99
[![npm-version](https://img.shields.io/npm/v/@embra/reactivity.svg)](https://www.npmjs.com/package/@embra/reactivity)
10-
[![Coverage Status](https://img.shields.io/coverallsCoverage/github/embrajs/reactivity)](https://coveralls.io/github/embrajs/reactivity)
10+
[![Coverage Status](https://embrajs.github.io/reactivity/coverage-badges/@embra/reactivity.svg)](https://embrajs.github.io/reactivity/coverage/)
1111

12-
Chainable, hook-flavored signals.
12+
A lightweight, composable and explicit reactivity system.
13+
14+
## Features
15+
16+
<details>
17+
<summary>Plain reactivity. No proxies, no magic.</summary>
18+
19+
It does not convert the value with `Object.defineProperty` nor `Proxy`. Keeping everything as plain JavaScript value makes it easier to work with other libraries and easier for the JavaScript engine to optimize.
20+
21+
```ts
22+
import { writable, readable, type Readable } from "@embra/reactivity";
23+
24+
const count$ = writable(0);
25+
count$.set(1);
26+
27+
const [count2$, setCount] = readable(0);
28+
setCount(1);
29+
```
30+
31+
</details>
32+
33+
<details>
34+
<summary>Explicit reactivity. No hidden dependencies, no surprises.</summary>
35+
36+
Unlike signal-based libraries, `@embra/reactivity` does not automatically track dependencies. You explicitly define what to watch and how to react to changes. This is easier to reason about dependencies and also reduce the cost of complex implicit dependency calculation.
37+
38+
With React hook-like API, computations can be pure functions which is more compatible with general non-reactive functions.
39+
40+
```ts
41+
import { writable, derive } from "@embra/reactivity";
42+
43+
const count$ = writable(0);
44+
45+
const isPositive = (value: number): boolean => value > 0;
46+
47+
const positiveCount$ = derive(count$, isPositive);
48+
```
49+
50+
Dynamic dependencies can be collected using `get` in `compute` or `watch`.
51+
52+
```ts
53+
import { writable, compute, watch } from "@embra/reactivity";
54+
55+
const count$ = writable(0);
56+
const doubleCount$ = compute(get => get(count$) * 2);
57+
58+
watch(get => {
59+
const count = get(count$);
60+
console.log(`Count is ${count}, double is ${get(doubleCount$)}`);
61+
});
62+
```
63+
64+
</details>
65+
66+
<details>
67+
<summary>Zero-cost ownership model. Type-safe lifecycle management.</summary>
68+
69+
In practice, one of the biggest problems we face with reactivity libraries is the lifecycle management of reactive values. `@embra/reactivity` provides a zero-cost ownership model that allows you to create reactive values with explicit ownership.
70+
71+
By default, created reactive values are with type `OwnedReadable` or `OwnedWritable`, which exposes a `dispose()` method to clean up the value and its dependencies. When passing the reactive value to a function, you can use `Readable` or `Writable` types to hide the `dispose()` method, ensuring that the value is not disposed of accidentally.
72+
73+
```ts
74+
import { writable, readable, type Readable, type OwnedWritable } from "@embra/reactivity";
75+
76+
const count$: OwnedWritable<number> = writable(0);
77+
count$.set(1);
78+
79+
// Hide the setter by typing
80+
function logCount(count$: Readable<number>) {
81+
count$.subscribe(console.log);
82+
83+
// @ts-expect-error
84+
count$.set(2);
85+
}
86+
logCount(count$);
87+
88+
// Hide the setter in runtime
89+
const [count2$, setCount] = readable(0);
90+
setCount(1);
91+
92+
// @ts-expect-error
93+
count2$.set(2);
94+
```
95+
96+
</details>
97+
98+
<details>
99+
<summary>Flexible abstractions of state and actions.</summary>
100+
101+
In the days of Flux model, we often used a single store to hold the state and actions to mutate the state. This was nice for reasoning about the state, but it also introduced a lot of boilerplate code.
102+
103+
Later on, a pattern with state and action glued together was introduced, like `redux-actions`. `@embra/reactivity` takes this a step further by providing a more simple and flexible abstraction of state and actions.
104+
105+
In the following example, we create a Writable `count$` which looks like a `Writable<number>`, but internally it is derived from a larger application state `appState$`. This allows other modules to depend on a `Writable<number>` without knowing the details of the application state.
106+
107+
```ts
108+
import { writable, derive, toWritable, trace } from "@embra/reactivity";
109+
110+
const appState$ = writable({
111+
count: 0,
112+
user: null,
113+
});
114+
115+
const count$ = toWritable(
116+
derive(appState$, state => state.count),
117+
count => appState$.set({ ...appState$.value, count }),
118+
);
119+
120+
// when debugging, you can trace the reactive value
121+
trace(count$);
122+
```
123+
124+
</details>
125+
126+
<details>
127+
<summary>Small bundle size. Focused on performance and simplicity.</summary>
128+
129+
![export size](https://embrajs.github.io/reactivity/assets/export-size.svg)
130+
131+
</details>
13132

14133
## Install
15134

@@ -19,8 +138,32 @@ npm add @embra/reactivity
19138

20139
![export size](https://embrajs.github.io/reactivity/assets/export-size.svg)
21140

22-
## Devtools
141+
## Debugging
142+
143+
### trace
144+
145+
`@embra/reactivity` provides a `trace()` function to help debug reactive values and watches. It tracks value and dependency changes and logs them to the console.
146+
147+
```js
148+
import { trace, writable, watch } from "@embra/reactivity";
149+
const count$ = writable(0);
23150

24-
## Custom Formatter
151+
// trace a reactive value
152+
trace(count$);
25153

26-
`@embra/reactivity` in development mode supports DevTools [custom formatters](https://www.mattzeunert.com/2016/02/19/custom-chrome-devtools-object-formatters.html). You may enable it by checking the "Enable custom formatters" option in the "Console" section of DevTools general settings.
154+
// trace a watch function
155+
watch(trace(get => get(count$)));
156+
157+
count$.set(1);
158+
```
159+
160+
### Chrome Devtools Custom Formatter
161+
162+
`@embra/reactivity` supports Chrome DevTools [custom formatters](https://www.mattzeunert.com/2016/02/19/custom-chrome-devtools-object-formatters.html). You may enable it by checking the "Enable custom formatters" option in the "Console" section of DevTools general settings.
163+
164+
It is enabled in development by default. You can also enable it manually by calling `customFormatter()`.
165+
166+
```js
167+
import { customFormatter } from "@embra/reactivity";
168+
customFormatter();
169+
```

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@embra/reactivity",
33
"version": "0.0.1",
4-
"description": "Chainable, hook-flavored signals.",
4+
"description": "A lightweight, composable and explicit reactivity system.",
55
"repository": "embrajs/reactivity",
66
"main": "./dist/index.js",
77
"module": "./dist/index.mjs",
@@ -24,7 +24,7 @@
2424
"docs": "typedoc --options typedoc.json && prettier --ignore-path .prettierignore --write docs && export-size-svg",
2525
"test": "vitest",
2626
"test:coverage": "vitest --coverage",
27-
"test:ci": "vitest --coverage",
27+
"test:ci": "vitest --coverage --coverage-reportsDirectory='./docs/coverage'",
2828
"build": "tsup",
2929
"build:min": "MINIFY=true tsup --env.NODE_ENV production && echo '' && gzip-size dist/index.mjs dist/index.js",
3030
"release": "commit-and-tag-version"

src/dev/trace.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export interface Trace {
2121
* Console logs trace information about the provided Readable or WatchEffect.
2222
* @example
2323
* ```ts
24-
* import { trace, writable, watch } from "@embra";
24+
* import { trace, writable, watch } from "@embra/reactivity";
2525
* const count$ = writable(0);
2626
*
2727
* trace(count$);

vitest.config.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export default defineConfig({
55
coverage: {
66
include: ["src/**"],
77
exclude: ["src/dev/**"],
8-
reporter: ["html", "text", "lcov"],
8+
reporter: ["html", "text", "json-summary"],
99
},
1010
poolOptions: {
1111
forks: {

0 commit comments

Comments
 (0)