or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

amd-loading.mdbuild-system.mdcommand-line.mdconfiguration.mderror-handling.mdindex.mdplugin-system.md
tile.json

plugin-system.mddocs/

Plugin System

RequireJS extensible plugin system for loading non-JavaScript resources and custom module types. Plugins enable loading text files, CSS, images, and other resources through the module system.

Capabilities

Plugin Loading

Load resources using plugin syntax with exclamation mark notation.

// Plugin loading syntax
require(['pluginName!resourcePath'], function(resource) {
  // Use loaded resource
});

// Common plugin patterns
require(['text!template.html'], function(template) {
  // template contains file contents as string
});

require(['css!styles.css'], function() {
  // CSS loaded and applied to page
});

require(['json!data.json'], function(data) {
  // JSON parsed and returned as object
});

Usage Examples:

// Load HTML template
require(['text!templates/user.html'], function(userTemplate) {
  document.getElementById('content').innerHTML = userTemplate;
});

// Load CSS stylesheet
require(['css!themes/dark.css'], function() {
  console.log('Dark theme loaded');
});

// Load JSON configuration
require(['json!config/settings.json'], function(settings) {
  console.log('API URL:', settings.apiUrl);
  console.log('Timeout:', settings.timeout);
});

// Multiple plugin resources
require([
  'text!templates/header.html',
  'text!templates/footer.html', 
  'css!styles/layout.css'
], function(headerTmpl, footerTmpl) {
  renderPage(headerTmpl, footerTmpl);
});

Plugin Definition API

Create custom plugins to handle specific resource types.

/**
 * Plugin definition interface
 */
interface RequirePlugin {
  /** Load and process a resource */
  load(name: string, req: LocalRequire, onload: (value: any) => void, config: any): void;
  
  /** Normalize resource names */
  normalize?(name: string, normalize: (name: string) => string): string;
  
  /** Build-time resource processing */
  write?(pluginName: string, moduleName: string, write: WriteAPI): void;
  
  /** Alternative build-time processing */
  writeFile?(pluginName: string, name: string, req: LocalRequire, write: WriteFileAPI, config: any): void;
  
  /** Plugin initialization */
  pluginBuilder?: string;
}

/**
 * Load function parameters
 */
interface LoadParameters {
  /** Resource name after normalization */
  name: string;
  
  /** Local require function */
  req: LocalRequire;
  
  /** Success callback */
  onload: (value: any) => void;
  
  /** RequireJS configuration */
  config: any;
}

interface LocalRequire {
  (moduleId: string): any;
  toUrl(moduleNamePlusExt: string): string;
}

Usage Examples:

// Simple text loader plugin
define('text', [], function() {
  return {
    load: function(name, req, onload, config) {
      var url = req.toUrl(name);
      var xhr = new XMLHttpRequest();
      
      xhr.open('GET', url, true);
      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            onload(xhr.responseText);
          } else {
            onload.error(new Error('Failed to load: ' + url));
          }
        }
      };
      xhr.send();
    }
  };
});

// JSON loader plugin
define('json', [], function() {
  return {
    load: function(name, req, onload, config) {
      var url = req.toUrl(name + '.json');
      var xhr = new XMLHttpRequest();
      
      xhr.open('GET', url, true);
      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            try {
              var data = JSON.parse(xhr.responseText);
              onload(data);
            } catch (e) {
              onload.error(e);
            }
          } else {
            onload.error(new Error('HTTP ' + xhr.status + ': ' + url));
          }
        }
      };
      xhr.send();
    }
  };
});

// Image loader plugin
define('image', [], function() {
  return {
    load: function(name, req, onload, config) {
      var url = req.toUrl(name);
      var img = new Image();
      
      img.onload = function() {
        onload(img);
      };
      
      img.onerror = function() {
        onload.error(new Error('Failed to load image: ' + url));
      };
      
      img.src = url;
    }
  };
});

Resource Normalization

Normalize resource names and handle relative paths.

/**
 * Normalize function for plugins
 */
interface NormalizeFunction {
  /** 
   * Normalize resource name
   * @param name - Resource name to normalize
   * @param normalize - Function to normalize module names
   * @returns Normalized resource name
   */
  normalize(name: string, normalize: (name: string) => string): string;
}

Usage Examples:

// Plugin with normalization
define('template', [], function() {
  return {
    normalize: function(name, normalize) {
      // Add .html extension if missing
      if (!/\.html$/.test(name)) {
        name += '.html';
      }
      
      // Handle relative paths
      return normalize(name);
    },
    
    load: function(name, req, onload, config) {
      // name is already normalized
      var url = req.toUrl(name);
      // Load logic...
    }
  };
});

// Usage with normalization
require(['template!user'], function(template) {
  // Loads 'user.html' template
});

require(['template!../shared/header'], function(template) {
  // Resolves relative path and loads 'header.html'
});

Build-Time Plugin Processing

Handle plugin resources during build optimization.

/**
 * Build-time processing interfaces
 */
interface WriteAPI {
  /** Write module as AMD module */
  asModule(moduleName: string, contents: string): void;
  
  /** Write raw contents */
  (contents: string): void;
}

interface WriteFileAPI {
  /** Write file to build output */
  (filename: string, contents: string): void;
}

/**
 * Build configuration for plugins
 */
interface PluginBuildConfig {
  /** Stub out plugin calls in built code */
  stubModules?: string[];
  
  /** Optimize all plugin resources */
  optimizeAllPluginResources?: boolean;
  
  /** Inline plugin resources */
  inlineText?: boolean;
}

Usage Examples:

// Plugin with build support
define('template', [], function() {
  return {
    load: function(name, req, onload, config) {
      // Runtime loading
      var url = req.toUrl(name + '.html');
      // ... xhr loading logic
    },
    
    write: function(pluginName, moduleName, write) {
      // Build-time processing
      write.asModule(moduleName, 
        'define("' + moduleName + '", function() {\n' +
        '  return ' + JSON.stringify(template) + ';\n' +
        '});'
      );
    }
  };
});

// CSS plugin with build processing
define('css', [], function() {
  return {
    load: function(name, req, onload, config) {
      var url = req.toUrl(name + '.css');
      var link = document.createElement('link');
      link.rel = 'stylesheet';
      link.href = url;
      document.head.appendChild(link);
      onload();
    },
    
    writeFile: function(pluginName, name, req, write, config) {
      // Read CSS file and write to build
      var cssContent = req.toUrl(name + '.css');
      write('css/' + name + '.css', cssContent);
    }
  };
});

// Build configuration
({
  baseUrl: 'src',
  name: 'main',
  out: 'built.js',
  
  // Preserve text plugin calls
  stubModules: ['text'],
  
  // Inline text resources
  inlineText: true,
  
  // Optimize plugin resources
  optimizeAllPluginResources: true
})

Common Built-in Plugins

RequireJS ecosystem plugins for common resource types.

// Text plugin (requirejs-text)
require(['text!template.html'], function(html) {
  // HTML content as string
});

// CSS plugin (require-css)
require(['css!stylesheet.css'], function() {
  // CSS loaded and applied
});

// Domready plugin (requirejs-domready) 
require(['domReady!'], function(doc) {
  // DOM is ready
});

// Order plugin (requirejs-order)
require(['order!lib1.js', 'order!lib2.js'], function() {
  // Scripts loaded in order
});

// Font plugin (requirejs-font)
require(['font!OpenSans'], function() {
  // Web font loaded
});

Usage Examples:

// Complex plugin combination
require([
  'domReady!',
  'text!templates/app.html',
  'css!styles/app.css',
  'json!config/settings.json'
], function(doc, appTemplate, settings) {
  // DOM ready, template loaded, CSS applied, settings loaded
  initializeApp(doc, appTemplate, settings);
});

// Conditional plugin loading
require(['has!webgl?webgl-plugin!shaders/vertex.glsl:canvas2d-plugin!sprites.json'], 
  function(resource) {
    // Loads different resources based on feature detection
  }
);

// Plugin chaining
require(['text!markdown!content/article.md'], function(html) {
  // Markdown processed to HTML
});

Plugin Error Handling

Handle plugin loading failures and errors.

/**
 * Plugin error handling
 */
interface PluginErrorHandling {
  /** Error callback for plugin loading */
  onload.error(error: Error): void;
  
  /** Plugin-specific error types */
  errors: {
    network: "Network error loading resource";
    parse: "Error parsing resource content";  
    notfound: "Resource not found";
    timeout: "Resource loading timeout";
  };
}

Usage Examples:

// Plugin with error handling
define('data', [], function() {
  return {
    load: function(name, req, onload, config) {
      var url = req.toUrl(name + '.json');
      var xhr = new XMLHttpRequest();
      var timeout = config.dataTimeout || 5000;
      
      var timeoutId = setTimeout(function() {
        xhr.abort();
        onload.error(new Error('Timeout loading: ' + url));
      }, timeout);
      
      xhr.open('GET', url, true);
      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
          clearTimeout(timeoutId);
          
          if (xhr.status === 200) {
            try {
              onload(JSON.parse(xhr.responseText));
            } catch (e) {
              onload.error(new Error('Parse error: ' + e.message));
            }
          } else if (xhr.status === 404) {
            onload.error(new Error('Resource not found: ' + url));
          } else {
            onload.error(new Error('HTTP ' + xhr.status + ': ' + url));
          }
        }
      };
      
      xhr.onerror = function() {
        clearTimeout(timeoutId);
        onload.error(new Error('Network error loading: ' + url));
      };
      
      xhr.send();
    }
  };
});

// Using plugin with error handling
require(['data!config'], 
  function(config) {
    console.log('Config loaded:', config);
  },
  function(err) {
    console.error('Failed to load config:', err.message);
    // Use default configuration
    useDefaultConfig();
  }
);

Types

// Plugin system types
interface PluginRegistry {
  [pluginName: string]: RequirePlugin;
}

interface PluginContext {
  config: any;
  req: LocalRequire;
  defined: { [key: string]: any };
  waiting: { [key: string]: boolean };
}

interface PluginLoadEvent {
  pluginName: string;
  resourceName: string;
  url: string;
  startTime: number;
  endTime?: number;
  error?: Error;
}

// Build-time plugin types
interface PluginBuildContext {
  optimize: string;
  inlineText: boolean;
  stubModules: string[];
  config: any;
}

interface PluginResource {
  pluginName: string;
  resourceName: string;
  content: string;
  url: string;
  buildPath?: string;
}