Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proxy-service: Possible to have services depend on other services? #89

Open
EDjur opened this issue Jan 30, 2025 · 4 comments
Open

proxy-service: Possible to have services depend on other services? #89

EDjur opened this issue Jan 30, 2025 · 4 comments

Comments

@EDjur
Copy link

EDjur commented Jan 30, 2025

Hey!

I just started using this and loving it so far - nice job! 🙌

I was wondering if it's possible to have services depend on other services? E.g. the following case

apiService.ts

export class ApiService {
    #client: GraphQLClient;

    constructor(client: GraphQLClient) {
        this.#client= client;
    }
}

export const [registerApiService, getApiService] = defineProxyService(
    'ApiService',
    (client: GraphQLClient) => new ApiService(client)
);

serviceA.ts

export class ServiceA {
    #api: ApiService;

    constructor(api: ApiService) {
        this.#api = api;
    }
}

export const [registerServiceA, getServiceA] = defineProxyService(
    'ServiceA',
    (api: ApiService) => new ServiceA(api)
);

background.ts

const client = new GraphQLClient();

registerApiService(client);
registerAssetService(getApiService());

export default defineBackground(() => {
    ...
})

I tried the above pattern but get an error message when starting the dev server:

Browser.runtime.getManifest not implemented

Mock the function yourself using your testing framework, or submit a PR with an in-memory implementation.
...

I can get around it by lazily instantiating ServiceA and set the api inside defineBackground. But the above approach seems cleaner so maybe I'm missing something.

Thank you!

@EDjur
Copy link
Author

EDjur commented Jan 30, 2025

Adding that this isn't really a requirement for me. My use case is likely small enough right now that I can just use a single service. But I got curious hence the question :)

@aklinker1
Copy link
Owner

aklinker1 commented Jan 30, 2025

To fix the air you're seeing, move your registration inside the background function

export default defineBackground(() => {
  registerApiService(client);
  registerAssetService(getApiService());
})

To answer your main question, yes! Your code should work just fine.

You could also use the return value from the previous register call instead of calling the getter:

export default defineBackground(() => {
  const apiService = registerApiService(client);
  registerAssetService(apiService);
})

This is how I prefer to build my dependency tree, that way you don't accidentally try and use a service before it's registered.

The final option would be to use the getter inside your service, instead of passing an argument:

export class ServiceA {
  #api: ApiService;
  constructor() {
    this.#api = getApiService();
  }
}

But this has the same problem of potentially trying to get a service before it's registered. So I still prefer using the return value of the register function.

@EDjur
Copy link
Author

EDjur commented Jan 30, 2025

Ah, nice. Thank you for the swift reply!

I think I must've misunderstood these lines in the docs

You need to call register synchronously at the top level of the background script to avoid race conditions between registering and accessing the service for the first time.

@aklinker1
Copy link
Owner

aklinker1 commented Jan 30, 2025

Yeah, I should change that to "at the beginning" instead of "top level". That conflicts with how WXT expects your background to look.

Edit: Done: 684feda

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants