LogoLogo
HomeDiscourseBlogDiscord
  • Introduction
  • Introduction
    • Quick start
    • Aurelia for new developers
    • Hello world
      • Creating your first app
      • Your first component - part 1: the view model
      • Your first component - part 2: the view
      • Running our app
      • Next steps
  • Templates
    • Template Syntax
      • Attribute binding
      • Event binding
      • Text interpolation
      • Template promises
      • Template references
      • Template variables
      • Globals
    • Custom attributes
    • Value converters (pipes)
    • Binding behaviors
    • Form Inputs
    • CSS classes and styling
    • Conditional Rendering
    • List Rendering
    • Lambda Expressions
    • Local templates (inline templates)
    • SVG
  • Components
    • Component basics
    • Component lifecycles
    • Bindable properties
    • Styling components
    • Slotted content
    • Scope and context
    • CustomElement API
    • Template compilation
      • processContent
      • Extending templating syntax
      • Modifying template parsing with AttributePattern
      • Extending binding language
      • Using the template compiler
      • Attribute mapping
  • Getting to know Aurelia
    • Routing
      • @aurelia/router
        • Getting Started
        • Creating Routes
        • Routing Lifecycle
        • Viewports
        • Navigating
        • Route hooks
        • Router animation
        • Route Events
        • Router Tutorial
        • Router Recipes
      • @aurelia/router-lite
        • Getting started
        • Router configuration
        • Configuring routes
        • Viewports
        • Navigating
        • Lifecycle hooks
        • Router hooks
        • Router events
        • Navigation model
        • Transition plan
    • App configuration and startup
    • Enhance
    • Template controllers
    • Understanding synchronous binding
    • Dynamic composition
    • Portalling elements
    • Observation
      • Observing property changes with @observable
      • Effect observation
      • HTML observation
      • Using observerLocator
    • Watching data
    • Dependency injection (DI)
    • App Tasks
    • Task Queue
    • Event Aggregator
  • Developer Guides
    • Animation
    • Testing
      • Overview
      • Testing attributes
      • Testing components
      • Testing value converters
      • Working with the fluent API
      • Stubs, mocks & spies
    • Logging
    • Building plugins
    • Web Components
    • UI virtualization
    • Errors
      • 0001 to 0023
      • 0088 to 0723
      • 0901 to 0908
    • Bundlers
    • Recipes
      • Apollo GraphQL integration
      • Auth0 integration
      • Containerizing Aurelia apps with Docker
      • Cordova/Phonegap integration
      • CSS-in-JS with Emotion
      • DOM style injection
      • Firebase integration
      • Markdown integration
      • Multi root
      • Progress Web Apps (PWA's)
      • Securing an app
      • SignalR integration
      • Strongly-typed templates
      • TailwindCSS integration
      • WebSockets Integration
      • Web Workers Integration
    • Playground
      • Binding & Templating
      • Custom Attributes
        • Binding to Element Size
      • Integration
        • Microsoft FAST
        • Ionic
    • Migrating to Aurelia 2
      • For plugin authors
      • Side-by-side comparison
    • Cheat Sheet
  • Aurelia Packages
    • Validation
      • Validation Tutorial
      • Plugin Configuration
      • Defining & Customizing Rules
      • Architecture
      • Tagging Rules
      • Model Based Validation
      • Validation Controller
      • Validate Binding Behavior
      • Displaying Errors
      • I18n Internationalization
      • Migration Guide & Breaking Changes
    • i18n Internationalization
    • Fetch Client
      • Overview
      • Setup and Configuration
      • Response types
      • Working with forms
      • Intercepting responses & requests
      • Advanced
    • Event Aggregator
    • State
    • Store
      • Configuration and Setup
      • Middleware
    • Dialog
  • Tutorials
    • Building a ChatGPT inspired app
    • Building a realtime cryptocurrency price tracker
    • Building a todo application
    • Building a weather application
    • Building a widget-based dashboard
    • React inside Aurelia
    • Svelte inside Aurelia
    • Synthetic view
    • Vue inside Aurelia
  • Community Contribution
    • Joining the community
    • Code of conduct
    • Contributor guide
    • Building and testing aurelia
    • Writing documentation
    • Translating documentation
Powered by GitBook
On this page
  • Minimal Plugin Example
  • What a Plugin Is
  • Simple Plugin Setup
  • Integrating the Plugin into Your Application
  • Adding Components
  • Creating a Configurable Plugin
  • Define Configuration Interface
  • Implement Configuration in Plugin
  • Using the Configurable Plugin
  • Accessing Configuration in a Component
  • Best Practices
  • Advanced Features
  • Advanced Configuration Management
  • Plugin Lifecycle Management
  • Mono-Repository Structure

Was this helpful?

Export as PDF
  1. Developer Guides

Building plugins

Aurelia makes it easy to create your plugins. Learn how to create individual plugins, register them, and work with tasks to run code during certain parts of the lifecycle process.

Aurelia plugins allow you to encapsulate functionality that can be reused across multiple applications. They can include custom elements, value converters, and other resources. The goal is to create packaged, easily shared, ready-to-use functionalities that integrate seamlessly with Aurelia applications.

Minimal Plugin Example

What a Plugin Is

At its core, a plugin in Aurelia is an object with a register method that configures dependencies and sets up your component or functionality for use in an Aurelia application.

Simple Plugin Setup

// my-simple-plugin.ts
import { IContainer } from '@aurelia/kernel';

export const MySimplePlugin = {
  register(container: IContainer): void {
    // Register your plugin resources here
  }
};

Integrating the Plugin into Your Application

// main.ts
import Aurelia from 'aurelia';
import { MySimplePlugin } from './my-simple-plugin';

Aurelia
  .register(MySimplePlugin)
  .app(MyApp)
  .start();

Adding Components

You often want to add custom components to make your plugin more useful.

import { customElement } from '@aurelia/runtime-html';

@customElement({
  name: 'hello-world',
  template: '<div>Hello, ${name}!</div>'
})
export class HelloWorld {
  name = 'World';
}
// my-component-plugin.ts
import { IContainer } from '@aurelia/kernel';
import { HelloWorld } from './hello-world';

export const MyComponentPlugin = {
  register(container: IContainer): void {
    container.register(HelloWorld);
  }
};

Creating a Configurable Plugin

Define Configuration Interface

// plugin-configuration.ts
export interface MyPluginOptions {
  greeting?: string;
  debug?: boolean;
}

const defaultOptions: MyPluginOptions = {
  greeting: 'Hello',
  debug: false
};

Implement Configuration in Plugin

export interface MyPluginOptions {
  greeting?: string;
  debug?: boolean;
}

const defaultOptions: MyPluginOptions = {
  greeting: 'Hello', // default greeting
  debug: false       // default debug setting
};
// my-configurable-plugin.ts
import { DI, IContainer, Registration } from '@aurelia/kernel';

export const IMyPluginOptions = DI.createInterface<MyPluginOptions>('IMyPluginOptions');

export const MyConfigurablePlugin = {
  configure(options: Partial<MyPluginOptions> = {}) {
    const finalOptions = { ...defaultOptions, ...options }; // Merge with defaults

    return {
      register(container: IContainer): void {
        container.register(
          Registration.instance(IMyPluginOptions, finalOptions) // Register configuration
        );
      }
    };
  }
};

Using the Configurable Plugin

// main.ts
import Aurelia from 'aurelia';
import { MyConfigurablePlugin } from './my-configurable-plugin';

Aurelia
  .register(
    MyConfigurablePlugin.configure({
      greeting: 'Bonjour',
      debug: true
    })
  )
  .app(MyApp)
  .start();

Accessing Configuration in a Component

// greeting.ts
import { customElement } from '@aurelia/runtime-html';
import { resolve } from 'aurelia';
import { IMyPluginOptions } from './my-configurable-plugin';

@customElement({
  name: 'greeting',
  template: '<div>${options.greeting}, ${name}!</div>'
})
export class Greeting {
  name = 'World';

  private options = resolve(IMyPluginOptions); // Resolve the dependency
}

Best Practices

  • Use Clear Naming Conventions: Prefix your plugin resources with your plugin name to avoid naming collisions.

  • Provide Sensible Defaults: Always have sensible default values when adding configuration options.

  • Document Plugin Usage: Write clear documentation on how to use your plugin and its configurations.

Advanced Features

Once you’ve mastered the basics of creating plugins, you may find that your needs evolve to require more complex functionality. This section covers advanced features in plugin development, such as advanced configuration management, lifecycle tasks, and mono-repository structures.

Advanced Configuration Management

When your plugin settings are more intricate, consider adding more comprehensive configuration handling:

Dynamic Configuration

Plugins can adjust settings dynamically based on user input or environment conditions.

// dynamic-configuration-plugin.ts
import { DI, IContainer, Registration } from '@aurelia/kernel';

export interface DynamicPluginOptions {
  mode: 'development' | 'production';
}

export const IDynamicPluginOptions = DI.createInterface<DynamicPluginOptions>('IDynamicPluginOptions');

export const DynamicPlugin = {
  configure(options: Partial<DynamicPluginOptions> = {}) {
    const environment = process.env.NODE_ENV || 'development';
    const finalOptions: DynamicPluginOptions = { 
      mode: environment, 
      ...options 
    };

    return {
      register(container: IContainer): void {
        container.register(
          Registration.instance(IDynamicPluginOptions, finalOptions)
        );
      }
    };
  }
};

// Usage
Aurelia
  .register(
    DynamicPlugin.configure({
      mode: 'production'
    })
  )
  .app(MyApp)
  .start();

Plugin Lifecycle Management

Aurelia provides lifecycle hooks that you can hook into within your plugins to perform operations at specific times during the app’s startup process.

Using Lifecycle Tasks

import { IContainer, AppTask } from '@aurelia/kernel';

const MyLifecyclePlugin = {
  register(container: IContainer): void {
    // Add tasks to run before or after different app stages
    container.register(
      AppTask.beforeStart(IContainer, () => {
        console.log('Plugin is initializing...');
      }),
      AppTask.afterStart(IContainer, () => {
        console.log('Plugin has finished initializing.');
      })
    );
  }
};

This approach is beneficial when your plugin needs to load data, configure services, or perform actions that require awareness of the application’s runtime state.

Mono-Repository Structure

Maintaining individual repositories may become cumbersome for larger projects with multiple interrelated plugins. A mono-repository can simplify this by organizing multiple packages in a single repository.

Setting Up a Mono-Repository

  1. Directory Structure

    my-mono-repo/
    ├── packages/
    │   ├── my-plugin-a/
    │   │   ├── src/
    │   │   ├── package.json
    │   │   └── ...
    │   ├── my-plugin-b/
    │   │   ├── src/
    │   │   ├── package.json
    │   │   └── ...
    └── package.json
  2. Top-level package.json Setup

    {
      "private": true,
      "workspaces": [
        "packages/*"
      ]
    }
  3. Link Dependencies Use tools like lerna or native npm workspaces (npm install -g lerna).

    Initialize the repository:

    lerna init

    This setup helps maintain consistency, allows for easier inter-package dependencies, and simplifies testing across multiple plugins.

PreviousLoggingNextWeb Components

Last updated 3 months ago

Was this helpful?