DEV Community

Fahad Heylaal
Fahad Heylaal

Posted on

Dependency Injection with FrintJS

This article was first published on Medium.

frintjs-dependency-injection

For those who do not know yet, FrintJS is an environment agnostic framework for building scalable reactive applications supporting both React and Vue.js.

Since the v1 release in early 2017, the core of the FrintJS framework has been mostly responsible for handling dependencies in your Apps. While other packages are mostly built around the core frint package’s API.

Providers

We have a terminology for dependencies in your FrintJS apps. We call them providers. Providers are any value that you can define in your FrintJS App, which can later be obtained by their unique names.

Creating a FrintJS app is as simple as:

import { createApp } from 'frint';

const MyApp = createApp({
  name: 'MyAppName',
});
Enter fullscreen mode Exit fullscreen mode

Below we will show you how providers can be defined in your App in three different ways.

You will find some similarities with Angular 2+, that’s because frint uses a fork of diyai, which is a port of the Angular’s Injector API built in a way to be used without needing TypeScript

Known values

If you already know the value of your provider, you can use the useValue property like this:

import { createApp } from 'frint';

const MyApp = createApp({
  name: 'MyAppName',
  providers: [
    {
      name: 'foo',
      useValue: 'foo value here',
    },
  ],
});
Enter fullscreen mode Exit fullscreen mode

Now once you instantiate your App, you can get the foo value as follows:

const app = new MyApp();

const foo = app.get('foo'); // `foo value here`
Enter fullscreen mode Exit fullscreen mode

Generated values

There are times, when you don’t really know the value of your provider, and can only generate them when the App itself is instantiated. The useFactory property can be used in those scenarios:

import { createApp } from 'frint';

const MyApp = createApp({
  name: 'MyAppName',
  providers: [
    {
      name: 'bar',
      useFactory: function () {
        return 'bar value here';
      },
    },
  ],
});
Enter fullscreen mode Exit fullscreen mode

Now the bar provider can be obtained from your App’s instance as follows:

const app = new MyApp();

const bar = app.get('bar'); // `bar value here`
Enter fullscreen mode Exit fullscreen mode

Please note that, the function that generates bar's value is only called once during the App’s instantiation. After that, it will keep returning the same cached value from the App’s internal registry of all providers.

Generated from ES6 classes

There are also cases, where you can also write your providers as ES6 classes first:

class Baz {
  getValue() {
    return 'baz value here';
  }
}
Enter fullscreen mode Exit fullscreen mode

To set ES6 classes as providers, we can use the useClass property when defining them in FrintJS Apps:

import { createApp } from 'frint';

const MyApp = createApp({
  name: 'MyAppName',
  providers: [
    {
      name: 'baz',
      useClass: Baz,
    },
  ],
});
Enter fullscreen mode Exit fullscreen mode

Now whenever your App gets instantiated, it will also instantiate the Baz class, and set the instance as baz provider’s value.

const app = new MyApp();

const baz = app.get('baz'); // instance of Baz class
console.log(baz.getValue()); // `baz value here`
Enter fullscreen mode Exit fullscreen mode

Similar to useFactory, the class will be instantiated only once during your App’s instantiation and will return the same cached value every time you do app.get('baz').

Injecting providers in other providers

Now that we understand how providers can be defined in various ways in FrintJS Apps, we can go further into advanced use cases where one provider may depend on another provider.

From above examples, let’s say bar provider needs to know the value of foo. How do we inject foo into bar?

We can use the deps (short for dependencies) property:

import { createApp } from 'frint';

const MyApp = createApp({
  name: 'MyAppName',
  providers: [
    {
      name: 'foo',
      useValue: 'foo value here',
    },
    {
      name: 'bar',
      useFactory: function (deps) {
        const { foo } = deps; // `foo value here`
        return foo + ', bar value here';
      },
      deps: ['foo'],
    },
  ],
});
Enter fullscreen mode Exit fullscreen mode

This is what we just did above:

  • Define foo provider
  • Define bar provider
  • For bar, list foo as a dependency
  • The function that generates bar value will now receive a deps object with all its dependencies keyed by their names. Since we have listed only foo as a dependency, it will receive foo only for now.
  • The generated value of bar now returns foo value here, baz value here.

You can try it yourself:

const app = new MyApp();

const foo = app.get('foo');
const bar = app.get('bar');

console.log(bar); // `foo value here, bar value here`
Enter fullscreen mode Exit fullscreen mode

You can apply similar technique for useClass too. The deps object will then be given to the class as its first constructor argument:

class Baz {
  constructor(deps) {
    console.log(deps);
  }
}
Enter fullscreen mode Exit fullscreen mode

You can read further about it in the official docs for frint package here: https://frint.js.org/docs/packages/frint/.

Top comments (0)