npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@project-sunbird/web-extensions

v8.0.1

Published

Sunbird web extension would allow you to write application as composition of pluggable modules and provide additional functionality through it. It helps you manage the scope of your application/project.

Downloads

235

Readme

Sunbird Web extensions

Sunbird web extension would allow you to write application as composition of pluggable modules and provide additional functionality through it. It helps you manage the scope of your application/project.

Sometimes, a requested feature is really nice and helpful, but it would bloat the application core when its design is not handled carefully. Instead of snowballing your whole application or library with such features, design your whole application in a way that it allows you to build a plugin architecture that has a great effect on the extensibility of your system.

A pluggable framework (or plug-in architecture) means a system which allows third party developers to create or extend the functionality of a primary application through the use of pluggable components without having direct access to or knowledge of the primary application's source code or inner workings.

This is because you're making your application open for extensibility but closing it for modification. This will allow us to develop portable functionality that is packaged into plugins.

Sections:

  1. Design overview
  2. Setup
  3. Getting started with Angular
  4. Tutorials
  5. API documentation
  6. Development server
  7. Build
  8. Running Unit testcase

1. Design Overview:

The system that we're going to build in this chapter borrows a lot of mechanisms that are already present in the Angular framework. In order to implement extensibility using plugins, we rely on the following core concepts:

Let's look at the following illustration to picture the architecture of our plugin system before we start implementing it:

2. Setup:

  1. cd web-extensions/sunbird-web-extensions-app
  2. npm install
  3. ng build sunbird-web-extension // to build library dist
  4. ng serve

3. Getting started with Angular:

Prerequisites:

we assume that you have at least some basic knowledge of Angular-CLI, TypeScript, a reasonable familiarity with Node and how all of these fit together and also you already have an angular application up and running.

If you don't have angular application running, continue to follow the steps below:

Angular in it's latest version(Angular 6.0), many of the improvements were to the Angular CLI and a new schematic has been added to help you generate a library.

Let us begin by setting up the workspace.

  1. Creating an Angular Workspace:

Our first goal was to create an Angular workspace named my-app

 ng new my-app
 cd my-app
 ng serve --open

When we point our browser at: http://localhost:4200/ we see the starter Angular application

NOTE: If you don't have Angular-CLI, follow the below steps:

  1. Install the Angular CLI, if you haven't already done so.
  2. To quickly set up Node.js on your machine, Set up Node.js.
  3. To learn more about Angular 6 and it's features, head to Angular 6 docs
  1. Creating a library with Angular 6 and above:

To generate a library in Angular-CLI just run the following command.

 ng generate library library-name

and it will scaffold the necessary files in the projects directory.

The important thing is that you can directly import from the library into your applications in the same CLI project, even without publishing the library on NPM.

For example, let’s say you generated a shared library. By default the CLI will produce a shared directory inside projects, with a ShareComponent and a SharedService.

If you want to use the SharedService inside your application, for example in app.component.ts, you simply have to import:

import { Component } from '@angular/core'; 
import { SharedService } from 'shared'; 

 @Component({ 
  selector: 'app-root', 
  templateUrl: './app.component.html', 
  styleUrls: ['./app.component.css'] 
 }) 
 export class AppComponent { 
  title = 'app'; 

  constructor(sharedService: SharedService) { 
 // note the import at the top! 
  } 
 } 

And the CLI will handle it!

This opens great possibilities for large project, and for developers to open source libraries of useful components and services!

Obviously, these developers will not be familiar with all of the intricacies of the code for the application they are plugging into. Once the plugins are developed, other even less technical users may simply install the application and any selected plugins.

4. Tutorials:

4.1 Build your first plugin:

Before we get into the plugin details, we should first agree on where to make our application extensible. Our plugin system is based on the ExtensionPoint directives, which should be placed somewhere in our component tree so that plugins can expose components to these extension points.

For now, we decide to make one menu items at the top in our application extensible:

Table Generator: A menu item that takes the user to generate a table in their content editor. Firstly, lets set the plugin placement by setting out ExtensionPoint directive into your app.component.ts which is going to load our top menu.

    <extension-point name="table-generator"></extension-point>

Let's start building this Table Generator plugin/library using the following CLI command.

ng generate library table-generator

It creates all the necessary files.

The files are create at a location based on the path mentioned in the angular.json file.

Here the path mentioned is my-app/projects

We have now created TableGeneratorComponent that we want to expose.

import { Component, OnInit } from '@angular/core'; 
  @Component({ 
   selector: 'lib-table-generator', 
   template: ` 
    <p> table-generator works!</p> 
   `, 
    styles: [] 
  }) 
  export class TableGeneratorComponent implements OnInit { 
   constructor() { } 
   ngOnInit() { } 
 }

You can see that we implemented a regular component here. There's nothing special about this component at all.

Create plugin.ts file inside table-generator/src/lib

This plugin.ts will contain the plugin configuration.

Alright, now we can import the sunbird-web-extension module and also can expose the plugin component in the plugin configuration using a PluginPlacement object. Let's make the necessary modification to our plugin.ts module file:

import { PluginConfig, PluginPlacement } from 'sunbird-web-extension'; 
import { TableGeneratorComponent } from '../public_api'; 

@PluginConfig({ 
 name: 'table generator plugin', 
 description: 'TableGenerator', 
 placements: [ 
 ] 
}) 
export class TableGeneratorPlugin { 
}

