Skip to content

microdev1/solid-undestructure

Repository files navigation

SolidJS Props Transform Plugin

A Vite plugin that automatically transforms props destructuring in SolidJS components to use mergeProps and splitProps, preserving reactivity.

Why?

In SolidJS, destructuring props directly breaks reactivity because it converts reactive getters into static values:

// ❌ Breaks reactivity
function Component({ name, count }) {
  return (
    <div>
      {name}: {count}
    </div>
  )
}

The correct approach is to use splitProps and mergeProps:

// ✅ Maintains reactivity
import { splitProps } from 'solid-js'

function Component(_props) {
  const [{ name, count }] = splitProps(_props, ['name', 'count'])
  // ...
}

This plugin performs that transformation automatically.

Features

  • ✨ Automatically transforms destructured props to splitProps/mergeProps
  • 🎯 Handles default values using mergeProps
  • 🔄 Preserves spread parameters with splitProps
  • 📦 Auto-imports mergeProps and splitProps from 'solid-js'
  • ⚡ Skips non-component functions

Installation

bun add -D vite-plugin-solid-undestructure

Usage

import solidUndestructure from './plugins/solid-undestructure'
import solid from 'vite-plugin-solid'

export default defineConfig({
  plugins: [solidUndestructure(), solid() /* other plugins */]
})

Examples

Basic Destructuring

// Before
function Greeting({ name, age }) {
  return (
    <div>
      Hello {name}, you are {age} years old
    </div>
  )
}

// After
function Greeting(_props) {
  return (
    <div>
      Hello {_props.name}, you are {_props.age} years old
    </div>
  )
}

Default Values

// Before
function Button({ label = 'Click me', disabled = false }) {
  return <button disabled={disabled}>{label}</button>
}

// After
import { mergeProps } from 'solid-js'

function Button(_props) {
  const _merged = mergeProps({ label: 'Click me', disabled: false }, _props)
  return <button disabled={_merged.disabled}>{_merged.label}</button>
}

Spread Properties

// Before
function Card({ title, description, ...props }) {
  return (
    <div {...props}>
      <h2>{title}</h2>
      <p>{description}</p>
    </div>
  )
}

// After
import { splitProps } from 'solid-js'

function Card(_props) {
  const [, props] = splitProps(_props, ['title', 'description'])
  return (
    <div {...props}>
      <h2>{_props.title}</h2>
      <p>{_props.description}</p>
    </div>
  )
}

TestComponent (Defaults + Nested Destructuring + Spread)

// Before
import { For } from 'solid-js'

function TestComponent({
  name = 'World',
  count = 0,
  avatar = '/default.png',
  items,
  nested: { a, b },
  ...props
}: {
  name?: string
  count?: number
  avatar?: string
  items: string[]
  nested: { a: number; b: number }
  class?: string
  onClick?: () => void
}) {
  return (
    <div {...props}>
      <p>{props.class}</p>
      <pre>{a}</pre>
      <pre>{b}</pre>
      <img src={avatar} alt={name} />
      <h1>Hello {name}!</h1>
      <p>Count: {count}</p>
      <ul>
        <For each={items}>{(item) => <li>{item}</li>}</For>
      </ul>
    </div>
  )
}

// After
import { For, mergeProps, splitProps } from 'solid-js'

function TestComponent(_props) {
  const _merged = mergeProps({ name: 'World', count: 0, avatar: '/default.png' }, _props)
  const [, props] = splitProps(_merged, ['name', 'count', 'avatar', 'items', 'nested'])
  return (
    <div {...props}>
      <p>{props.class}</p>
      <pre>{_merged.nested.a}</pre>
      <pre>{_merged.nested.b}</pre>
      <img src={_merged.avatar} alt={_merged.name} />
      <h1>Hello {_merged.name}!</h1>
      <p>Count: {_merged.count}</p>
      <ul>
        <For each={_merged.items}>{(item) => <li>{item}</li>}</For>
      </ul>
    </div>
  )
}

How It Works

  1. Parse — Uses @babel/parser to parse TypeScript/JSX files into an AST
  2. Detect — Identifies functions with destructured props that return JSX
  3. Transform — Rewrites destructuring into mergeProps/splitProps calls and replaces all references to destructured identifiers with property accesses on the merged/props object
  4. Import — Adds necessary imports from solid-js if not already present
  5. Generate — Outputs transformed code with source maps

Notes

  • Only transforms functions that return JSX (regular functions are left untouched)
  • Requires the first parameter to be an object pattern (destructuring)
  • Skips files in node_modules

Testing

bun test

About

Automatically transforms props destructuring in SolidJS components

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors