React Refresh runtime and Babel plugin for Fast Refresh functionality that enables live editing of React components without losing state
—
Babel transformation plugin that automatically instruments React components for Fast Refresh support. The plugin analyzes component code and injects the necessary registration and signature calls.
Main plugin factory function that creates the Babel plugin configuration.
/**
* Babel plugin factory for React Refresh transforms
* @param babel - Babel instance with types and utilities
* @param opts - Plugin configuration options
* @returns Babel plugin configuration object
* @throws Error if not in development environment (unless skipEnvCheck is true)
*/
function BabelPlugin(babel: any, opts?: BabelPluginOptions): BabelPluginConfig;
interface BabelPluginOptions {
/** Custom refresh registration function name (default: '$RefreshReg$') */
refreshReg?: string;
/** Custom refresh signature function name (default: '$RefreshSig$') */
refreshSig?: string;
/** Skip development environment check */
skipEnvCheck?: boolean;
/** Emit full signatures instead of hashed keys */
emitFullSignatures?: boolean;
}
interface BabelPluginConfig {
visitor: {
ExportDefaultDeclaration: Function;
FunctionDeclaration: Function;
VariableDeclaration: Function;
Program: Function;
[key: string]: any;
};
}Usage Example:
// babel.config.js
module.exports = {
plugins: [
['react-refresh/babel', {
skipEnvCheck: process.env.NODE_ENV !== 'development',
refreshReg: '$RefreshReg$',
refreshSig: '$RefreshSig$',
emitFullSignatures: false
}]
]
};Customize the registration function name used in generated code:
// With default options
$RefreshReg$(MyComponent, 'MyComponent');
// With custom refreshReg: 'myCustomReg'
myCustomReg(MyComponent, 'MyComponent');Customize the signature function name used in generated code:
// With default options
$RefreshSig$(MyComponent, 'hookSignature', false);
// With custom refreshSig: 'myCustomSig'
myCustomSig(MyComponent, 'hookSignature', false);Skip the automatic development environment check:
// Plugin normally throws in production unless skipEnvCheck is true
{
plugins: [
['react-refresh/babel', { skipEnvCheck: true }]
]
}Control signature key format:
// With emitFullSignatures: false (default)
$RefreshSig$(MyComponent, 'a8f3k2n9x7', false);
// With emitFullSignatures: true
$RefreshSig$(MyComponent, 'useState{[count, setCount]}(0)', false);The plugin performs several AST transformations:
Input:
function MyComponent() {
const [count, setCount] = useState(0);
return <div>{count}</div>;
}Output:
var _s = $RefreshSig$();
function MyComponent() {
_s();
const [count, setCount] = useState(0);
return <div>{count}</div>;
}
_s(MyComponent, 'useState{[count, setCount]}(0)', false);Input:
const MyComponent = () => {
const [count, setCount] = useState(0);
return <div>{count}</div>;
};Output:
var _s = $RefreshSig$();
const MyComponent = () => {
_s();
const [count, setCount] = useState(0);
return <div>{count}</div>;
};
_s(MyComponent, 'useState{[count, setCount]}(0)', false);Input:
export default function MyComponent() {
return <div>Hello</div>;
}Output:
var _c;
export default function MyComponent() {
return <div>Hello</div>;
}
_c = MyComponent;
$RefreshReg$(_c, 'MyComponent%default%');Input:
const EnhancedComponent = memo(() => {
return <div>Enhanced</div>;
});Output:
var _s = $RefreshSig$();
var _c;
const EnhancedComponent = _c = memo(_s(() => {
_s();
return <div>Enhanced</div>;
}, 'hookSignature'));
$RefreshReg$(_c, 'EnhancedComponent');The plugin automatically detects Hook usage patterns:
useState, useReducer, useEffect, useLayoutEffectuseMemo, useCallback, useRef, useContextuseImperativeMethods, useDebugValueAny function call starting with use and a capital letter:
function MyComponent() {
const data = useCustomData();
const auth = useAuth();
// etc.
}// Single Hook
'useState{[count, setCount]}(0)'
// Multiple Hooks
'useState{[count, setCount]}(0)\nuseEffect{}([count])'
// Custom Hooks
'useCustomHook{}'Use special comments to force component remounting:
/* @refresh reset */
function MyComponent() {
// This component will always remount on changes
return <div>Always resets</div>;
}The plugin automatically detects the environment:
// Automatically enabled in development
babel.env() === 'development'
// Throws error in production unless skipEnvCheck: true
babel.env() === 'production' // Error!$RefreshReg$ and $RefreshSig$ to be in scope@babel/preset-typescriptInstall with Tessl CLI
npx tessl i tessl/npm-react-refresh