nanoeffects 0.33.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/dist/actions.d.ts +2 -2
- package/dist/actions.js +1 -1
- package/dist/dev.d.ts +1 -1
- package/dist/{module-DPKjzfRk.d.ts → module-Fk4OtkZk.d.ts} +10 -27
- package/dist/notrace/actions.d.ts +10 -27
- package/dist/notrace/actions.js +1 -1
- package/dist/signal.d.ts +11 -10
- package/dist/signal.js +1 -1
- package/docs/README.md +29 -2
- package/docs/actions.md +13 -7
- package/docs/cancel-stale-requests.md +1 -1
- package/docs/context.md +1 -1
- package/docs/guide.md +6 -6
- package/docs/package.md +1 -1
- package/docs/pass-the-signal.md +45 -17
- package/docs/policies.md +1 -1
- package/docs/react.md +41 -0
- package/docs/ru/README.md +29 -2
- package/docs/ru/actions.md +13 -7
- package/docs/ru/cancel-stale-requests.md +1 -1
- package/docs/ru/context.md +1 -1
- package/docs/ru/guide.md +6 -6
- package/docs/ru/package.md +1 -1
- package/docs/ru/pass-the-signal.md +46 -18
- package/docs/ru/policies.md +1 -1
- package/docs/ru/react.md +41 -0
- package/docs/ru/svelte.md +41 -0
- package/docs/ru/vue.md +45 -0
- package/docs/svelte.md +41 -0
- package/docs/vue.md +45 -0
- package/llms-full.txt +195 -34
- package/package.json +2 -2
package/llms-full.txt
CHANGED
|
@@ -394,7 +394,7 @@ Use strings for the plain case. Use objects when other code already builds actio
|
|
|
394
394
|
|
|
395
395
|
**Problem.** The handler of an action is in the file of the feature, but a test needs a fake, or another layer owns the work. If the handler sits in `createAction`, the event file is tied to the work.
|
|
396
396
|
|
|
397
|
-
**What to do.** Create the action without a handler: it is an event. Bind the real handler with `
|
|
397
|
+
**What to do.** Create the action without a handler: it is an event. Bind the real handler with `actions.handle` when the bus is made. A later `actions.handle` binds a newer handler that wins until you remove it.
|
|
398
398
|
|
|
399
399
|
```js
|
|
400
400
|
// user.js
|
|
@@ -406,16 +406,16 @@ export const getUser = createAction("user/get"); // no handler yet: an event
|
|
|
406
406
|
```js
|
|
407
407
|
// bus.js
|
|
408
408
|
import { createBus } from "nanoeffects";
|
|
409
|
-
import { actionsPlugin
|
|
409
|
+
import { actionsPlugin } from "nanoeffects/actions";
|
|
410
410
|
import { getUser } from "./user";
|
|
411
411
|
|
|
412
412
|
export const bus = createBus();
|
|
413
413
|
|
|
414
|
-
// setHandler — binds the real handler to the action
|
|
415
|
-
const realUser = setHandler(getUser, (id) => api.user(id));
|
|
416
|
-
|
|
417
414
|
// actionsPlugin — the registry of bound handlers of this bus
|
|
418
|
-
export const actions = bus.use(actionsPlugin(
|
|
415
|
+
export const actions = bus.use(actionsPlugin());
|
|
416
|
+
|
|
417
|
+
// actions.handle — binds the real handler to the action
|
|
418
|
+
actions.handle(getUser, (id) => api.user(id));
|
|
419
419
|
```
|
|
420
420
|
|
|
421
421
|
```js
|
|
@@ -1312,7 +1312,7 @@ Each row is optional. The "when" column says what need brings you to it.
|
|
|
1312
1312
|
| `nanoeffects/actions` | `createAction`, `createJob`, `createModule`, `modulePlugin`, `actionsPlugin` | `emit` must return a result, or domain logic leaves the UI |
|
|
1313
1313
|
| `nanoeffects/match` | `matchPlugin`: `on`, `once` and `off` that take a function which picks the events | `on` must take a function that picks events |
|
|
1314
1314
|
| `nanoeffects/context` | `contextPlugin`: your own fields (a store, a client) on `ctx` of every task, typed from the value | a store or client must be on every task |
|
|
1315
|
-
| `nanoeffects/signal` | `signalPlugin`: `emit(call, { signal })` ties the tasks of an emit to an outside `AbortSignal`; `
|
|
1315
|
+
| `nanoeffects/signal` | `signalPlugin`: `emit(call, { signal })` ties the tasks of an emit to an outside `AbortSignal`; `signalFetch(ctx, url)`: a `fetch` that stops with its task; `fromSignal`: a client made from the signal of each task | an outside `AbortSignal` (request, React Query) must stop tasks, or a handler must not pass the signal by hand |
|
|
1316
1316
|
| `nanoeffects/oop` | `Emitter`, `extendBus`, `WithBus`, `On`, `Once`, `disposeBus`: the methods of a bus on a class, with the subscriptions of each instance ended by `dispose()` | you write classes, not functions |
|
|
1317
1317
|
| `nanoeffects/scope` | `scopePlugin`, `effect`: fields for one action, job, module or `emit` (the types `Scope`, `Effect`) | one action or module needs its own fields |
|
|
1318
1318
|
| `nanoeffects/redux` | `createEffectsMiddleware` | you already use Redux |
|
|
@@ -1772,7 +1772,7 @@ bus.on(
|
|
|
1772
1772
|
);
|
|
1773
1773
|
```
|
|
1774
1774
|
|
|
1775
|
-
Pass `signal` to `fetch` (and the like) so the request cancels. To not pass it at all, bind it once: with `ctx
|
|
1775
|
+
Pass `signal` to `fetch` (and the like) so the request cancels. To not pass it at all, bind it once: with `signalFetch(ctx, url)` the request stops with the handler and there is nothing to forget ([Keep the signal through a handler](pass-the-signal.md#bind-the-signal-once)).
|
|
1776
1776
|
|
|
1777
1777
|
## Choose a policy
|
|
1778
1778
|
|
|
@@ -2002,7 +2002,7 @@ bus.on("results", (items) => render(items));
|
|
|
2002
2002
|
|
|
2003
2003
|
What to replace: `api.search` is your own request function. It must accept `{ signal }` and give it to `fetch`. Without it, `latest` still ignores the old result, but the request keeps running.
|
|
2004
2004
|
|
|
2005
|
-
To make the mistake impossible, bind the signal once: `
|
|
2005
|
+
To make the mistake impossible, bind the signal once: `signalFetch(ctx, url)` is a `fetch` that stops with the handler, and `effectsPlugin({ fetch: signalFetch })` gives every handler a `ctx.fetch` of it ([how](pass-the-signal.md#bind-the-signal-once)). To find the requests that already forget it, use `devPlugin` while you develop, and `getLostSignalsCount(bus)` in a test ([how](pass-the-signal.md#count-lost-signals-in-a-test)).
|
|
2006
2006
|
|
|
2007
2007
|
Result: `emit("search", "ab")` followed by `emit("search", "abc")` shows only the results for `abc`, and the request for `ab` is cancelled.
|
|
2008
2008
|
|
|
@@ -3049,15 +3049,21 @@ export const sendMail = createAction("mail/send");
|
|
|
3049
3049
|
```js
|
|
3050
3050
|
// bus.js
|
|
3051
3051
|
import { createBus } from "nanoeffects";
|
|
3052
|
-
import { actionsPlugin
|
|
3053
|
-
import { sendMail } from "./mail";
|
|
3052
|
+
import { actionsPlugin } from "nanoeffects/actions";
|
|
3054
3053
|
|
|
3055
3054
|
export const bus = createBus();
|
|
3056
3055
|
|
|
3057
|
-
// actionsPlugin — the registry of handlers of this bus
|
|
3058
|
-
export const actions = bus.use(
|
|
3059
|
-
|
|
3060
|
-
|
|
3056
|
+
// actionsPlugin — the registry of handlers of this bus
|
|
3057
|
+
export const actions = bus.use(actionsPlugin());
|
|
3058
|
+
```
|
|
3059
|
+
|
|
3060
|
+
```js
|
|
3061
|
+
// mail-handlers.js
|
|
3062
|
+
import { actions } from "./bus";
|
|
3063
|
+
import { sendMail } from "./mail";
|
|
3064
|
+
|
|
3065
|
+
// actions.handle — binds the work to the action on this bus
|
|
3066
|
+
actions.handle(sendMail, smtpSend);
|
|
3061
3067
|
```
|
|
3062
3068
|
|
|
3063
3069
|
```js
|
|
@@ -3071,7 +3077,7 @@ unbind();
|
|
|
3071
3077
|
|
|
3072
3078
|
A handler bound in the registry makes `bus.emit(sendMail(mail))` run it and return its result, the same as for an action that carries its handler. The listeners of the type are told first. With no handler bound, `sendMail` is an event again.
|
|
3073
3079
|
|
|
3074
|
-
The registry lives in `nanoeffects/actions`, so a bus without one carries none of that code. Without a registry, `emit` runs the handler that the action carries. `bus.use(actionsPlugin())` sets `bus.actions`. A second `actionsPlugin`
|
|
3080
|
+
The registry lives in `nanoeffects/actions`, so a bus without one carries none of that code. Without a registry, `emit` runs the handler that the action carries. `bus.use(actionsPlugin())` sets `bus.actions`. A second `actionsPlugin` returns that registry. There is no `actions` option in `createBus`; assign a custom runner with `bus.actions = { run }`, and add `bound(type)` to it to answer for actions that have no handler of their own.
|
|
3075
3081
|
|
|
3076
3082
|
### The result type of a bound handler
|
|
3077
3083
|
|
|
@@ -4617,6 +4623,47 @@ Steps 1 and 2 are required, step 3 is not. The last two sections are extra.
|
|
|
4617
4623
|
|
|
4618
4624
|
You need a React project and `nanoeffects` installed. The form talks to your own client, `api` below: replace it with your requests.
|
|
4619
4625
|
|
|
4626
|
+
The shortest version: a name field that asks the backend whether the name is free. The rest of the page builds a whole form from it.
|
|
4627
|
+
|
|
4628
|
+
```js
|
|
4629
|
+
// username.js
|
|
4630
|
+
import { createBus } from "nanoeffects";
|
|
4631
|
+
import { latest } from "nanoeffects/policies";
|
|
4632
|
+
|
|
4633
|
+
export const bus = createBus(); // the bus, created once
|
|
4634
|
+
|
|
4635
|
+
// the name check, outside the component; latest aborts the check of the previous name
|
|
4636
|
+
bus.on(
|
|
4637
|
+
"username/typed",
|
|
4638
|
+
latest(async (name, ctx) => {
|
|
4639
|
+
const available = await api.usernameAvailable(name, { signal: ctx.signal });
|
|
4640
|
+
ctx.emit("username/checked", available);
|
|
4641
|
+
}),
|
|
4642
|
+
);
|
|
4643
|
+
```
|
|
4644
|
+
|
|
4645
|
+
```jsx
|
|
4646
|
+
// NameField.jsx
|
|
4647
|
+
import { useEffect, useState } from "react";
|
|
4648
|
+
import { bus } from "./username";
|
|
4649
|
+
|
|
4650
|
+
export function NameField() {
|
|
4651
|
+
const [available, setAvailable] = useState(null); // null: not checked yet
|
|
4652
|
+
|
|
4653
|
+
// on returns the unbind function; returning it removes the listener on unmount
|
|
4654
|
+
useEffect(() => bus.on("username/checked", setAvailable), []);
|
|
4655
|
+
|
|
4656
|
+
return (
|
|
4657
|
+
<>
|
|
4658
|
+
<input onChange={(event) => bus.emit("username/typed", event.target.value)} />
|
|
4659
|
+
{available === false && <p>This name is taken</p>}
|
|
4660
|
+
</>
|
|
4661
|
+
);
|
|
4662
|
+
}
|
|
4663
|
+
```
|
|
4664
|
+
|
|
4665
|
+
The handler knows nothing about React, and the component knows nothing about requests.
|
|
4666
|
+
|
|
4620
4667
|
## On this page
|
|
4621
4668
|
|
|
4622
4669
|
- [Problems of the form without a bus](#problems-of-the-form-without-a-bus)
|
|
@@ -5412,6 +5459,51 @@ Use this page when your app is in Vue 3 and a component has to talk to the bus:
|
|
|
5412
5459
|
|
|
5413
5460
|
You need Vue 3.3 or newer and `nanoeffects` installed. If you do not know what the bus is, read the [Guide](guide.md) first.
|
|
5414
5461
|
|
|
5462
|
+
The shortest version: a search box that shows what the handler found. No plugin is needed for this; the sections below add a helper that shortens the component.
|
|
5463
|
+
|
|
5464
|
+
```js
|
|
5465
|
+
// search.js
|
|
5466
|
+
import { createBus } from "nanoeffects";
|
|
5467
|
+
import { latest } from "nanoeffects/policies";
|
|
5468
|
+
|
|
5469
|
+
export const bus = createBus(); // the bus, created once
|
|
5470
|
+
|
|
5471
|
+
// the search logic, outside the component; latest aborts the previous request
|
|
5472
|
+
bus.on(
|
|
5473
|
+
"search",
|
|
5474
|
+
latest(async (query, ctx) => {
|
|
5475
|
+
const items = await api.search(query, { signal: ctx.signal });
|
|
5476
|
+
ctx.emit("found", items);
|
|
5477
|
+
}),
|
|
5478
|
+
);
|
|
5479
|
+
```
|
|
5480
|
+
|
|
5481
|
+
The handler knows nothing about the UI, and the component only sends `search` and listens to `found`.
|
|
5482
|
+
|
|
5483
|
+
<!-- docs-check: skip - a .vue file -->
|
|
5484
|
+
```vue
|
|
5485
|
+
<script setup>
|
|
5486
|
+
import { onUnmounted, ref } from "vue";
|
|
5487
|
+
import { bus } from "./search";
|
|
5488
|
+
|
|
5489
|
+
const items = ref([]);
|
|
5490
|
+
|
|
5491
|
+
// on returns the unbind function; unmounting calls it
|
|
5492
|
+
const unbind = bus.on("found", (found) => {
|
|
5493
|
+
items.value = found;
|
|
5494
|
+
});
|
|
5495
|
+
onUnmounted(unbind);
|
|
5496
|
+
</script>
|
|
5497
|
+
|
|
5498
|
+
<template>
|
|
5499
|
+
<input @input="bus.emit('search', $event.target.value)" />
|
|
5500
|
+
<ul>
|
|
5501
|
+
<li v-for="item in items" :key="item.id">{{ item.title }}</li>
|
|
5502
|
+
</ul>
|
|
5503
|
+
</template>
|
|
5504
|
+
```
|
|
5505
|
+
|
|
5506
|
+
|
|
5415
5507
|
## Add the plugin to the bus
|
|
5416
5508
|
|
|
5417
5509
|
**Problem.** Without help, a component writes `watch(query, (value) => bus.emit(queryChanged(value)))` and its own subscription in `onMounted` and `onUnmounted`. The same few lines are copied into every component, and each copy forgets something: the cleanup, the equality check, or the name of the subscription in the trace.
|
|
@@ -5514,6 +5606,47 @@ Use this page when your app is in Svelte 5 and a component has to show the resul
|
|
|
5514
5606
|
|
|
5515
5607
|
You need Svelte 5 or newer and `nanoeffects` installed. If you do not know what the bus is, read the [Guide](guide.md) first.
|
|
5516
5608
|
|
|
5609
|
+
The shortest version: a search box that shows what the handler found. No plugin is needed for this; the sections below add a helper that shortens the component.
|
|
5610
|
+
|
|
5611
|
+
```js
|
|
5612
|
+
// search.js
|
|
5613
|
+
import { createBus } from "nanoeffects";
|
|
5614
|
+
import { latest } from "nanoeffects/policies";
|
|
5615
|
+
|
|
5616
|
+
export const bus = createBus(); // the bus, created once
|
|
5617
|
+
|
|
5618
|
+
// the search logic, outside the component; latest aborts the previous request
|
|
5619
|
+
bus.on(
|
|
5620
|
+
"search",
|
|
5621
|
+
latest(async (query, ctx) => {
|
|
5622
|
+
const items = await api.search(query, { signal: ctx.signal });
|
|
5623
|
+
ctx.emit("found", items);
|
|
5624
|
+
}),
|
|
5625
|
+
);
|
|
5626
|
+
```
|
|
5627
|
+
|
|
5628
|
+
The handler knows nothing about the UI, and the component only sends `search` and listens to `found`.
|
|
5629
|
+
|
|
5630
|
+
<!-- docs-check: skip - a .svelte file -->
|
|
5631
|
+
```svelte
|
|
5632
|
+
<script>
|
|
5633
|
+
import { bus } from "./search";
|
|
5634
|
+
|
|
5635
|
+
let items = $state([]);
|
|
5636
|
+
|
|
5637
|
+
// on returns the unbind function; $effect calls it on cleanup
|
|
5638
|
+
$effect(() => bus.on("found", (found) => (items = found)));
|
|
5639
|
+
</script>
|
|
5640
|
+
|
|
5641
|
+
<input oninput={(event) => bus.emit("search", event.target.value)} />
|
|
5642
|
+
<ul>
|
|
5643
|
+
{#each items as item (item.id)}
|
|
5644
|
+
<li>{item.title}</li>
|
|
5645
|
+
{/each}
|
|
5646
|
+
</ul>
|
|
5647
|
+
```
|
|
5648
|
+
|
|
5649
|
+
|
|
5517
5650
|
## Add the plugin to the bus
|
|
5518
5651
|
|
|
5519
5652
|
**Problem.** A Svelte component reads a value with `$store`. An event of the bus is not a store, so without help the component writes its own `readable` and its own `bus.on`, and has to remember to stop listening. The same few lines are copied into every component.
|
|
@@ -5694,7 +5827,7 @@ bus.on("user/open", async (id, ctx) => {
|
|
|
5694
5827
|
});
|
|
5695
5828
|
```
|
|
5696
5829
|
|
|
5697
|
-
- `signalFetch` from the same entry
|
|
5830
|
+
- For `fetch` you need no `fromSignal`: `signalFetch(ctx, url)` from the same entry stops with the task, and `effectsPlugin({ fetch: signalFetch })` gives every handler a `ctx.fetch`. [Bind the signal once](pass-the-signal.md#bind-the-signal-once)
|
|
5698
5831
|
- `make` runs at the first read, so a handler that never uses `ctx.http` pays nothing for it.
|
|
5699
5832
|
- A task that `ctx.run` starts builds its own value from its own signal, so aborting the child stops only the child's requests.
|
|
5700
5833
|
- The field is not copied by `{ ...ctx }` and `Object.keys(ctx)` does not list it. Read `ctx.http` first if you copy a context.
|
|
@@ -7407,25 +7540,36 @@ A policy such as `latest` cancels an older call by aborting its `ctx.signal`. Th
|
|
|
7407
7540
|
|
|
7408
7541
|
## Bind the signal once
|
|
7409
7542
|
|
|
7410
|
-
The surest fix is a handler
|
|
7543
|
+
The surest fix is a handler that never writes a signal. `signalFetch` is a `fetch` that takes `ctx` first, like `retry(ctx, ...)`: the request carries `ctx.signal`, so there is nothing to forget.
|
|
7411
7544
|
|
|
7412
7545
|
```js
|
|
7413
|
-
//
|
|
7414
|
-
import {
|
|
7415
|
-
import {
|
|
7416
|
-
import {
|
|
7417
|
-
import axios from "axios";
|
|
7546
|
+
// search-handlers.js
|
|
7547
|
+
import { latest } from "nanoeffects/policies";
|
|
7548
|
+
import { signalFetch } from "nanoeffects/signal";
|
|
7549
|
+
import { bus } from "./bus";
|
|
7418
7550
|
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
fetch:
|
|
7423
|
-
|
|
7424
|
-
|
|
7551
|
+
bus.on(
|
|
7552
|
+
"search",
|
|
7553
|
+
latest(async (query, ctx) => {
|
|
7554
|
+
// signalFetch — fetch with ctx.signal: it stops when the policy cancels the handler
|
|
7555
|
+
const response = await signalFetch(ctx, `/api?q=${query}`);
|
|
7556
|
+
ctx.emit("results", await response.json());
|
|
7425
7557
|
}),
|
|
7426
7558
|
);
|
|
7427
7559
|
```
|
|
7428
7560
|
|
|
7561
|
+
To get `ctx.fetch` in every handler, put the effect on the context once. `effectsPlugin` binds it to each task, so the handler drops the `ctx` argument:
|
|
7562
|
+
|
|
7563
|
+
```js
|
|
7564
|
+
// bus.js
|
|
7565
|
+
import { createBus } from "nanoeffects";
|
|
7566
|
+
import { effectsPlugin } from "nanoeffects/effects";
|
|
7567
|
+
import { signalFetch } from "nanoeffects/signal";
|
|
7568
|
+
|
|
7569
|
+
// effectsPlugin — ctx.fetch is signalFetch bound to the task that reads it
|
|
7570
|
+
export const bus = createBus().use(effectsPlugin({ fetch: signalFetch }));
|
|
7571
|
+
```
|
|
7572
|
+
|
|
7429
7573
|
```js
|
|
7430
7574
|
// search-handlers.js
|
|
7431
7575
|
import { latest } from "nanoeffects/policies";
|
|
@@ -7433,10 +7577,27 @@ import { bus } from "./bus";
|
|
|
7433
7577
|
|
|
7434
7578
|
bus.on(
|
|
7435
7579
|
"search",
|
|
7436
|
-
latest(async (query,
|
|
7437
|
-
// no signal
|
|
7438
|
-
const response = await
|
|
7439
|
-
|
|
7580
|
+
latest(async (query, { fetch, emit }) => {
|
|
7581
|
+
// no signal and no ctx argument: fetch stops when the policy cancels the handler
|
|
7582
|
+
const response = await fetch(`/api?q=${query}`);
|
|
7583
|
+
emit("results", await response.json());
|
|
7584
|
+
}),
|
|
7585
|
+
);
|
|
7586
|
+
```
|
|
7587
|
+
|
|
7588
|
+
A client that is not an effect, such as an `axios` instance, is made from the signal of each task with `fromSignal`:
|
|
7589
|
+
|
|
7590
|
+
```js
|
|
7591
|
+
// bus.js
|
|
7592
|
+
import { createBus } from "nanoeffects";
|
|
7593
|
+
import { contextPlugin } from "nanoeffects/context";
|
|
7594
|
+
import { fromSignal } from "nanoeffects/signal";
|
|
7595
|
+
import axios from "axios";
|
|
7596
|
+
|
|
7597
|
+
// fromSignal — ctx.http is made from the signal of the task that reads it
|
|
7598
|
+
export const bus = createBus().use(
|
|
7599
|
+
contextPlugin({
|
|
7600
|
+
http: fromSignal((signal) => axios.create({ signal })),
|
|
7440
7601
|
}),
|
|
7441
7602
|
);
|
|
7442
7603
|
```
|
|
@@ -7508,7 +7669,7 @@ Each row is a situation where the signal is easy to lose. The right column says
|
|
|
7508
7669
|
| A function takes the signal and never uses it: `search(query, options) { return fetch(url); }` | Pass the signal on inside it. Only type information finds this in the linter; a test finds it for sure | types | |
|
|
7509
7670
|
| The signal is wired by hand: `signal.addEventListener("abort", ...)` | Nothing, the handler is not checked step by step | accepted | |
|
|
7510
7671
|
| `bus.emit` in a handler | Use `ctx.emit`: only it is dropped after the handler was cancelled | yes | |
|
|
7511
|
-
| A request that keeps running after the cancel, on Node | Pass the signal, or use `ctx
|
|
7672
|
+
| A request that keeps running after the cancel, on Node | Pass the signal, or use `signalFetch(ctx, url)` | | yes |
|
|
7512
7673
|
| Results emitted after the cancel | The handler ignored the signal. Pass it, or check `ctx.signal.aborted` | | yes |
|
|
7513
7674
|
| `ctx.on` after the cancel | The same | | yes |
|
|
7514
7675
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nanoeffects",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "Business logic and side effects outside UI components, as plain async functions. Tiny, no dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"event-bus",
|
|
@@ -246,7 +246,7 @@
|
|
|
246
246
|
{
|
|
247
247
|
"name": "signal (plugin)",
|
|
248
248
|
"path": "dist/signal.js",
|
|
249
|
-
"limit": "0.
|
|
249
|
+
"limit": "0.81 kB"
|
|
250
250
|
},
|
|
251
251
|
{
|
|
252
252
|
"name": "context (plugin)",
|