# @plumeria/unplugin

Source: https://plumeria.dev/docs/api-reference/plugins/unplugin





[`@plumeria/unplugin`](https://www.npmjs.com/package/@plumeria/unplugin) is a general-purpose bundler plugin for Plumeria.

## Installation [#installation]

<Tabs items="['npm', 'yarn', 'pnpm']">
  <Tab>
    ```sh title="Terminal"
    npm i -D @plumeria/unplugin
    ```
  </Tab>

  <Tab>
    ```sh title="Terminal"
    yarn add -D @plumeria/unplugin
    ```
  </Tab>

  <Tab>
    ```sh title="Terminal"
    pnpm i -D @plumeria/unplugin
    ```
  </Tab>
</Tabs>

## Configuration [#configuration]

```ts
import plumeria from '@plumeria/unplugin';
export default {
  plugins: [
    plumeria.vite({
      include: ['**/*.{ts,tsx}'],
      exclude: ['**/node_modules/**'],
      devEmitToDisk: false,
      styleProp: 'sx',
    }),
  ],
};
```

### Options [#options]

* `include`: The path to the file to be converted.
* `exclude`: The path to the file to be excluded from conversion.
* `devEmitToDisk`: Whether to write styles as actual files (`zero-virtual.css`) instead of virtual modules in development mode. The default is `false`.
* `styleProp`: The JSX prop that carries styles. The default is `'classStyle'`.
* `withoutLogicalProperties`: Rejects the logical name of a property that also has a physical name. The default is `false`.
* `withoutPhysicalProperties`: Rejects the physical name of a property that also has a logical name. The default is `false`.

```ts
interface PluginOptions {
  include?: string | RegExp | Array<string | RegExp>;
  exclude?: string | RegExp | Array<string | RegExp>;
  devEmitToDisk?: boolean;
  styleProp?: string;
  withoutLogicalProperties?: boolean | { sizes?: boolean };
  withoutPhysicalProperties?: boolean | { sizes?: boolean };
}
```

### styleProp [#styleprop]

Renaming the prop takes two steps, and they have to agree. Tell the plugin:

```ts
plumeria.vite({ styleProp: 'sx' });
```

and declare the same name for TypeScript. `@plumeria/core` ships no prop declaration of its own, so add one file to your project:

```ts title="plumeria.d.ts"
import type { Style } from '@plumeria/core';

declare global {
  namespace React {
    interface HTMLAttributes<T> {
      sx?: Style;
    }
    interface SVGAttributes<T> {
      sx?: Style;
    }
  }
}
```

For the default name, reference the declaration that ships with the package instead:

```ts title="plumeria.d.ts"
/// <reference types="@plumeria/core/class-style" />
```

If the two disagree, the prop type-checks but is never compiled away. [`@plumeria/eslint-plugin`](/docs/api-reference/plugins/eslint-plugin) reads the same name from `settings.plumeria.styleProp`.

### withoutLogicalProperties and withoutPhysicalProperties [#withoutlogicalproperties-and-withoutphysicalproperties]

Two names for the same box edge cannot be ranked by specificity, so a file that
uses both leaves the result to source order. These options settle it by
rejecting one spelling:

```ts
plumeria.vite({ withoutPhysicalProperties: true });
```

The build fails on the first rejected property, and the message names the file
and the property to write instead. Nothing is rewritten. `{ sizes: true }`
extends the check from the edges to the twelve axis pairs — `width`, `height`,
their `min` and `max` forms, and `overflow`, `overscroll-behavior` and
`contain-intrinsic-size` on both axes:

```ts
plumeria.vite({ withoutPhysicalProperties: { sizes: true } });
```

Enabling both is a configuration error, and the direction has to match the lint
rule you run: `withoutPhysicalProperties` with
[`no-physical-properties`](/docs/api-reference/plugins/eslint-plugin/optional-rules) and `withoutLogicalProperties` with
[`no-logical-properties`](/docs/api-reference/plugins/eslint-plugin/optional-rules), `{ sizes }` included. Set opposite
directions and the rule renames a property the build then rejects.

[Specificity](/docs/reference/specificity) explains why the pair cannot be
ranked, and why neither spelling is rewritten for you.

## Driving the transform [#driving-the-transform]

`@plumeria/unplugin/factory` exposes the plugin behind every bundler entry. `transform` takes a source string and hands back the rewritten code; `load` hands back the stylesheet it emitted:

```js
const { unpluginFactory } = require('@plumeria/unplugin/factory');

const plugin = unpluginFactory();
const { code } = await plugin.transform(source, id);
const css = plugin.load(code.match(/import "(.+\.zero\.css)"/)[1]);
```

No bundler, no DOM and no runtime resolution of `@plumeria/core` is involved, so it runs anywhere plain JavaScript does. The hooks are part of the published surface. See [Testing](/docs/testing).
