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

Introduce UI PluginsService #32672

Merged
merged 20 commits into from
Apr 3, 2019

Conversation

joshdover
Copy link
Contributor

@joshdover joshdover commented Mar 7, 2019

Summary

Closes #18874

This PR introduces two changes:

  • Adds new platform plugins as a new bundles to the optimizer
  • A PluginsService that loads plugin bundles, initializes plugins, and manages the lifecycle of plugins.

For testing locally, here are two plugins you can download and extract into src/plugins to see real plugins loading in the browser and interacting. Use these to hack around with if you'd like.

Building plugin bundles

To create immutable bundles for new platform plugins, I've updated the BaseOptimizer to add new entry points, one for each UI plugin discovered by Core's plugin discovery process. I've also updated our Webpack output to include these new options:

library: ['__kbnBundles__', '[name]'],
libraryExport: 'plugin',

This directs Webpack to assign the exported plugin value from each entry point (if present) to a global object that it sets up, where the key of the object is the name of the entry point. Since all plugin entry points are configured with the name plugin/${pluginName} this global object looks like this once these entry points are loaded on the page:

window.__kbnBundles__ = {
  'plugin/pluginA': function plugin() { ... },
  'plugin/pluginB': function plugin() { ... },
  'kibana': undefined  // this output setting applies to all bundles
};

Since all bundles are affected by this output setting, the entry points for the legacy system will also attach their exported plugin values to the the global __kbnBundles__ object. Since these entry points do not export any plugin values, this will be undefined and unused.

I've also verified that our splitChunks configuration correctly deduplicates dependencies from these plugin bundles. For example, importing React in a plugin does not result in a copy of the React module being included in the plugin's bundle. It will continue to use the common React module from our DLLs.

PluginsService

The structure of the new PluginsService is largely the same as the server side, with the discovery process replaced with a bundle loading step.

Each Plugin instance (a thin wrapper that manages a plugin's construction and lifecycle) has a load function that loads the bundle into the browser and grabs the exported plugin function from window.__kbnBundles__.

In order to decrease startup time, all of these bundles are loaded in parallel. This step happens after the page loads, but before the legacy platform is started. This is one area of this PR that could be optimized further if needed, but I suspect will be fast for most users because these plugin bundles should be cached in the browser after the first load. Options for making this faster:

  • Add these bundles in the generated bootstrap.js file so they're loaded immediately.
  • Concatenate all the bundle files on the backend and serve them in single request to reduce the number of connections needed.
  • Use HTTP/2 to load these bundles over a single connection. This may not be an option that works for all customers as they may have proxy configurations or browsers that do not support HTTP/2.

Once bundles are loaded, the PluginsService proceeds almost identically to the backend service to manage the lifecycle of the plugins and wire up dependencies.

Dev Docs

Introduce UI PluginsService

The experimental new platform now supports plugins in the browser. The API for defining plugins mirrors the interface for server-side plugins. New platform plugins can enable a client-side plugin by defining an entry point my_plugin/public/index.ts and adding the "ui": true flag in their my_plugin/kibana.json file.

The entry point for the plugin should export a single plugin function that returns an initialized plugin with the required setup, start, and stop functions:

// my_plugin/public/index.ts
import { CoreSetup, CoreStart, Plugin, PluginInitializer } from 'kibana/public';

export const plugin: PluginInitializer<MyPluginSetup, MyPluginStart> = () =>
  new MyPlugin();

interface MyPluginSetup {
  foo: string;
}

interface MyPluginStart {
  bar(): string;
}

class MyPlugin implements Plugin<MyPluginSetup, MyPluginStart> {
  setup(core: CoreSetup) {
    return { foo: 'bar' };
  }

  start(core: CoreStart) {
    return {
      bar() { return 'baz' }
    };
  }

  stop() { }
}

Any value returned by your plugin's setup and start functions will be provided as dependencies for any plugins that depend on your plugin via the requiredPlugins and optionalPlugins options in a plugin's kibana.json file.

@joshdover joshdover force-pushed the np-ui-plugins-load-bundle branch 7 times, most recently from b8cdc6f to 30b4931 Compare March 12, 2019 14:42
@joshdover joshdover force-pushed the np-ui-plugins-load-bundle branch 9 times, most recently from 8d65ffb to 772e6e7 Compare March 22, 2019 14:50
@joshdover joshdover changed the title [wip] Introduce UI plugins service [wip] Introduce UI PluginsService Mar 22, 2019
@joshdover joshdover force-pushed the np-ui-plugins-load-bundle branch from 772e6e7 to 3377535 Compare March 22, 2019 15:41
@@ -66,6 +66,7 @@ export default async (kbnServer, server, config) => {
const optimizer = new FsOptimizer({
logWithMetadata: (tags, message, metadata) => server.logWithMetadata(tags, message, metadata),
uiBundles,
discoveredPlugins: newPlatform.start.plugins.uiPlugins.internal,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This will be updated to newPlatform.setup once #33708 is merged.

@@ -30,6 +30,7 @@ export default async (kbnServer, kibanaHapiServer, config) => {
const watchOptimizer = new WatchOptimizer({
logWithMetadata,
uiBundles: kbnServer.uiBundles,
discoveredPlugins: kbnServer.newPlatform.start.plugins.uiPlugins.internal,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This will be updated to newPlatform.setup once #33708 is merged.

@joshdover joshdover changed the title [wip] Introduce UI PluginsService Introduce UI PluginsService Mar 22, 2019
@elastic elastic deleted a comment from elasticmachine Mar 22, 2019
@elastic elastic deleted a comment from elasticmachine Mar 22, 2019
@elastic elastic deleted a comment from elasticmachine Mar 22, 2019
@elastic elastic deleted a comment from elasticmachine Mar 22, 2019
@joshdover joshdover force-pushed the np-ui-plugins-load-bundle branch from 9d29795 to e31d95f Compare April 1, 2019 21:05
@elasticmachine
Copy link
Contributor

💔 Build Failed

@elasticmachine
Copy link
Contributor

💔 Build Failed

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

Copy link
Contributor

@mshustov mshustov left a comment

Choose a reason for hiding this comment

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

LGTM

@elasticmachine
Copy link
Contributor

💔 Build Failed

@elasticmachine
Copy link
Contributor

💔 Build Failed

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

@joshdover joshdover merged commit d33e689 into elastic:master Apr 3, 2019
@joshdover joshdover deleted the np-ui-plugins-load-bundle branch April 3, 2019 17:02
@joshdover
Copy link
Contributor Author

joshdover commented Apr 3, 2019

Waiting on getting in the backport for #34421 before backporting this as they conflict with one another.

joshdover added a commit to joshdover/kibana that referenced this pull request Apr 3, 2019
This commit introduces two changes:
- Adds new platform plugins as a new bundles to the optimizer
- A PluginsService in the UI that loads plugin bundles, initializes plugins, and manages the lifecycle of plugins.
joshdover added a commit that referenced this pull request Apr 4, 2019
This commit introduces two changes:
- Adds new platform plugins as a new bundles to the optimizer
- A PluginsService in the UI that loads plugin bundles, initializes plugins, and manages the lifecycle of plugins.
@epixa epixa added the release_note:plugin_api_changes Contains a Plugin API changes section for the breaking plugin API changes section. label May 8, 2019
@elasticmachine
Copy link
Contributor

💔 Build Failed

@elasticmachine
Copy link
Contributor

💔 Build Failed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:New Platform release_note:enhancement release_note:plugin_api_changes Contains a Plugin API changes section for the breaking plugin API changes section. Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc v7.2.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[new-platform] UI plugins
5 participants