Service Providers
Introduction
Service providers are essential when bootstrapping your application. The Supercharge framework uses service providers to load core functionalities and your application should use them as well.
You may ask what “bootstrapping” actually means? In the context of a Supercharge application, it means composing your application: registering services into the container, loading routes and binding controllers, loading events and binding listeners. Service providers are a central place for your application.
Supercharge looks for the bootstrap/providers.ts
file when starting your application. This file exports a providers
property storing the service providers that will be loaded when booting your application. By default, you’ll see a handful of providers listed. For example, you’ll find the route service provider required for HTTP routing listed in the array.
This page shows you how to write your own service provider and register it with your Supercharge app.
Creating Service Providers
All service providers should extends the ServiceProvider
class provided by @supercharge/support
. The main methods you can implement in your service provider are register
and boot
.
Here’s a MarkdownServiceProvider
that we’ll use as an example:
import { ServiceProvider } from '@supercharge/support'
import { MarkdownRenderer } from './markdown-renderer'
export class MarkdownServiceProvider extends ServiceProvider {
/**
* Register application services into the container.
*/
override register (): void {
this.app().singleton(MarkdownRenderer, () => {
return new MarkdownRenderer(this.app())
})
}
/**
* Boot application services.
*/
override async boot (): Promise<void> {
await this.app().make(MarkdownRenderer).boot()
}
}
The following sections look at the register
and boot
methods in more detail.
The Register Method
The register
method should bind services into the service container. The register
method runs synchronously and doesn’t support promises. Remember, you should only register services and their dependencies here:
Notice: you have access to the app
instance in your service providers via the this.app()
method. Also, you must manually resolve other dependencies from the container if your service needs them.
Here’s an example registering the markdown renderer into the container and providing a factory callback returning a resolved (not booted) instance:
import { ServiceProvider } from '@supercharge/support'
import { MarkdownRenderer } from './markdown-renderer'
export class MarkdownServiceProvider extends ServiceProvider {
/**
* Register application services into the container.
*/
override register (): void {
this.app().singleton(MarkdownRenderer, () => {
return new MarkdownRenderer(
this.app().config().get('markdown')
)
})
}
}
The register
method binds an implementation of the MarkdownRenderer
into the container. Please find more details about the container and bindings in its documentation.
The Boot Method
The boot
method is called after all service providers have been registered. Here, you have access to all services in the container. The boot
method runs asynchronously and can return a promise. Use this method to boot your application services.
For example, let’s say the markdown renderer needs to load a syntax highlighting theme file from the local hard drive. The boot method is the correct place to load this file asynchronously.
import { ServiceProvider } from '@supercharge/support'
import { MarkdownRenderer } from './markdown-renderer'
export class MarkdownServiceProvider extends ServiceProvider {
/**
* Boot application services.
*/
override async boot (): Promise<void> {
await this.app().make(MarkdownRenderer).boot()
}
}
Registering Providers
All service providers are registered through the bootstrap/providers.ts
file. This file must export a providers
property. The value of this property is an array of service providers. You’ll find a handful of default service providers, for example the route service provider.
Add service providers from community packages or your own modules to this list:
import { MarkdownServiceProvider } from '../app/modules/markdown'
export const providers: ServiceProviderCtor[] = [
// other service providers
MarkdownServiceProvider,
]