definePlugin API

The definePlugin function is the entry point for extending Coralite's functionality. It allows you to inject server-side logic, register custom templates, and most importantly, bundle and configure client-side scripts that can be used by your components.

Configuration Options #

The definePlugin function accepts a configuration object with the following options:

JavaScript
Code copied!
  import { definePlugin } from 'coralite'
  
  const myPlugin = definePlugin({
    name: 'my-plugin', // Required: Unique name for the plugin
  
    // Optional: Server-side logic
    server: {
      // Two-Phase Curried functions for component data() blocks
      exports: {
        log: (context) => (message) => {
          console.log(`[${context.id}] ${message}`, context.state)
        }
      },
      // Register custom components
      components: ['./path/to/component-name.html'],
      // Server-side lifecycle hooks
      onPageSet: async (data) => { /* ... */ },
      onBeforeComponentRender: ({ state, session }) => { /* ... */ }
    },
  
    // Optional: Client-side logic
    client: {
      config: { /* static configuration */ },
      context: {
        // Two-Phase Curried utilities for script context
        myHelper: (globalContext) => (localContext) => () => {
          return 'hello'
        }
      }
    }
  })
Context Binding (`server.exports`) #

The server.exports property is an object of functions that processes content using plugin logic during the server-side build process. These functions are available to component data() blocks.

These functions use a Two-Phase Currying pattern to receive the globalContext and config explicitly.

JavaScript
Code copied!
  export default definePlugin({
    name: 'logger-plugin',
    server: {
      config: { prefix: 'LOG' },
      exports: {
        log: (globalContext, config) => (instanceContext) => (message) => {
          // Phase 1: Receive globalContext and config
          // Phase 2: Receive instanceContext (app, session, state, page, etc.)
          // Phase 3: Receive arguments from component data() block
          console.log(`[${config.prefix}] [${instanceContext.id}] ${message}`, instanceContext.state);
          
          // Returning a state patch to be merged into component state
          return { logged: true };
        }
      }
    }
  })
Server-Side Hooks #

Plugins can hook into Coralite's build lifecycle within the server block. All hooks support asynchronous operations. All hooks receive the shared globalContext (as properties) and the plugin's config in their context object.

Client-Side Scripting #

The client property is powerful: it allows you to inject code that runs in the browser. This code is bundled with your application.

client.context #

Define utilities that will be flattened directly onto the context object in defineComponent scripts in the browser.

JavaScript
Code copied!
  definePlugin({
    name: 'utils',
    client: {
      context: {
        formatDate: (globalContext, config) => (instanceContext) => (date) => {
          return new Date(date).toLocaleDateString()
        }
      }
    }
  })

Note: Context utilities must use the Two-Phase Currying System.

Client Configuration #

The client.config object allows you to pass static configuration data from the server (where the plugin is defined) to the client. This is useful for API keys, theme settings, or feature flags.

JavaScript
Code copied!
  definePlugin({
    name: 'analytics',
    client: {
      config: {
        trackingId: 'UA-123456-7',
        debug: true
      },
      // ...
    }
  })
Context Injection #

The client.config is automatically passed as the second argument to your context factories. Additionally, you can mutate globalContext in Phase 1 to expose services to downstream plugins.

JavaScript
Code copied!
  // Inside client.context
  context: {
    trackEvent: (globalContext, config) => {
      const { trackingId } = config;
      
      // ✨ EXPOSE TO DOWNSTREAM PLUGINS
      globalContext.analyticsReady = true;
  
      return (localContext) => async (eventName) => {
        const { default: analyticsLib } = await import('analytics-lib')
        analyticsLib.send(trackingId, eventName)
      }
    }
  }
Complete Example: Confetti Plugin #

Let's build a plugin that triggers a confetti explosion using a remote library and allows configuration of particle count.

JavaScript
Code copied!
  import { definePlugin } from 'coralite'
  
  export default definePlugin({
    name: 'confetti-plugin',
    client: {
      // Define configuration
      config: {
        particleCount: 100,
        spread: 70
      },
  
      // Create the context utility
      context: {
        explode: (globalContext, config) => (localContext) => async () => {
          // Dynamically import the library (auto-bundled by AST)
          const { default: confetti } = await import('https://esm.sh/canvas-confetti@1.6.0')
  
          // Use the library with the config
          confetti({
            particleCount: config.particleCount,
            spread: config.spread,
            origin: { y: 0.6 }
          })
        }
      }
    }
  })

Usage in a component:

HTML
Code copied!
<template id="celebration-button">
  <button ref="btn">Celebrate!</button>
</template>

<script type="module">  
  import { defineComponent } from 'coralite'
  
  export default defineComponent({
    script: ({ state, signal, refs }) => {
      const btn = refs('btn')
  
      btn.addEventListener('click', () => {
        explode()
      })
    }
  })
</script>

Start Building with Coralite!

Use the scaffolding script to get jump started into your next project with Coralite

Copied commandline!