# Configuration

Set up your plugin project with the correct structure and build configuration.

## vite.config.js (REQUIRED FORMAT)

**CRITICAL:** Use this EXACT format for your vite.config.js:

```javascript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  root: 'ui',                    // React source is in ui/ directory
  base: '',                      // IMPORTANT: Empty string, NOT './'
  server: {
    port: 3000,
    strictPort: false,
  },
  build: {
    outDir: '../dist',           // Build output to dist/ (parent of ui/)
    assetsDir: 'assets',
    emptyOutDir: true,
  },
});
```

**Why `base: ''`?**
- MAJK loads plugins in iframes with dynamic paths
- Empty base ensures assets load correctly
- `base: './'` will cause 404 errors for assets

## Project Structure

```
my-plugin/
├── src/
│   ├── index.ts              # Plugin definition (definePlugin)
│   └── core/                 # Business logic (no plugin dependencies)
│       ├── analytics.ts
│       └── formatters.ts
├── ui/
│   ├── index.html
│   ├── src/
│   │   ├── main.tsx          # React entry point
│   │   ├── App.tsx           # Router setup
│   │   ├── components/
│   │   │   ├── DashboardPage.tsx
│   │   │   ├── SettingsPage.tsx
│   │   │   └── shared/
│   │   │       └── ErrorBoundary.tsx
│   │   └── generated/        # Auto-generated (DO NOT EDIT)
│   │       ├── hooks.ts      # useHealth(), useGetAnalytics(), etc.
│   │       ├── client.ts     # RPC client
│   │       ├── types.ts      # TypeScript types
│   │       └── index.ts
│   └── vite.config.js
├── tests/
│   └── plugin/
│       ├── functions/
│       │   └── unit/
│       │       ├── health.test.js
│       │       └── analytics.test.js
│       └── ui/
│           └── unit/
│               ├── dashboard.test.js
│               └── events-list.test.js
├── dist/                     # Build output (ignored by git)
│   ├── index.html
│   ├── assets/
│   │   ├── index-abc123.js
│   │   └── index-def456.css
│   └── index.js              # Plugin definition (compiled)
├── package.json
├── tsconfig.json
├── .gitignore
└── README.md
```

## package.json

```json
{
  "name": "@yourorg/my-plugin",
  "version": "1.0.0",
  "main": "dist/index.js",
  "type": "commonjs",
  "scripts": {
    "build": "tsc && cd ui && npm run build",
    "build:plugin": "tsc",
    "build:ui": "cd ui && npm run build",
    "dev": "cd ui && npm run dev",
    "test:plugin:functions": "majk-test 'tests/plugin/functions/**/*.test.js'",
    "test:plugin:ui": "majk-test 'tests/plugin/ui/**/*.test.js'",
    "test:plugin": "majk-test 'tests/plugin/**/*.test.js'"
  },
  "dependencies": {
    "@majkapp/plugin-kit": "^3.2.1"
  },
  "devDependencies": {
    "@majkapp/plugin-test": "^1.0.0",
    "@majkapp/plugin-ui": "^1.0.0",
    "@types/node": "^20.0.0",
    "@types/react": "^18.0.0",
    "@types/react-dom": "^18.0.0",
    "@vitejs/plugin-react": "^4.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.11.0",
    "typescript": "^5.0.0",
    "vite": "^4.3.0"
  }
}
```

## tsconfig.json (Plugin)

```json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "declaration": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "moduleResolution": "node"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "ui", "tests"]
}
```

## tsconfig.json (UI)

```json
// ui/tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}
```

## ui/index.html

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Plugin</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>
```

## ui/src/main.tsx

```typescript
import React from 'react';
import ReactDOM from 'react-dom/client';
import { App } from './App';
import './index.css';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);
```

## ui/src/App.tsx

```typescript
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { DashboardPage } from './components/DashboardPage';
import { SettingsPage } from './components/SettingsPage';

export function App() {
  // CRITICAL: Use window.__MAJK_IFRAME_BASE__ for basename
  const basename = (window as any).__MAJK_IFRAME_BASE__ || '/';

  return (
    <BrowserRouter basename={basename}>
      <Routes>
        <Route path="/" element={<DashboardPage />} />
        <Route path="/settings" element={<SettingsPage />} />
      </Routes>
    </BrowserRouter>
  );
}
```

## .gitignore

```
# Dependencies
node_modules/
ui/node_modules/

