# @plumeria/next-plugin

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





[`@plumeria/next-plugin`](https://www.npmjs.com/package/@plumeria/next-plugin) is a plugin for using Plumeria with Next.js.
It supports both Turbopack and Webpack for Next.js and provides style compilation and HMR (Hot Module Replacement) at build time.

## Installation [#installation]

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

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

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

## Usage [#usage]

Wrap your configuration using `withPlumeria` in `next.config.ts` or `next.config.js`.

```ts title="next.config.ts"
import type { NextConfig } from "next";
import { withPlumeria } from "@plumeria/next-plugin";

const nextConfig: NextConfig = {
  // Existing configuration
};

export default withPlumeria(nextConfig);
```

## API [#api]

### `withPlumeria(nextConfig, options)` [#withplumerianextconfig-options]

Takes a Next.js configuration object and returns a new configuration object with the necessary Turbopack or Webpack configurations added for Plumeria.

* `nextConfig`: Next.js configuration object.
* `options`: Compiler options, passed through to the loader.

```ts
function withPlumeria(nextConfig: NextConfig, options?: LoaderOptions): NextConfig;
```

### Options [#options]

```ts title="next.config.ts"
export default withPlumeria(nextConfig, {
  include: ['./src/**/*.{ts,tsx}'],
  exclude: ['**/node_modules/**', '**/.next/**'],
  styleProp: 'sx',
});
```

* `include`: Globs the stylesheet is compiled from. The default is every `js/jsx/ts/tsx` file.
* `exclude`: Globs excluded from that compilation. The default is `node_modules`, `dist` and `.next`.
* `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 LoaderOptions {
  include?: string[];
  exclude?: string[];
  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 title="next.config.ts"
export default withPlumeria(nextConfig, { styleProp: 'sx' });
```

and declare the same name for TypeScript instead of referencing the default:

```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 title="next.config.ts"
export default withPlumeria(nextConfig, { 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 title="next.config.ts"
export default withPlumeria(nextConfig, {
  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 loader [#driving-the-loader]

`@plumeria/turbopack-loader` is the loader `withPlumeria` installs, and it can be called directly with a webpack loader context of your own:

```js
const loader = require('@plumeria/turbopack-loader');
const fn = loader.default ?? loader;

fn.call(
  {
    resourcePath: `${__dirname}/fixture.tsx`,
    async: () => (err, content) => (err ? reject(err) : resolve(content)),
    addDependency: () => {},
    clearDependencies: () => {},
  },
  source,
);
```

`withPlumeria` takes no part in this. The test requires the loader itself, so add `@plumeria/turbopack-loader` to your dev dependencies — it arrives as a dependency of this package either way, but a strict package manager such as pnpm does not put a transitive dependency where your own code can reach it.

The rewritten code comes back through `async`. The stylesheet is written only when `NODE_ENV` is `development` or `production` — a test run is neither, so the file is left alone — and those writes are taken under a lock, so parallel callers do not lose rules. Those four context properties are part of the published surface. See [Testing](/docs/testing).
