Built-in plugin for babel can be used for ssr and debugging. It inserts a name a Unit,
inferred from variable name and sid
(Stable IDentifier), computed from the location in the source code.
For example, in case effects without handlers, it improves error messages by clearly showing in which effect error happened.
import { createEffect } from "effector";
const fetchFx = createEffect();
fetchFx();
// => no handler used in fetchFx
Usage
In the simplest case, it can be used without any configuration:
// .babelrc
{
"plugins": ["effector/babel-plugin"]
}
SID
Stable hash identifier for events, effects, stores and domains, preserved between environments, to handle client-server interaction within the same codebase.
The crucial value of sid is that it can be autogenerated by effector/babel-plugin
with default config, and it will be stable between builds.
If you need the detailed deep-dive explanation about why we need SIDs and how they are used internally, you can find it by following this link
See example project
// common.js
import { createEffect } from "effector";
export const getUser = createEffect({ sid: "GET /user" });
console.log(getUsers.sid);
// => GET /user
// worker.js
import { getUsers } from "./common.js";
getUsers.use((userID) => fetch(userID));
getUsers.done.watch(({ result }) => {
postMessage({ sid: getUsers.sid, result });
});
onmessage = async ({ data }) => {
if (data.sid !== getUsers.sid) return;
getUsers(data.userID);
};
// client.js
import { createEvent } from "effector";
import { getUsers } from "./common.js";
const onMessage = createEvent();
const worker = new Worker("worker.js");
worker.onmessage = onMessage;
getUsers.use(
(userID) =>
new Promise((rs) => {
worker.postMessage({ sid: getUsers.sid, userID });
const unwatch = onMessage.watch(({ data }) => {
if (data.sid !== getUsers.sid) return;
unwatch();
rs(data.result);
});
}),
);
Configuration
importName
Specifying import name or names to process by plugin. Import should be used in the code as specified.
Formulae
[
"effector/babel-plugin",
{
"importName": ["effector"]
}
]
- Type:
string | string[]
- Default:
['effector', 'effector/compat']
factories
Accepts an array of module names which exports treat as custom factories, therefore, each function call provides a unique prefix for sids of units inside them. Used to SSR(Server Side Rendering) and it’s not required for client-only application.
Formulae
[
"effector/babel-plugin",
{
"factories": ["path/here"]
}
]
-
Type:
string[]
-
Factories can have any number of arguments.
-
Factories can create any number of units.
-
Factories can call any effector methods.
-
Factories can call other factories from other modules.
-
Modules with factories can export any number of functions.
-
Factories should be compiled with
effector/babel-plugin
as well as code which use them.
Examples
// .babelrc
{
"plugins": [
[
"effector/babel-plugin",
{
"factories": ["src/createEffectStatus", "~/createCommonPending"]
}
]
]
}
// ./src/createEffectStatus.js
import { rootDomain } from "./rootDomain";
export function createEffectStatus(fx) {
const $status = rootDomain.createStore("init").on(fx.finally, (_, { status }) => status);
return $status;
}
// ./src/statuses.js
import { createEffectStatus } from "./createEffectStatus";
import { fetchUserFx, fetchFriendsFx } from "./api";
export const $fetchUserStatus = createEffectStatus(fetchUserFx);
export const $fetchFriendsStatus = createEffectStatus(fetchFriendsFx);
Import createEffectStatus
from './createEffectStatus'
was treated as factory function, so each store created by it
has its own sid and will be handled by serialize
independently, although without factories
they will share the same sid
.
reactSsr
Replaces imports from effector-react
to effector-react/scope
. Useful for building both server-side and client-side
builds from the same codebase.
Since effector 23.0.0 the core team recommends deleting this option from babel-plugin
configuration because effector-react supports SSR by default.
Formulae
[
"effector/babel-plugin",
{
"reactSsr": false
}
]
- Type:
boolean
- Default:
false
addNames
Adds name to units factories call. Useful for minification and obfuscation of production builds.
Formulae
[
"effector/babel-plugin",
{
"addNames": true
}
]
- Type:
boolean
- Default:
true
addLoc
Adds location to methods’ calls. Used by devtools, for example effector-logger.
Formulae
[
"effector/babel-plugin",
{
"addLoc": false
}
]
- Type:
boolean
- Default:
false
debugSids
Adds a file path and variable name of a unit definition to a sid. Useful for debugging SSR.
Formulae
[
"effector/babel-plugin",
{
"debugSids": false
}
]
- Type:
boolean
- Default:
false
noDefaults
Option for effector/babel-plugin
for making custom unit factories with clean configuration.
Formulae
[
"effector/babel-plugin",
{
"noDefaults": false
}
]
- Type:
boolean
- Default:
false
Examples
// .babelrc
{
"plugins": [
["effector/babel-plugin", { "addLoc": true }],
[
"effector/babel-plugin",
{
"importName": "@lib/createInputField",
"storeCreators": ["createInputField"],
"noDefaults": true
},
"createInputField"
]
]
}
// @lib/createInputField.js
import { createStore } from "effector";
import { resetForm } from "./form";
export function createInputField(defaultState, { sid, name }) {
return createStore(defaultState, { sid, name }).reset(resetForm);
}
// src/state.js
import { createInputField } from "@lib/createInputField";
const foo = createInputField("-");
/*
will be treated as store creator and compiled to
const foo = createInputField('-', {
name: 'foo',
sid: 'z&si65'
})
*/
Usage with Bundlers
Vite + React (SSR)
To use with effector/babel-plugin
, you have to following next steps:
- Install
@vitejs/plugin-react
package. vite.config.js
should be follows:
Note:
effector/babel-plugin
is not a package, it is bundled witheffector
// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [
react({
babel: {
plugins: ["effector/babel-plugin"],
// Use .babelrc files
babelrc: true,
// Use babel.config.js files
configFile: true,
},
}),
],
});