Now, we include a new PluginPlacement object in our plugin configuration, which maps our TableGenerator component to be exposed into the application extension point with the name table-generator:

import { PluginConfig, PluginPlacement } from 'sunbird-web-extension'; 
import { TableGeneratorComponent } from '../public_api'; 

@PluginConfig({ 
 name: 'table generator plugin', 
 description: 'TableGenerator', 
 placements: [ 
 new PluginPlacement({name: 'table-generator', priority: 1, component: TableGeneratorComponent})

 ] 
}) 
export class TableGeneratorPlugin { 
} 

Let us create an index.ts and export the plugin's module, component and the plugin configurations.

 export * from './src/lib/plugin'; 
 export * from './src/lib/table-generator.module'; 
 export * from './src/lib/table-generator.component';

This would already be enough for the plugin to work.

The only thing that is left is to add the plugin to the list of plugins that should be loaded initially by the PluginService directive.

4.2 Integrating plugin with app:

  1. To integrate the plugin that we just built into the Sunbird Platform we'll create a framework.config.ts file on the root of our application and add the following content:
export const WebExtensionsConfig = { 
  plugins: [ 
  { 
   'id': 'table-generator', 
   'ver': '1.0.0', 
   'module': TableGeneratorModule, 
   'main': TableGeneratorPlugin 
  }] 
 };

Next, we will import the build of sunbird-web-extension module and framework.config.ts into your main app.module.ts

import { BootstrapFramework, WebFrameworkModule } from '../../libs/sunbird-web-extension'; 
import { WebExtensionsConfig } from '../framework.config';  

This will import BootstrapFramework and WebFrameworkModule classes. and the config file which has the array of plugins that we want to extend on the fly.

Now, if we launch our application, the plugin will be loaded by the PluginService and ExtensionPoint directives will instantiate the TableGenerator plugin components where appropriate.

  1. Next, create a file called framework.config.ts file under the src/ folder of your angular app
your-angular-app-folder/
├── libs/
     ├──sunbird-web-extension
├── src/
        ...
     ├──framework.config.ts
├── angular.json
├── ...

Summarizing on our first plugin:

Well done! You have successfully implemented your first plugin! In this section, we used the API of our plugin architecture to create a plugin to manage Table Generation. We used the PluginPlacement class to map our plugin components to different slots in the UI of our application. We also made use of the PluginData object that is provided to each instantiated component in the plugin slot in order to access the plugin instance. The advantage of implementing functionality like this inside a plugin should be obvious. We added an additional feature to our application without building up additional dependencies. Our Table Generator feature is completely portable. Third-party developers can write independent plugins, and they can be loaded by our system. This is a big advantage, and it helps us keep our core slim while providing great extensibility.

4.3 Sample plugin demo:

Click here

NOTE: Dynamic loading of plugin during runtime is not supported!

Here in the demo, Plugin is loaded dynamically for demo purpose only.

5. API document:

1. extension-point Angular directive:

This directive will allow other extensions to extend the app functionality. Plugin can also use this directive inside there components to allow other plugin to extend and so on.

Options:

|Attribute|Description| |---|----| |1. name: String| name of the extension point, to be namespaced, to avoid global namespace collision. e.g: com.sunbird.myplugin for sunbird extensions | |2. override: Boolean| if true, it will allow multiple extensions on the same extension point, if false, it will allow only one extension (based on hihest priority set in PluginPlacement) | |3. input: any | to bind data to extension during initialisation | |4. output: EventEmitter | to bind output events from extensions |

2. PluginConfig Annotation:

@PluginConfig({
    name: String,
    description: String,
    placements: Array<PluginPlacement>
})
export class MyPlugin {
}

PluginConfig annotation decorates MyPlugin(in example) class with details such as name, description, placements of the extension which is required for the framework to place the extension based on the placements info provided.

3. PluginPlacement Class:

PluginPlacement has detail about the angular component which has to be rendered at defined host extension-point.

|Member| Description |
|----|----| | 1. name: String| name of the host extension-point | | 2. priority: number (non-negative)| can be any valid poisitve Integer, priority 1 is considered as highest priority | | 3. component: AngularComponent<T> | Token/class of angular component |

priority: if a extension-point is extended by more than one extension, then framework resolves which extension to allowed based on this feild.

Example: Say, we have extension-point as below:

<extension-point name="com.subird.profile.widget" override=true>

this extension would allow only extension to extended, since override flag is set to true.

for instance, there are 2 plugins (A, B) would like to extend the same extension-point, in this case it check for priority. Say A has priority 1 and B has priority 4, in this case framework picks the A plugin to extend the host extension-point.

If A and B has same priority, say 1 (which is not desirable), in this case framework picks up the plugin randomly.

6. Development server

Run ng serve for a dev server. Navigate to http://localhost:4200/. The app will automatically reload if you change any of the source files.

7. Build:

Run npm run build to create production ready build.

8. Running unit tests

Run npm run test to execute the unit tests via Karma.

Versions

| release branch | npm package version | Angular Version | |:-----------------:|:-------------------:|:---------------:| | release-5.1.0 | 0.0.2 | Ng V6 | | release-5.1.1 | 5.1.1 | Ng V11 | | release-5.1.2 | 5.1.2 | Ng V12 |