CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-server-dom-webpack

React Server Components bindings for DOM using Webpack, enabling server-side rendering with streaming support and client-server communication.

Pending
Overview
Eval results
Files

data-communication.mddocs/

Data Communication

Functions for encoding client-to-server data, decoding server responses, and handling form actions in React Server Components applications.

Capabilities

Encode Reply

Encodes client-side data for transmission to the server, supporting complex data structures, files, and temporary references.

/**
 * Encodes client data for server transmission
 * @param value - Any serializable value to encode
 * @param options - Optional encoding configuration
 * @returns Promise resolving to encoded data in appropriate format
 */
function encodeReply(
  value: ReactServerValue,
  options?: EncodeReplyOptions
): Promise<string | URLSearchParams | FormData>;

Usage Examples:

import { encodeReply } from "react-server-dom-webpack/client.browser";

// Encode simple data
const simpleData = await encodeReply({
  action: "updateProfile",
  userId: 123,
  name: "John Doe"
});

// Encode with files
const formData = await encodeReply({
  message: "Hello server",
  files: [fileInput.files[0], fileInput.files[1]],
  metadata: { timestamp: Date.now() }
});

// Encode with abort signal
const abortController = new AbortController();
const encodedData = await encodeReply(complexObject, {
  signal: abortController.signal
});

// Send to server
await fetch("/api/server-action", {
  method: "POST",
  body: encodedData
});

Decode Reply

Decodes client-transmitted data on the server side, handling various formats including FormData and JSON strings.

/**
 * Decodes client data sent to the server
 * @param body - Request body containing encoded client data
 * @param webpackMap - Optional server manifest for module resolution
 * @param options - Optional configuration with temporary references
 * @returns Promise resolving to decoded client data
 */
function decodeReply<T>(
  body: string | FormData,
  webpackMap?: ServerManifest,
  options?: {temporaryReferences?: TemporaryReferenceSet}
): Thenable<T>;

Usage Examples:

import { decodeReply } from "react-server-dom-webpack/server.node";

// Handle POST request with encoded data
export async function POST(request) {
  const serverManifest = await loadServerManifest();
  
  // Decode string body
  const stringData = decodeReply(
    await request.text(),
    serverManifest
  );
  
  // Or decode FormData body
  const formData = decodeReply(
    await request.formData(),
    serverManifest
  );
  
  // Process decoded data
  const result = await processAction(formData);
  return Response.json(result);
}

// Handle multipart uploads
async function handleUpload(request) {
  const formData = await request.formData();
  const decodedData = decodeReply(formData, serverManifest);
  
  // Access files and regular data
  const { files, userInput, metadata } = decodedData;
  
  return processUpload(files, userInput, metadata);
}

Decode Reply from Busboy

Specialized decoding for multipart form data using the busboy library, ideal for file uploads in Node.js environments.

/**
 * Decodes multipart form data using busboy for Node.js
 * @param busboyStream - Busboy stream processing multipart data
 * @param bundlerConfig - Optional server manifest for module resolution
 * @returns Promise resolving to decoded form data with files and fields
 */
function decodeReplyFromBusboy(
  busboyStream: any,
  bundlerConfig?: ServerManifest
): Promise<any>;

Usage Examples:

import { decodeReplyFromBusboy } from "react-server-dom-webpack/server.node";
import busboy from "busboy";
import { IncomingMessage } from "http";

// Handle file upload with busboy
async function handleFileUpload(req: IncomingMessage) {
  const bb = busboy({ 
    headers: req.headers,
    limits: { fileSize: 10 * 1024 * 1024 } // 10MB limit
  });
  
  const decodedData = await decodeReplyFromBusboy(bb, serverManifest);
  
  // Process uploaded files and form fields
  const { files, fields } = decodedData;
  
  for (const file of files) {
    console.log(`Uploaded: ${file.filename}, Size: ${file.size}`);
    await saveFile(file);
  }
  
  return { success: true, uploadedFiles: files.length };
}

