Creating Custom Integrations
Integrations in Ecopages add support for new templating engines or frameworks. This guide will show you how to create your own integration.
Basic Structure
An integration extends the IntegrationPlugin
abstract class:
import { IntegrationPlugin } from '@ecopages/core/plugins/integration-plugin';
import type { IntegrationRenderer } from '@ecopages/core/route-renderer/integration-renderer';
class CustomIntegration extends IntegrationPlugin {
constructor() {
super({
name: 'custom-integration',
extensions: ['.custom'], // File extensions to handle
});
}
createRenderer(): IntegrationRenderer {
return new CustomRenderer({
appConfig: this.appConfig!,
});
}
}
Creating a Custom Renderer
The renderer handles the actual transformation of your templates:
class CustomRenderer extends IntegrationRenderer {
name = 'custom-renderer';
async render(options: IntegrationRendererRenderOptions): Promise<RouteRendererBody> {
const { Page, props, metadata, HtmlTemplate } = options;
// Transform the page content
const pageContent = await this.renderPage(Page, props);
// Render the final HTML using the template
return HtmlTemplate({
children: pageContent,
metadata,
});
}
private async renderPage(Page: EcoComponent, props: any): Promise<string> {
// Implement your rendering logic here
return '';
}
}
Handling Dependencies
Manage assets and dependencies for your integration:
class CustomIntegration extends IntegrationPlugin {
constructor() {
super({
name: 'custom-integration',
extensions: ['.custom'],
dependencies: [
{
kind: 'script',
importPath: './runtime.js',
position: 'head',
},
{
kind: 'stylesheet',
importPath: './styles.css',
},
],
});
}
}
Setup and Teardown
Handle initialization and cleanup:
class CustomIntegration extends IntegrationPlugin {
async setup(): Promise<void> {
// Initialize resources
// Register dependencies
// Set up compilation
}
async teardown(): Promise<void> {
// Clean up resources
}
}
Using the Integration
Register your integration in the Ecopages configuration:
import { ConfigBuilder } from '@ecopages/core';
const customIntegration = new CustomIntegration();
const config = await new ConfigBuilder()
.setIntegrations([customIntegration])
.build();
Best Practices
- Follow the Single Responsibility Principle
- Handle errors gracefully
- Provide clear documentation
- Use TypeScript for type safety
- Test your integration thoroughly
- Manage dependencies efficiently
Example: Complete Integration
Here's a complete example of a custom integration:
import { IntegrationPlugin } from '@ecopages/core/plugins/integration-plugin';
import type { IntegrationRenderer } from '@ecopages/core/route-renderer/integration-renderer';
import type {
EcoComponent,
RouteRendererBody,
IntegrationRendererRenderOptions
} from '@ecopages/core/public-types';
class CustomRenderer extends IntegrationRenderer {
name = 'custom-renderer';
async render(options: IntegrationRendererRenderOptions): Promise<RouteRendererBody> {
const { Page, props, metadata, HtmlTemplate } = options;
// Transform the page
const pageContent = await this.renderPage(Page, props);
// Return the complete HTML
return HtmlTemplate({
children: pageContent,
metadata,
dependencies: {
scripts: ['./runtime.js'],
stylesheets: ['./styles.css'],
},
});
}
private async renderPage(Page: EcoComponent, props: any): Promise<string> {
return Page(props);
}
}
export class CustomIntegration extends IntegrationPlugin {
constructor() {
super({
name: 'custom-integration',
extensions: ['.custom'],
});
}
createRenderer(): IntegrationRenderer {
return new CustomRenderer({
appConfig: this.appConfig!,
});
}
async setup(): Promise<void> {
// Setup logic
}
async teardown(): Promise<void> {
// Cleanup logic
}
}