# Build output
dist/
ui/dist/

# Test output
tests/__screenshots__/

# Logs
*.log
npm-debug.log*

# Environment
.env
.env.local

# IDE
.vscode/
.idea/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db
```

## Build Process

### 1. Install Dependencies

```bash
# Root dependencies
npm install

# UI dependencies
cd ui && npm install && cd ..
```

### 2. Build Plugin

```bash
npm run build
```

This runs:
1. `tsc` - Compiles `src/index.ts` → `dist/index.js`
2. `cd ui && npm run build` - Builds React app → `dist/` (assets)

### 3. Generated Files

After build, your `dist/` should contain:

```
dist/
├── index.js              # Compiled plugin definition
├── index.d.ts            # TypeScript declarations
├── index.html            # Built React app
└── assets/
    ├── index-abc123.js   # Bundled React app
    └── index-def456.css  # Bundled CSS
```

## Development Workflow

### 1. Start UI Development Server

```bash
npm run dev
```

Opens UI at `http://localhost:3000` with hot reload.

### 2. Build Plugin for Testing

```bash
npm run build:plugin
```

Compiles plugin without rebuilding UI.

### 3. Full Build

```bash
npm run build
```

Compiles plugin AND builds UI for production.

### 4. Run Tests

```bash
# All tests
npm run test:plugin

# Function tests only
npm run test:plugin:functions

# UI tests only
npm run test:plugin:ui
```

## Environment Variables

React app can access these globals:

```typescript
// ui/src/types/window.d.ts
declare global {
  interface Window {
    __MAJK_BASE_URL__: string;      // Host base URL
    __MAJK_IFRAME_BASE__: string;   // Plugin iframe base
    __MAJK_PLUGIN_ID__: string;     // Your plugin ID
  }
}

export {};
```

Usage:

```typescript
// ui/src/config.ts
export const config = {
  baseUrl: window.__MAJK_BASE_URL__,
  iframeBase: window.__MAJK_IFRAME_BASE__,
  pluginId: window.__MAJK_PLUGIN_ID__
};
```

## Multi-Package Setup (Optional)

For larger plugins, split into separate packages:

```
packages/
├── plugin/              # @yourorg/my-plugin
│   ├── src/
│   ├── package.json
│   └── tsconfig.json
├── ui/                  # @yourorg/my-plugin-ui
│   ├── src/
│   ├── package.json
│   └── vite.config.js
└── core/                # @yourorg/my-plugin-core
    ├── src/
    ├── package.json
    └── tsconfig.json
```

## Troubleshooting

### Assets 404 Error

**Problem:** UI loads but assets fail with 404

**Fix:** Check `vite.config.js` has `base: ''` (NOT `base: './'`)

### Plugin Not Found

**Problem:** Plugin doesn't load in MAJK

**Fix:**
1. Ensure `dist/index.js` exists
2. Check `package.json` has `"main": "dist/index.js"`
3. Verify plugin calls `.build()` at the end

### Generated Hooks Not Found

**Problem:** `import { useHealth } from './generated/hooks'` fails

**Fix:**
1. Run `npm run build` to generate hooks
2. Check `ui/src/generated/` directory exists
3. Verify functions are defined before `.build()`

### Tests Can't Find Plugin

**Problem:** `invoke('functionName')` fails in tests

**Fix:**
1. Ensure plugin is built: `npm run build:plugin`
2. Check function name matches definition
3. Verify `export = plugin;` at end of `src/index.ts`

## Quick Start Checklist

- [ ] Create project structure
- [ ] Add `vite.config.js` with `base: ''`
- [ ] Add `tsconfig.json` for plugin and UI
- [ ] Create `src/index.ts` with `definePlugin()`
- [ ] Create `ui/src/App.tsx` with `BrowserRouter`
- [ ] Add `.gitignore` to exclude `dist/` and `node_modules/`
- [ ] Run `npm install` in root and `ui/`
- [ ] Run `npm run build` to compile
- [ ] Run `npm run test:plugin` to verify setup

## Next Steps

Run `npx @majkapp/plugin-kit --functions` - Define your functions
Run `npx @majkapp/plugin-kit --screens` - Configure screens
Run `npx @majkapp/plugin-kit --testing` - Write tests
