Edit this page

Framework Integration

⚠️ Alpha Stage: Framework integration APIs are in alpha and may change.

Learn how to integrate Photon into your Vite-based framework to enable universal server capabilities.

Overview

Photon enables frameworks to work universally across server runtimes and deployment platforms. This guide shows how to integrate Photon into your framework.

Basic Integration

1. Install Dependencies

npm install @photonjs/core @photonjs/runtime @universal-middleware/core

2. Create Photon Plugin

Create a Vite plugin that integrates Photon:

// src/vite/photonPlugin.ts
import { installPhoton } from "@photonjs/runtime/vite";
import type { Plugin } from "vite";
 
export function photonPlugin(): Plugin[] {
  return installPhoton("your-framework", {
    // Enable full Photon functionality
    fullInstall: true,
 
    // Configure code splitting (optional)
    codeSplitting: {
      // Disable if your framework doesn't support it
      framework: false,
    },
 
    // Define universal middlewares for all entries
    resolveMiddlewares() {
      return "your-framework/universal-middleware";
    },
 
    // Define framework-specific entries
    entries: {
      standalone: {
        id: "your-framework/standalone",
        compositionMode: "isolated",
      },
    },
  });
}

3. Create Universal Middleware

Define middleware using the universal middleware pattern:

// src/photon/middlewares/ssr.ts
import { enhance } from "@universal-middleware/core";
 
export const ssrMiddleware = enhance(
  async (request: Request) => {
    // Your framework's rendering logic
    const html = await renderPage(request.url);
 
    return new Response(html, {
      status: 200,
      headers: {
        "Content-Type": "text/html",
      },
    });
  },
  {
    name: "your-framework:ssr",
    path: "/**",
    method: "GET",
  }
);

4. Export Middleware

Create entry points for your middleware:

// src/photon/entries/universal-middleware.ts
export { ssrMiddleware } from "../middlewares/ssr.js";
export { apiMiddleware } from "../middlewares/api.js";

5. Configure Package Exports

Set up conditional exports in your package.json:

{
  "exports": {
    "./universal-middleware": "./dist/photon/entries/universal-middleware.js",
    "./standalone": "./dist/photon/entries/standalone.js"
  }
}

Advanced Patterns

Multiple Middleware Types

Create different middleware for different purposes:

Conditional Middleware Loading

Use export conditions to load middleware conditionally:

{
  "exports": {
    "./universal-middleware": {
      "types": "./dist/universal.d.ts",
      "development": {
        "types": "./dist/universal.dev.d.ts",
        "import": "./dist/universal.dev.js",
        "default": "./dist/universal.dev.js"
      },
      "worker": {
        "types": "./dist/universal.edge.d.ts",
        "import": "./dist/universal.edge.js",
        "default": "./dist/universal.edge.js"
      },
      "import": "./dist/universal.js",
      "default": "./dist/universal.js"
    }
  }
}

Deployment Integration

Enable your framework users to deploy anywhere by integrating deployment adapters.

Basic Deployment Support

// src/vite/photonPlugin.ts
export function photonPlugin(options: FrameworkOptions): Plugin[] {
  const plugins = installPhoton("your-framework", {
    fullInstall: true,
    resolveMiddlewares: () => "your-framework/universal-middleware"
  });
 
  // Add deployment adapters based on user configuration
  if (options.deploy?.cloudflare) {
    const { cloudflare } = await import("@photonjs/cloudflare/vite");
    plugins.push(cloudflare(options.deploy.cloudflare));
  }
 
  return plugins;
}

Framework Configuration for Deployment

// Allow users to configure deployment
export interface FrameworkOptions {
  deploy?: {
    cloudflare?: {
      entry?: string;
      pages?: boolean;
    };
    vercel?: {
      edge?: boolean;
    };
    netlify?: {
      edge?: boolean;
    };
  };
}

Universal Build Output

Ensure your framework generates universal build outputs:

// src/build/index.ts
export async function buildFramework(options: BuildOptions) {
  // Build client assets
  await buildClient(options);
 
  // Build server with universal middleware
  await buildServer(options);
 
  // Generate deployment-specific entries
  await generateDeploymentEntries(options);
}
 
async function generateDeploymentEntries(options: BuildOptions) {
  // Generate Cloudflare entry
  if (options.deploy?.cloudflare) {
    await generateCloudflareEntry(options);
  }
 
  // Generate Vercel entry
  if (options.deploy?.vercel) {
    await generateVercelEntry(options);
  }
}

Integration Examples

Simple Framework (awesome-framework)

The example/awesome-framework shows a minimal integration:

  • Universal middleware for SSR and API handling
  • Simple configuration with basic Photon setup
  • Export conditions for conditional loading

Key files:

  • src/vite/photonPlugin.ts - Photon integration
  • src/photon/middlewares/ssr.ts - SSR middleware
  • src/photon/entries/ - Middleware exports

Advanced Framework (Vike)

Vike demonstrates advanced Photon integration:

  • Complex middleware composition with multiple layers
  • Runtime-specific optimizations for different deployment targets
  • Advanced configuration with user customization options

Best Practices

Universal Middleware Design

Every handler and middleware used by Photon should respect the universal middleware pattern.

import { enhance } from "@universal-middleware/core";
 
// ✅ Good: Universal middleware that works everywhere
export const middleware = enhance(
  async (request: Request) => {
    // Use standard Web APIs
    const url = new URL(request.url);
    const response = await processRequest(url);
    return response;
  },
  { name: "framework:handler" }
);
 
// ❌ Avoid: Platform-specific code
export const middleware = enhance(
  async (request: Request, context, runtime) => {
    // Don't rely on platform-specific context
    const nodeReq = runtime.req.node; // Won't work on edge
    return processNodeRequest(nodeReq);
  },
  { name: "framework:handler" }
);

Development vs. Production

// src/photon/entries/universal-middleware.dev.ts
import { ssrMiddleware } from "../middlewares/ssr.js";
import { loggerMiddleware } from "../middlewares/logger.js";
import { errorMiddleware } from "../middlewares/error.js";
 
export default [ssrMiddleware, loggerMiddleware, errorMiddleware];
 
// src/photon/entries/universal-middleware.prod.ts  
import { ssrMiddleware } from "../middlewares/ssr.js";
import { errorMiddleware } from "../middlewares/error.js";
// No logger in production
 
export default [ssrMiddleware, errorMiddleware];

Testing Your Integration

TODO

Troubleshooting

TODO