Plugins

Linter Rules (Oxlint)

Enforcing framework standards, accessibility, and performance using native Oxlint JS plugins.

Linter Rules (@manicjs/lint)

Manic enforces production-grade performance, accessibility, and routing conventions using native Oxlint custom rules. Rather than using slow regex wrappers, Manic runs ESLint-compatible AST traversals natively within Oxlint's Rust engine via @manicjs/lint.


Installation

The @manicjs/lint plugin is installed automatically in new Manic projects, but you can also add it manually to existing workspaces:

bun add @manicjs/lint

Configuration

Enable the custom rules in your project's .oxlintrc.json configuration file by adding the plugin to the jsPlugins array and enabling the rules:

{
  "jsPlugins": [
    {
      "name": "manic",
      "specifier": "@manicjs/lint"
    }
  ],
  "rules": {
    "manic/no-raw-img-element": "warn",
    "manic/no-raw-anchor-element": "warn",
    "manic/image-needs-dimensions": "warn",
    "manic/routes-require-default-export": "error",
    "manic/no-sibling-route-import": "error"
  }
}

Enforced Linting Rules

1. manic/no-raw-img-element (Warning)

Bans the use of raw HTML <img> elements in favor of the framework's optimized <Image /> component.

  • Why: <Image /> enables automatic layout stability (preventing Cumulative Layout Shift) and uses server-side SIMD-accelerated image optimizations.
  • Incorrect:
    <img src="/assets/logo.png" alt="Logo" />
  • Correct:
    import { Image } from 'manicjs';
    
    <Image src="/assets/logo.png" alt="Logo" />

2. manic/no-raw-anchor-element (Warning)

Bans the use of raw HTML <a> tags in favor of the framework's routing <Link /> component.

  • Why: <Link /> intercept routing natively to trigger superfast SPA view transitions, bypassing full page reloads.
  • Incorrect:
    <a href="/about">About Us</a>
  • Correct:
    import { Link } from 'manicjs';
    
    <Link to="/about">About Us</Link>

3. manic/image-needs-dimensions (Warning)

Requires <Image /> components to explicitly declare both width and height properties unless the source (src) is a static vector (.svg) file.

  • Why: Reserving layout boxes before image load improves visual stability and prevents CLS layout jumps.
  • Incorrect:
    <Image src="/logo.png" alt="Logo" />
  • Correct:
    <Image src="/logo.png" alt="Logo" width={100} height={100} />

4. manic/routes-require-default-export (Error)

Ensures that all route components (inside app/routes/ but not prefixed with ~) contain a default export.

  • Why: Manic’s router discovery scanner expects every routing page entry to export its component as the default export. Missing default exports result in blank route pages.
  • Incorrect:
    export function Home() {
      return <h1>Home</h1>;
    }
  • Correct:
    export default function Home() {
      return <h1>Home</h1>;
    }

5. manic/no-sibling-route-import (Error)

Bans importing components or functions directly from sibling route files.

  • Why: Direct routing sibling imports break route isolation, cause duplicate bundling sizes, and complicate hot-module-reload (HMR) propagation.
  • Solution: Move shared code to a component folder (e.g. app/components/) or a route file prefixed with ~ (e.g. app/routes/~shared.tsx).
  • Incorrect:
    import SiblingComponent from './sibling-page.tsx';
  • Correct:
    import SharedComponent from '~/components/SharedComponent';

On this page