Babel plugin that optimizes React hook array destructuring to object destructuring for better performance and smaller bundle sizes. This plugin transforms array destructuring patterns commonly used with React hooks into more efficient object destructuring patterns.
Creates a Babel plugin that transforms React hook array destructuring patterns.
/**
* Babel plugin factory for optimizing React hook destructuring
* @param {object} babel - Babel object with types utility
* @returns {BabelPlugin} Babel plugin object with visitor pattern
*/
function optimizeHookDestructuring({ types });
interface HookOptimizationOptions {
/** Only transform built-in React hooks */
onlyBuiltIns?: boolean;
/** Libraries that provide hooks (true for React/Preact, or specific library name) */
lib?: boolean | string;
}
interface BabelPlugin {
name: string;
visitor: object;
}Usage Examples:
// Babel configuration with hook optimization
{
"plugins": [
["./optimize-hook-destructuring", {
"lib": true,
"onlyBuiltIns": false
}]
]
}
// Programmatic usage
import babel from "@babel/core";
import optimizeHookDestructuring from "./optimize-hook-destructuring";
const result = babel.transform(code, {
plugins: [
[optimizeHookDestructuring, { lib: true }]
]
});The plugin transforms array destructuring to object destructuring for better performance:
Before transformation:
import { useState } from "react";
const [count, setCount] = useState(0);
const [name, setName] = useState("");After transformation:
import { useState } from "react";
const { 0: count, 1: setCount } = useState(0);
const { 0: name, 1: setName } = useState("");Works with custom hooks that follow the use* naming pattern:
Before transformation:
import { useCustomState } from "./hooks";
const [value, setValue, reset] = useCustomState(initialValue);After transformation:
import { useCustomState } from "./hooks";
const { 0: value, 1: setValue, 2: reset } = useCustomState(initialValue);When onlyBuiltIns: true, only transforms recognized React built-in hooks:
Recognized built-in hooks:
useCallbackuseContextuseDebugValueuseEffectuseImperativeHandleuseLayoutEffectuseMemouseReduceruseRefuseState// Configuration for built-ins only
{
"plugins": [
["./optimize-hook-destructuring", {
"onlyBuiltIns": true
}]
]
}lib)Controls which libraries are processed for hook transformations:
// Process React and Preact hooks (default when lib: true)
{
"lib": true
}
// Process specific library only
{
"lib": "react"
}
// Process custom hook library
{
"lib": "my-hooks-library"
}
// No library filtering (process all hook-like functions)
{
// lib option omitted
}Library configuration examples:
// React hooks only
import { useState } from "react";
const [count, setCount] = useState(0); // ✅ Transformed
import { useCustom } from "other-lib";
const [value, setValue] = useCustom(); // ❌ Not transformed
// Custom library
{
"lib": "my-hooks"
}
import { useMyHook } from "my-hooks";
const [data, setData] = useMyHook(); // ✅ Transformed
import { useState } from "react";
const [count, setCount] = useState(0); // ❌ Not transformedonlyBuiltIns)Restricts transformations to only React's built-in hooks:
// Transform all hook-like functions (default)
{
"onlyBuiltIns": false
}
// Transform only React built-in hooks
{
"onlyBuiltIns": true
}Built-in filtering examples:
// onlyBuiltIns: false (default)
const [state, setState] = useState(0); // ✅ Transformed
const [data, setData] = useCustomHook(); // ✅ Transformed
// onlyBuiltIns: true
const [state, setState] = useState(0); // ✅ Transformed
const [data, setData] = useCustomHook(); // ❌ Not transformedThe plugin uses regular expressions to identify hook functions:
Default pattern (all hooks):
const isHook = /^use[A-Z]/;
// Matches: useState, useEffect, useCustomHook, etc.Built-in hooks pattern:
const isBuiltInHook = /^use(Callback|Context|DebugValue|Effect|ImperativeHandle|LayoutEffect|Memo|Reducer|Ref|State)$/;
// Matches only: useCallback, useContext, useDebugValue, etc.When library filtering is enabled, the plugin validates import sources:
// Valid import for React hooks
import { useState } from "react";
const [count, setCount] = useState(0); // ✅ Processed
// Invalid import source
import { useState } from "other-library";
const [count, setCount] = useState(0); // ❌ SkippedObject destructuring can be more efficiently minified than array destructuring:
Array destructuring (before):
const [a, b, c] = hook();
// Minified: const[a,b,c]=hook();Object destructuring (after):
const {0: a, 1: b, 2: c} = hook();
// Minified: const{0:a,1:b,2:c}=hook();
// Further optimization possible by minifiersObject destructuring can have slight performance advantages in certain JavaScript engines for accessing specific indices.
The plugin is automatically included in the babel-preset-gatsby configuration:
// Automatic inclusion in Gatsby projects
{
"plugins": [
[
"./optimize-hook-destructuring",
{
"lib": true
}
]
]
}You can configure the plugin separately for advanced use cases:
// Custom Babel configuration
{
"presets": ["babel-preset-gatsby"],
"plugins": [
// Additional hook optimization with custom settings
["babel-preset-gatsby/optimize-hook-destructuring", {
"lib": "my-custom-hooks",
"onlyBuiltIns": false
}]
]
}The plugin only transforms code that meets all criteria:
// All conditions met - will be transformed
import { useState } from "react";
const [count, setCount] = useState(0);
// Not transformed - not array destructuring
const state = useState(0);
// Not transformed - not a variable assignment
useState(0);
// Not transformed - doesn't match hook pattern
const [data, setData] = fetchData();