// Express.js integration
app.post("/upload", async (req, res) => {
  try {
    const result = await handleFileUpload(req);
    res.json(result);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

Decode Action

Decodes form actions submitted from client components, returning executable server functions.

/**
 * Decodes form action from client form submission
 * @param body - FormData containing action information and arguments
 * @param bundlerConfig - Optional server manifest for action resolution
 * @returns Promise resolving to executable action function or null
 */
function decodeAction(
  body: FormData,
  bundlerConfig?: ServerManifest
): Promise<() => any> | null;

Usage Examples:

import { decodeAction } from "react-server-dom-webpack/server.browser";

// Handle form action submission
export async function POST(request) {
  const formData = await request.formData();
  const action = await decodeAction(formData, serverManifest);
  
  if (!action) {
    return new Response("Invalid action", { status: 400 });
  }
  
  try {
    // Execute the decoded action
    const result = await action();
    return Response.json(result);
  } catch (error) {
    return new Response(error.message, { status: 500 });
  }
}

// Progressive enhancement form handling
async function handleFormSubmission(request) {
  const formData = await request.formData();
  
  // Try to decode as action first
  const action = await decodeAction(formData, serverManifest);
  
  if (action) {
    // Handle as server action
    return await action();
  } else {
    // Handle as traditional form submission
    return handleTraditionalForm(formData);
  }
}

Decode Form State

Decodes form state information for progressive enhancement and form validation scenarios.

/**
 * Decodes form state from action result and form data
 * @param actionResult - Result from previous action execution
 * @param body - FormData containing current form state
 * @param bundlerConfig - Optional server manifest for state resolution
 * @returns Decoded form state for progressive enhancement
 */
function decodeFormState(
  actionResult: any,
  body: FormData,
  bundlerConfig?: ServerManifest
): any;

Usage Examples:

import { decodeFormState } from "react-server-dom-webpack/server.browser";

// Handle form with validation state
export async function handleFormWithState(request, previousResult) {
  const formData = await request.formData();
  
  const formState = decodeFormState(
    previousResult,
    formData,
    serverManifest
  );
  
  // Use form state for validation and user feedback
  if (formState.errors) {
    return renderFormWithErrors(formState);
  }
  
  // Process valid form
  return processValidForm(formState.data);
}

// Multi-step form handling
async function handleMultiStepForm(request, stepResult) {
  const formData = await request.formData();
  const currentState = decodeFormState(stepResult, formData, serverManifest);
  
  if (currentState.isComplete) {
    return processCompleteForm(currentState);
  } else {
    return renderNextStep(currentState);
  }
}

Data Serialization Patterns

Common patterns for handling complex data structures in client-server communication.

Complex Object Encoding:

// Client-side: Encode complex nested object
const complexData = {
  user: { id: 1, name: "Alice" },
  preferences: { theme: "dark", notifications: true },
  files: [file1, file2],
  metadata: {
    timestamp: new Date(),
    location: navigator.geolocation
  }
};

const encoded = await encodeReply(complexData);

// Server-side: Decode and access nested data
const decoded = decodeReply(await request.formData(), serverManifest);
console.log(decoded.user.name); // "Alice"
console.log(decoded.files.length); // 2

File Upload Handling:

// Client-side: Encode files with metadata
const fileData = {
  action: "uploadDocument",
  files: Array.from(fileInput.files),
  category: "documents",
  tags: ["important", "project-a"]
};

const formData = await encodeReply(fileData);

// Server-side: Process uploaded files
const { action, files, category, tags } = decodeReply(formData, serverManifest);

for (const file of files) {
  await saveFileWithMetadata(file, { category, tags });
}

Types

interface EncodeReplyOptions {
  /** Set for tracking temporary references during encoding */
  temporaryReferences?: TemporaryReferenceSet;
  /** AbortSignal for cancelling encoding operation */
  signal?: AbortSignal;
}

type ReactServerValue = 
  | string
  | number
  | boolean
  | null
  | undefined
  | Array<ReactServerValue>
  | { [key: string]: ReactServerValue }
  | File
  | Blob
  | FormData
  | URLSearchParams;

type ServerManifest = Record<string, any>;
type TemporaryReferenceSet = any;

interface DecodedFormData {
  /** Uploaded files from multipart form */
  files?: File[];
  /** Form field values */
  fields?: Record<string, string | string[]>;
  /** Any additional encoded data */
  [key: string]: any;
}

Install with Tessl CLI

npx tessl i tessl/npm-react-server-dom-webpack

docs

client-apis.md

data-communication.md

index.md

nodejs-integration.md

server-apis.md

static-rendering.md

webpack-plugin.md

tile.json