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

chore: clean up extension generator #6158

Merged
merged 1 commit into from
Aug 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions docs/site/Component.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,64 @@ const app = new RestApplication();
app.component(AuthenticationComponent);
```

## Official components

Here is a list of components officially created and maintained by the LoopBack
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the list below contains the components from the core (e.g. @loopback/rest) and extensions (e.g. @loopback/apiconnect). Perhaps it's better to separate the 2 categories?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bajtos what do you say?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind either way.

team.

### Core components

These components implement the primary LoopBack capabilities.

- [@loopback/authentication](https://github.com/strongloop/loopback-next/tree/master/packages/authentication) -
A LoopBack component for authentication support
- [@loopback/authorization](https://github.com/strongloop/loopback-next/tree/master/packages/authorization) -
A LoopBack component for authorization support
- [@loopback/boot](https://github.com/strongloop/loopback-next/tree/master/packages/boot) -
A collection of Booters for LoopBack 4 Applications
- [@loopback/booter-lb3app](https://github.com/strongloop/loopback-next/tree/master/packages/booter-lb3app) -
A booter component for LoopBack 3 applications to expose their REST API via
LoopBack 4
- [@loopback/rest](https://github.com/strongloop/loopback-next/tree/master/packages/rest) -
Expose controllers as REST endpoints and route REST API requests to controller
methods
- [@loopback/rest-crud](https://github.com/strongloop/loopback-next/tree/master/packages/rest-crud) -
REST API controller implementing default CRUD semantics
- [@loopback/rest-explorer](https://github.com/strongloop/loopback-next/tree/master/packages/rest-explorer) -
LoopBack's API Explorer

### Extensions

These components add additional capabilities to LoopBack.

- [@loopback/apiconnect](https://github.com/strongloop/loopback-next/tree/master/extensions/apiconnect) -
An extension for integrating with
[IBM API Connect](https://www.ibm.com/cloud/api-connect)
- [@loopback/authentication-jwt](https://github.com/strongloop/loopback-next/tree/master/extensions/authentication-jwt) -
Extension for JWT authentication
- [@loopback/authentication-passport](https://github.com/strongloop/loopback-next/tree/master/extensions/authentication-passport) -
A package creating adapters between the passport module and
@loopback/authentication
- [@loopback/context-explorer](https://github.com/strongloop/loopback-next/tree/master/extensions/context-explorer) -
Visualize context hierarchy, bindings, configurations, and dependencies
- [@loopback/cron](https://github.com/strongloop/loopback-next/tree/master/extensions/cron) -
Schedule tasks using cron-like syntax
- [@loopback/extension-health](https://github.com/strongloop/loopback-next/tree/master/extensions/health) -
An extension exposes health check related endpoints with LoopBack 4
- [@loopback/extension-logging](https://github.com/strongloop/loopback-next/tree/master/extensions/logging) -
An extension exposes logging for Winston and Fluentd with LoopBack 4
- [@loopback/extension-metrics](https://github.com/strongloop/loopback-next/tree/master/extensions/metrics) -
An extension exposes metrics for Prometheus with LoopBack 4
- [@loopback/pooling](https://github.com/strongloop/loopback-next/tree/master/extensions/pooling) -
Resource pooling service for LoopBack 4
- [@loopback/typeorm](https://github.com/strongloop/loopback-next/tree/master/extensions/typeorm) -
Adds support for TypeORM in LoopBack

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to add the link for community extensions as well? https://loopback.io/doc/en/lb4/Community-extensions.html

### Community extensions

For a list of components created by community members, refer to
[Community extensions](./Community-extensions.html).

## Creating components

Please refer to [Creating components](Creating-components.md) for more
Expand Down
40 changes: 26 additions & 14 deletions docs/site/Creating-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -441,23 +441,35 @@ app.find('repositories.*');

## Configuring components

More often than not, the component may want to offer different value providers
depending on the configuration. For example, a component providing an email API
may offer different transports (stub, SMTP, and so on).
Components can be configured by an app by calling `this.configure()` in its
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CHANGE NOTE

Let's keep examples as simple as possible and avoid using concepts and terms which can be overwhelming for beginners.

constructor, and the configuration object can be injected into the component
constructor using the `@config()` decorator.

Components should use constructor-level
[Dependency Injection](Context.md#dependency-injection) to receive the
configuration from the application.
{% include code-caption.html content="mycomponent.ts" %}

```ts
class EmailComponent {
constructor(@inject('config#components.email') config) {
this.providers = {
sendEmail:
this.config.transport == 'stub'
? StubTransportProvider
: SmtpTransportProvider,
};
export class MyComponent implements Component {
constructor(
@config()
options: MyComponentOptions = {enableLogging: false},
) {
if (options.enableLogging) {
// do logging
} else {
// no logging
}
}
}
```

{% include code-caption.html content="application.ts" %}

```ts
...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep code snippets a valid TypeScript please.

Suggested change
...
// ...

Per Raymond's suggestions above. The same comment applies to all other places where you are using ....

// MyComponent.COMPONENT is the binding key of MyComponent
this.configure(MyComponent.COMPONENT).to({
enableLogging: true,
});
this.component(MyComponent);
...
```
6 changes: 3 additions & 3 deletions docs/site/Extending-LoopBack-4.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ ctx.bind('utilities.PasswordHash').to(PasswordHasher)
// Bind the UserController class as the user management implementation
ctx.bind('controllers.UserController').toClass(UserController);

// Locate the an instance of UserController from the context
// Locate the instance of UserController from the context
const userController: UserController = await ctx.get<UserController>('controller.UserController');
// Run the login()
const ok = await userController.login('John', 'MyPassWord');
Expand Down Expand Up @@ -189,8 +189,8 @@ An application-level component usually contributes:

### Learn from existing ones

- [loopback4-example-log-extension](https://github.com/strongloop/loopback-next/tree/master/examples/log-extension)
- [@loopback/authentication](https://github.com/strongloop/loopback-next/tree/master/packages/authentication)
Refer to the list of [official components](./Component.md#official-components)
for an idea about how different types of components are written.

### Create your own extension

Expand Down
8 changes: 8 additions & 0 deletions packages/cli/generators/extension/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ module.exports = class ExtensionGenerator extends ProjectGenerator {
}

scaffold() {
if (this.projectInfo) {
this.projectInfo.optionsInterface = `${this.projectInfo.componentName}Options`;
this.projectInfo.bindingsNamespace = `${this.projectInfo.componentName}Bindings`;
const uppercaseUnderscore = this.projectInfo.name
.toUpperCase()
.replace(/\W/g, '_');
this.projectInfo.defaultOptions = `DEFAULT_${uppercaseUnderscore}_OPTIONS`;
}
return super.scaffold();
}

Expand Down
26 changes: 20 additions & 6 deletions packages/cli/generators/extension/templates/src/component.ts.ejs
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
import {Component, ProviderMap} from '@loopback/core';
import {
Application,
bind,
Component,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
config,
ContextTags,
CoreBindings,
inject,
} from '@loopback/core';
import {<%= project.bindingsNamespace %>} from './keys'
import {<%= project.defaultOptions %>, <%= project.optionsInterface %>} from './types';

// Configure the binding for <%= project.componentName %>
@bind({tags: {[ContextTags.KEY]: <%= project.bindingsNamespace %>.COMPONENT}})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add some comments for the component.

export class <%= project.componentName %> implements Component {
constructor() {}

providers?: ProviderMap = {
};

constructor(
@inject(CoreBindings.APPLICATION_INSTANCE)
private application: Application,
@config()
private options: <%= project.optionsInterface %> = <%= project.defaultOptions %>,
) {}
}
2 changes: 2 additions & 0 deletions packages/cli/generators/extension/templates/src/index.ts.ejs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './component';
export * from './keys';
export * from './types';
11 changes: 11 additions & 0 deletions packages/cli/generators/extension/templates/src/keys.ts.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {BindingKey, CoreBindings} from '@loopback/core';
import {<%= project.componentName %>} from './component';

/**
* Binding keys used by this component.
*/
export namespace <%= project.bindingsNamespace %> {
export const COMPONENT = BindingKey.create<<%= project.componentName %>>(
`${CoreBindings.COMPONENTS}.<%= project.componentName %>`,
);
}
15 changes: 15 additions & 0 deletions packages/cli/generators/extension/templates/src/types.ts.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Interface defining the component's options object
*/
export interface <%= project.optionsInterface %> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add some comments here to explain the purpose of <Extension>Options and describe specific properties should be added into the empty body.

// Add the definitions here

}

/**
* Default options for the component
*/
export const <%= project.defaultOptions %>: <%= project.optionsInterface %> = {
// Specify the values here

};
29 changes: 29 additions & 0 deletions packages/cli/generators/project/templates/README.md.ejs
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
# <%= project.name %>

[![LoopBack](https://github.com/strongloop/loopback-next/raw/master/docs/site/imgs/branding/Powered-by-LoopBack-Badge-(blue)[email protected])](http://loopback.io/)

## Installation

Install <%= project.componentName %> using `npm`;

```sh
$ npm install <%= project.name %>
```

## Basic Use

Configure and load <%= project.componentName %> in the application constructor
as shown below.

```ts
import {<%= project.componentName %>, <%= project.optionsInterface %>, <%= project.defaultOptions %>} from '<%= project.name %>';
// ...
export class MyApplication extends BootMixin(ServiceMixin(RepositoryMixin(RestApplication))) {
constructor(options: ApplicationConfig = {}) {
const opts: <%= project.optionsInterface %> = <%= project.defaultOptions %>;
this.configure(<%= project.bindingsNamespace %>.COMPONENT).to(opts);
// Put the configuration options here
});
this.component(<%= project.componentName %>);
// ...
}
// ...
}
```
2 changes: 1 addition & 1 deletion packages/core/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export interface ClassMap {
}

/**
* A component declares a set of artifacts so that they cane be contributed to
* A component declares a set of artifacts so that they can be contributed to
* an application as a group
*/
export interface Component {
Expand Down