or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

client-api.mdcontent-scripts.mdfile-writer-system.mdindex.mdmanifest-definition.mdplugin-configuration.md
tile.json

client-api.mddocs/

Client-Side API

Special import syntax and type definitions for content scripts, enabling different script formats and execution environments with HMR support. Provides seamless integration between modern development workflows and Chrome extension runtime requirements.

Capabilities

Script Import Syntax

Special import suffixes that transform script files for different Chrome extension execution contexts.

/**
 * Default script import - alias for ?script&loader
 * ESM format with dynamic import loader and HMR support
 * Use with Chrome Scripting API in background scripts or extension pages
 */
declare module '*?script' {
  const fileName: string;
  export default fileName;
}

/**
 * Explicit loader format
 * ESM format loaded via dynamic import script with HMR support
 * Exports the filename of the loader script for Chrome Scripting API
 */
declare module '*?script&loader' {
  const fileName: string;
  export default fileName;
}

/**
 * IIFE (Immediately Invoked Function Expression) format
 * Self-contained script for content scripts with opaque origins
 * No HMR support but guaranteed isolated execution
 */
declare module '*?script&iife' {
  const fileName: string;
  export default fileName;
}

/**
 * Pure ES module format
 * No loader wrapper, no HMR support
 * For injection into main world or when framework HMR is not needed
 */
declare module '*?script&module' {
  const fileName: string;
  export default fileName;
}

Usage Examples:

// In background script or extension page
import contentScript from "./content.ts?script";
import contentScriptLoader from "./content.ts?script&loader";
import contentScriptIIFE from "./content.ts?script&iife";
import contentScriptModule from "./content.ts?script&module";

// Inject using Chrome Scripting API
chrome.scripting.executeScript({
  target: { tabId: tab.id },
  files: [contentScript], // Uses the generated filename
});

// Inject into main world (requires ?script&module)
chrome.scripting.executeScript({
  target: { tabId: tab.id },
  files: [contentScriptModule],
  world: "MAIN",
});

Content Script Execution API

Interface for content scripts to integrate with the CRXJS execution lifecycle and performance monitoring.

declare namespace ContentScriptAPI {
  /**
   * Performance metrics for content script execution
   */
  interface ExecuteFnOptions {
    perf: {
      /** Time taken to inject the script (milliseconds) */
      injectTime: number;
      /** Time taken to load the script (milliseconds) */
      loadTime: number;
    };
  }

  /**
   * Optional execution callback function
   * Called when the content script is executed with performance metrics
   */
  interface ExecuteFn {
    (options: ExecuteFnOptions): void;
  }

  /**
   * Module exports interface for content scripts
   * Content scripts can export an onExecute function to receive execution callbacks
   */
  interface ModuleExports {
    /** Optional callback executed when the script runs */
    onExecute?: ExecuteFn;
  }
}

Usage Examples:

// In content script file (content.ts)
/// <reference types="@crxjs/vite-plugin/client" />

// Export execution callback to receive performance metrics
export const onExecute: ContentScriptAPI.ExecuteFn = (options) => {
  console.log(`Content script injected in ${options.perf.injectTime}ms`);
  console.log(`Content script loaded in ${options.perf.loadTime}ms`);
  
  // Initialize content script functionality
  initializeContentScript();
};

function initializeContentScript() {
  // Content script implementation
  console.log("Content script is running!");
  
  // Access to all standard web APIs
  document.addEventListener('DOMContentLoaded', () => {
    // DOM manipulation
  });
  
  // Chrome extension APIs (in isolated world)
  chrome.runtime.sendMessage({ type: 'content-script-ready' });
}

// Alternative: Direct execution without callback
console.log("Content script executing directly");

Client Module Declarations

Type definitions for client-side module imports and dynamic resources.

/**
 * Client code modules - used internally by CRXJS
 * Exports raw code as string for injection
 */
declare module 'client/*' {
  const code: string;
  export default code;
}

/**
 * Dynamic localhost modules for development
 * Supports Vite dev server integration
 */
declare module 'http://localhost:*/*' {
  const module: any;
  export = module;
}

/**
 * Dynamic path-based modules
 * Supports runtime module resolution
 */
declare module '*/%PATH%' {
  const module: any;
  export = module;
}

Script Format Comparison

?script (Default / Loader Format):

  • Use Case: Standard content scripts with full development features
  • Features: HMR, dynamic imports, framework support
  • Runtime: Uses loader script for dynamic injection
  • Best For: React, Vue, Svelte content scripts during development
import contentScript from "./react-content.tsx?script";

// Generates a loader that dynamically imports the actual content script
// Supports hot reloading and framework-specific HMR

?script&iife Format:

  • Use Case: Simple, isolated content scripts
  • Features: Self-contained, no external dependencies
  • Runtime: Direct execution, no loader needed
  • Best For: Simple content scripts, opaque origin environments
import contentScript from "./simple-content.ts?script&iife";

// Generates an IIFE that executes immediately
// No HMR support but guaranteed to work in all contexts

?script&module Format:

  • Use Case: Main world injection, no HMR needed
  • Features: Pure ES module, no wrapper code
  • Runtime: Direct ES module execution
  • Best For: Main world scripts, library integration
import mainWorldScript from "./page-script.ts?script&module";

chrome.scripting.executeScript({
  target: { tabId },
  files: [mainWorldScript],
  world: "MAIN", // Inject into page's main world
});

Development vs Production Behavior

Development Mode:

  • All script formats include HMR client code (except ?script&module)
  • Source maps are preserved for debugging
  • Verbose logging and error reporting
  • Live connection to Vite dev server

Production Mode:

  • HMR code is stripped from all formats
  • Scripts are minified and optimized
  • Source maps are optional (based on build config)
  • No development server dependencies

Advanced Client API Patterns

Multi-Script Coordination:

// Background script coordinating multiple content scripts
import mainScript from "./main-content.ts?script";
import helperScript from "./helper.ts?script&iife";

async function injectContentScripts(tabId: number) {
  // Inject helper script first (IIFE for immediate execution)
  await chrome.scripting.executeScript({
    target: { tabId },
    files: [helperScript],
  });
  
  // Then inject main script (with HMR and dependencies)
  await chrome.scripting.executeScript({
    target: { tabId },
    files: [mainScript],
  });
}

Conditional Script Loading:

// Load different scripts based on page context
import devScript from "./dev-content.ts?script";
import prodScript from "./prod-content.ts?script&iife";

const scriptToInject = process.env.NODE_ENV === 'development' 
  ? devScript 
  : prodScript;

chrome.scripting.executeScript({
  target: { tabId },
  files: [scriptToInject],
});

Performance Monitoring:

// Content script with performance tracking
export const onExecute: ContentScriptAPI.ExecuteFn = (options) => {
  // Track performance metrics
  const metrics = {
    injectTime: options.perf.injectTime,
    loadTime: options.perf.loadTime,
    startTime: Date.now(),
  };
  
  // Send metrics to background script
  chrome.runtime.sendMessage({
    type: 'performance-metrics',
    metrics,
  });
  
  // Continue with script initialization
  initializeScript();
};

TypeScript Integration

The client API provides full TypeScript support with strict type checking.

Type-Safe Content Scripts:

// Type-safe content script with proper interfaces
/// <reference types="@crxjs/vite-plugin/client" />

interface ContentScriptState {
  initialized: boolean;
  features: string[];
}

const state: ContentScriptState = {
  initialized: false,
  features: [],
};

export const onExecute: ContentScriptAPI.ExecuteFn = (options) => {
  // Type-safe access to performance metrics
  const { injectTime, loadTime } = options.perf;
  
  if (injectTime > 100) {
    console.warn(`Slow injection time: ${injectTime}ms`);
  }
  
  state.initialized = true;
  state.features.push('performance-monitoring');
};

Environment-Specific Types:

// Different types for different execution contexts
interface MainWorldAPI {
  // APIs available in main world
  pageFunction: () => void;
}

interface ContentScriptAPI {
  // APIs available in content script world
  chromeExtensionAPI: typeof chrome;
}

// Use appropriate types based on script format
import mainWorldScript from "./main.ts?script&module"; // MainWorldAPI
import contentScript from "./content.ts?script";        // ContentScriptAPI