@microbackend/plugin-core
v1.0.1
Published
Micro-backend core plugin
Downloads
403
Readme
@microbackend/plugin-core
The core plugin that contains extensible interfaces and extension logic. This
plugin must be included in all microbackend
-based projects.
Installation
yarn add @microbackend/plugin-core
npm install @microbackend/plugin-core
Usage
In your project's webpack configuration file (for examle, webpack.config.ts
):
import createPluginConfig, {
mergeConfigurations,
} from "@microbackend/plugin-core/build/webpack.build";
import "./src/interface/microbackend";
const webpackConfiguration = mergeConfigurations(
createPluginConfig({ environment: process.env.NODE_ENV }),
{
// Your own project's webpack configuration here.
}
);
export default webpackConfiguration;
Extension patterns
An extension pattern represents the process of extending the capabilities of a module using plugins.
microbackend
uses typescript
and webpack
exclusively for building. At
compilation time, the webpack module rules in @microbackend/plugin-core
look
for the files corresponding to each extension pattern, and import them into
the main extensible module.
For example, let's consider the extensible module
@microbackend/plugin-core/src/extension/app.ts
. When we run webpack
to build
the project, it looks for all files that match
[pluginName]/src/extension/app.ts
, extract their exports and import them into
@microbackend/plugin-core/src/extension/app.ts
, resulting in the
following pre-bundling file contents:
// @microbackend/plugin-core/src/extension/app.ts
import pluginname from "pluginname/src/extension/app.ts";
export { pluginName };
The function extendMicrobackendApplication
in @microbackend/plugin-core
then
takes all these exports and merge them into the provided
IMicrobackendApp
object using Object.defineProperty
.
Extension pattern example
For illustration purposes, create the following files in your project:
src/extension/app.ts
:
// src/extension/app.ts
declare module "@microbackend/plugin-core" {
interface IMicrobackendApp {
readonly appProperty1: () => number;
readonly appProperty2: number;
}
}
export function appProperty1(): number {
return 1;
}
export default {
get appProperty2(): number {
return 2;
},
};
src/extension/request.ts
:
import { IMicrobackendRequest } from "@microbackend/plugin-core";
export function appProperty1(this: IMicrobackendRequest): number {
// Now the application object already possesses the "appProperty1" extension.
return this.app.appProperty1();
}
export default {
get appProperty2(): number {
// Now the application object already possesses the "appProperty2" extension.
return (this as unknown as IMicrobackendRequest).app.appProperty2;
},
};
src/extension/lifecycle.ts
:
import { MicrobackendLifecycle } from "@microbackend/plugin-core";
export default class MainLifecycle extends MicrobackendLifecycle {
override initialize() {
console.log("Initialized");
}
override deinitialize() {
console.log("Deinitialized");
}
}
src/extension/config.ts
:
import { MicrobackendConfig } from "@microbackend/plugin-core";
export default class CommonConfig extends MicrobackendConfig {
get config(): MicrobackendConfig["config"] {
return () => {
// Accessible via app.config.config1.
return { config1: 1 };
};
}
}
So now, IMicrobackendApp
has two additional properties appProperty1
and
appProperty2
, as does IMicrobackendRequest
.
Supported extension patterns
IMicrobackendApp
, supported byextension/app
: An interface representing an application. For example, this could beexpress.Application
if we are using the plugin@microbackend/plugin-express
.IMicrobackendRequest
, supported byextension/request
: An interface representing a request. For example, this could beexpress.Request
if we are using the plugin@microbackend/plugin-express
. A microbackend request could contain properties such asbody
,headers
,params
,query
etc.IMicrobackendService
, supported byextension/service
: An interface representing services that handle business logic, and are available to access usingrequest.service
. If the service extension is a folder (i.e.extension/service
), the service object can contain namespaces based on its subfolders. For example:// extension/service/auth/service1.ts export default class Service { method1() {} } // extension/service/logic/service2.ts export default class Service { method2() {} } // elsewhere request.service.auth.service1.method1(); request.service.logic.service2.method2();
Please note that only service extension modules in the current project are included in
req.service
.IMicrobackendLifecycle
, supported byextension/lifecycle
: An object that contains methods to hook into the application's lifecycle events, such asinit
anddeinit
.IMicrobackendConfig
, supported byextension/config
: An interface representing the current application's configurations, and is accessible viaapp.config
.Environment-specific extension overrides, supported by
extension/env_overrides/{environment}
: Anything that can be extended normally, such as application, request, configuration etc, can be overridden depending on the current environment. The environment value depends on what we pass tocreatePluginConfig
, so we are free to declare any value (not just development/production) - it could be prd/dev/local/test/e2e.For example, if we want to serve different configurations in development and production, we can do it like so:
// extension/env_overrides/development/config.ts import { MicrobackendConfig } from "@microbackend/plugin-core"; export default class CommonConfig extends MicrobackendConfig { get config(): MicrobackendConfig["config"] { return () => { // If the current environment is development, this config will be picked // and merged with the common configuration (if any). return { config1: 2 }; }; } } // extension/env_overrides/production/config.ts import { MicrobackendConfig } from "@microbackend/plugin-core"; export default class CommonConfig extends MicrobackendConfig { get config(): MicrobackendConfig["config"] { return () => { // If the current environment is production, this config will be picked // and merged with the common configuration (if any). return { config1: 3 }; }; } }
The corresponding functions for these extensions are:
enhanceMicrobackendApp
enhanceMicrobackendRequest
createMicrobackendLifecycle
Since this plugin can work for any application that adheres to an Application/Request model, you can import and use these functions in your project like so:
import {
createMicrobackendLifecycle,
enhanceMicrobackendApp,
enhanceMicrobackendRequest,
} from "@microbackend/plugin-core";
class Application {}
class Request {}
const application = new Application();
enhanceMicrobackendApp(application);
application.onRequest((request: Request) => {
enhanceMicrobackendRequest(request);
});
const lifecycle = createMicrobackendLifecycle({ application });
lifecycle.initialize().then(() => {
return application.start({
onEnd: async () => {
await lifecycle.deinitialize();
},
});
});
However, you should not have to call them manually to set up the extensions. Instead, please use one of the following framework-specific plugins:
Creating a new extension pattern
To create a new extension pattern:
Create a new file under
src/extension
in the plugin or project you are working on, such assrc/extension/a.ts
.Populate this file with the following contents:
/** Replace with imports */
export default {};
The
/** Replace with imports */
placeholder is necessary for webpack to substitute the correct import/export statements.Create a
webpack.build.ts
(unless it is already available), and importcreateMicrobackendExtension
from@microbackend/plugin-core/webpack.build.config
. Call this function, provide the necessary arguments, and merge the resulting configuration with your existing configuration (using@microbackend/plugin-core/webpack.build.ts > mergeConfigurations
).For a practical example, please check out
/package/plugin_graphql_core/webpack.build.ts
.
Creating a plugin
A plugin in an installable package that can be consumed in a microbackend
-based
application. Each plugin generally have the following structure:
/src
/extension // contains extension modules
/app.ts // contains application extensions
/request.ts // contains request extensions
/config.ts // contains configuration extensions
/lifecycle.ts // contains lifecycle extensions
/service.ts // contains service extensions
/index.ts // contains type declarations and other exports
/package.json // contains plugin package information
/tsconfig.json // contains TypeScript configurations
/webpack.build.ts // contains webpack configurations that will be merged
// during compilation. Please note that this config is not
// used to build the plugin itself, but to build the
// microbackend application.
Installing a plugin
To add a new plugin, there are two ways:
Via the microbackend
CLI tool (recommended)
Check out the CLI package here. You can install and use it as follows:
yarn add @microbackend/cli
npm install @microbackend/cli
npx microbackend plugin add @microbackend/plugin-example-1 @microbackend/plugin-example-2
Manually (not recommended)
You need to install the correct package from npm:
yarn add @microbackend/plugin-example
npm install @microbackend/plugin-example
Since @microbackend/plugin-core
reads microbackend meta information from your
project's package.json
, add the new plugin to microbackend > plugin
section:
{
"microbackend": {
"plugins": ["@microbackend/plugin-core", "@microbackend/plugin-example"]
}
}