jarle / remix-starter-kit

Starter kit for building Remix apps with AdonisJS 6
5 stars 0 forks source link

Support for instantiated services #35

Closed rustworthy closed 3 months ago

rustworthy commented 3 months ago

Hello @jarle! Thanks again for the adapter and the starter kit - it's a pleasure to work with.

I am currently having a case where I need to instantiate a service doing an async operation internally. So I am making use of a top-level await like so:

// '#services/example_service'
class ExampleService {
  static async connect(url?: string) {
    /* make a network request */
    return new ExampleService()
  }
}

export default await ExampleService.connect() // export an  already instantiated and connected client

Apparently, I cannot simply register this service in ServiceProviders in '#services/_index.ts' , since the default export is not a class that the container resolver will know to create a singleton of.

I guess, there are numerous ways out. I am currently just registering this service (instance of service) separately in the service_provider.ts module with:

import instantiatedExampleService from '#services/example_service'

export default class ServiceProvider {
 ...
  register() {
    Object.entries(ServiceProviders).forEach(([serviceName, creator]) => {
      this.app.container.singleton(serviceName as any, async (resolver) => {
        const constructor = await creator()
        return resolver.make(constructor.default)
      })
    })
    this.app.container.singleton('example_service' as any, () => instantiatedExampleService)
  }
  ...
}

What this gives me is I can use this client anywhere in the app knowing that it has already connected to a peer.

But I am looking at my implementation and well I am pretty sure there should be a more elegant way out.

Do you think this is something that the starter kit could support?

jarle commented 3 months ago

That's a very good suggestion :) I have updated the starter kit so that the service resolver is a bit more flexible: https://github.com/jarle/remix-starter-kit/blob/60eabc17b99ea7cc0ca175e30cd6891bc93bb770/providers/service_provider.ts

You can provide your function as the default export, or provide the function through the class export like this:

  hello_service: () => import('./hello_service.js').then(m => m.default.connect),

This approach should also work:

  hello_service: () => {
    return HelloService.connect()
  },
rustworthy commented 3 months ago

I swapped the service_provider.ts in my project with the current implementation in this repo, and added my service along side other services - and it just works! Thanks a lot!