diff --git a/.ci/Jenkinsfile_visual_baseline b/.ci/Jenkinsfile_visual_baseline
index 2a16c499fa168..7c7cc8d98c306 100644
--- a/.ci/Jenkinsfile_visual_baseline
+++ b/.ci/Jenkinsfile_visual_baseline
@@ -21,5 +21,6 @@ kibanaPipeline(timeoutMinutes: 120) {
}
kibanaPipeline.sendMail()
+ slackNotifications.onFailure()
}
}
diff --git a/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.md b/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.md
index 0e2b9bd60ab67..b88a179c5c4b3 100644
--- a/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.md
+++ b/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.md
@@ -19,5 +19,6 @@ export interface DiscoveredPlugin
| [configPath](./kibana-plugin-core-server.discoveredplugin.configpath.md) | ConfigPath
| Root configuration path used by the plugin, defaults to "id" in snake\_case format. |
| [id](./kibana-plugin-core-server.discoveredplugin.id.md) | PluginName
| Identifier of the plugin. |
| [optionalPlugins](./kibana-plugin-core-server.discoveredplugin.optionalplugins.md) | readonly PluginName[]
| An optional list of the other plugins that if installed and enabled \*\*may be\*\* leveraged by this plugin for some additional functionality but otherwise are not required for this plugin to work properly. |
+| [requiredBundles](./kibana-plugin-core-server.discoveredplugin.requiredbundles.md) | readonly PluginName[]
| List of plugin ids that this plugin's UI code imports modules from that are not in requiredPlugins
. |
| [requiredPlugins](./kibana-plugin-core-server.discoveredplugin.requiredplugins.md) | readonly PluginName[]
| An optional list of the other plugins that \*\*must be\*\* installed and enabled for this plugin to function properly. |
diff --git a/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.requiredbundles.md b/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.requiredbundles.md
new file mode 100644
index 0000000000000..6d54adb5236ea
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.requiredbundles.md
@@ -0,0 +1,18 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [DiscoveredPlugin](./kibana-plugin-core-server.discoveredplugin.md) > [requiredBundles](./kibana-plugin-core-server.discoveredplugin.requiredbundles.md)
+
+## DiscoveredPlugin.requiredBundles property
+
+List of plugin ids that this plugin's UI code imports modules from that are not in `requiredPlugins`.
+
+Signature:
+
+```typescript
+readonly requiredBundles: readonly PluginName[];
+```
+
+## Remarks
+
+The plugins listed here will be loaded in the browser, even if the plugin is disabled. Required by `@kbn/optimizer` to support cross-plugin imports. "core" and plugins already listed in `requiredPlugins` do not need to be duplicated here.
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md
index 5edee51d6c523..6db2f89590149 100644
--- a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md
+++ b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md
@@ -25,6 +25,7 @@ Should never be used in code outside of Core but is exported for documentation p
| [id](./kibana-plugin-core-server.pluginmanifest.id.md) | PluginName
| Identifier of the plugin. Must be a string in camelCase. Part of a plugin public contract. Other plugins leverage it to access plugin API, navigate to the plugin, etc. |
| [kibanaVersion](./kibana-plugin-core-server.pluginmanifest.kibanaversion.md) | string
| The version of Kibana the plugin is compatible with, defaults to "version". |
| [optionalPlugins](./kibana-plugin-core-server.pluginmanifest.optionalplugins.md) | readonly PluginName[]
| An optional list of the other plugins that if installed and enabled \*\*may be\*\* leveraged by this plugin for some additional functionality but otherwise are not required for this plugin to work properly. |
+| [requiredBundles](./kibana-plugin-core-server.pluginmanifest.requiredbundles.md) | readonly string[]
| List of plugin ids that this plugin's UI code imports modules from that are not in requiredPlugins
. |
| [requiredPlugins](./kibana-plugin-core-server.pluginmanifest.requiredplugins.md) | readonly PluginName[]
| An optional list of the other plugins that \*\*must be\*\* installed and enabled for this plugin to function properly. |
| [server](./kibana-plugin-core-server.pluginmanifest.server.md) | boolean
| Specifies whether plugin includes some server-side specific functionality. |
| [ui](./kibana-plugin-core-server.pluginmanifest.ui.md) | boolean
| Specifies whether plugin includes some client/browser specific functionality that should be included into client bundle via public/ui_plugin.js
file. |
diff --git a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.requiredbundles.md b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.requiredbundles.md
new file mode 100644
index 0000000000000..98505d07101fe
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.requiredbundles.md
@@ -0,0 +1,18 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [PluginManifest](./kibana-plugin-core-server.pluginmanifest.md) > [requiredBundles](./kibana-plugin-core-server.pluginmanifest.requiredbundles.md)
+
+## PluginManifest.requiredBundles property
+
+List of plugin ids that this plugin's UI code imports modules from that are not in `requiredPlugins`.
+
+Signature:
+
+```typescript
+readonly requiredBundles: readonly string[];
+```
+
+## Remarks
+
+The plugins listed here will be loaded in the browser, even if the plugin is disabled. Required by `@kbn/optimizer` to support cross-plugin imports. "core" and plugins already listed in `requiredPlugins` do not need to be duplicated here.
+
diff --git a/examples/bfetch_explorer/kibana.json b/examples/bfetch_explorer/kibana.json
index 0039e9647bf83..f32cdfc13a1fe 100644
--- a/examples/bfetch_explorer/kibana.json
+++ b/examples/bfetch_explorer/kibana.json
@@ -5,5 +5,6 @@
"server": true,
"ui": true,
"requiredPlugins": ["bfetch", "developerExamples"],
- "optionalPlugins": []
+ "optionalPlugins": [],
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/examples/dashboard_embeddable_examples/kibana.json b/examples/dashboard_embeddable_examples/kibana.json
index bb2ced569edb5..807229fad9dcf 100644
--- a/examples/dashboard_embeddable_examples/kibana.json
+++ b/examples/dashboard_embeddable_examples/kibana.json
@@ -5,5 +5,6 @@
"server": false,
"ui": true,
"requiredPlugins": ["embeddable", "embeddableExamples", "dashboard", "developerExamples"],
- "optionalPlugins": []
+ "optionalPlugins": [],
+ "requiredBundles": ["esUiShared"]
}
diff --git a/examples/embeddable_examples/kibana.json b/examples/embeddable_examples/kibana.json
index 8ae04c1f6c644..771c19cfdbd3d 100644
--- a/examples/embeddable_examples/kibana.json
+++ b/examples/embeddable_examples/kibana.json
@@ -6,5 +6,6 @@
"ui": true,
"requiredPlugins": ["embeddable", "uiActions"],
"optionalPlugins": [],
- "extraPublicDirs": ["public/todo", "public/hello_world", "public/todo/todo_ref_embeddable"]
+ "extraPublicDirs": ["public/todo", "public/hello_world", "public/todo/todo_ref_embeddable"],
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/examples/state_containers_examples/kibana.json b/examples/state_containers_examples/kibana.json
index 66da207cb4e77..58346af8f1d19 100644
--- a/examples/state_containers_examples/kibana.json
+++ b/examples/state_containers_examples/kibana.json
@@ -5,5 +5,6 @@
"server": true,
"ui": true,
"requiredPlugins": ["navigation", "data", "developerExamples"],
- "optionalPlugins": []
+ "optionalPlugins": [],
+ "requiredBundles": ["kibanaUtils", "kibanaReact"]
}
diff --git a/examples/ui_action_examples/kibana.json b/examples/ui_action_examples/kibana.json
index cd12442daf61c..0e0b6b6830b95 100644
--- a/examples/ui_action_examples/kibana.json
+++ b/examples/ui_action_examples/kibana.json
@@ -5,5 +5,6 @@
"server": false,
"ui": true,
"requiredPlugins": ["uiActions"],
- "optionalPlugins": []
+ "optionalPlugins": [],
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/examples/ui_actions_explorer/kibana.json b/examples/ui_actions_explorer/kibana.json
index f57072e89b06d..0a55e60374710 100644
--- a/examples/ui_actions_explorer/kibana.json
+++ b/examples/ui_actions_explorer/kibana.json
@@ -5,5 +5,6 @@
"server": false,
"ui": true,
"requiredPlugins": ["uiActions", "uiActionsExamples", "developerExamples"],
- "optionalPlugins": []
+ "optionalPlugins": [],
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json
index 20c8046daa65e..33f53e336598d 100644
--- a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json
+++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json
@@ -1,4 +1,5 @@
{
"id": "bar",
- "ui": true
+ "ui": true,
+ "requiredBundles": ["foo"]
}
diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/_other_styles.scss b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/_other_styles.scss
new file mode 100644
index 0000000000000..2c1b9562b9567
--- /dev/null
+++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/_other_styles.scss
@@ -0,0 +1,3 @@
+p {
+ background-color: rebeccapurple;
+}
diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss
index e71a2d485a2f8..1dc7bbe9daeb0 100644
--- a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss
+++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss
@@ -1,3 +1,5 @@
+@import "./other_styles.scss";
+
body {
width: $globalStyleConstant;
background-image: url("ui/icon.svg");
diff --git a/packages/kbn-optimizer/src/cli.ts b/packages/kbn-optimizer/src/cli.ts
index 0916f12a7110d..9d3f4b88a258f 100644
--- a/packages/kbn-optimizer/src/cli.ts
+++ b/packages/kbn-optimizer/src/cli.ts
@@ -87,6 +87,11 @@ run(
throw createFlagError('expected --report-stats to have no value');
}
+ const filter = typeof flags.filter === 'string' ? [flags.filter] : flags.filter;
+ if (!Array.isArray(filter) || !filter.every((f) => typeof f === 'string')) {
+ throw createFlagError('expected --filter to be one or more strings');
+ }
+
const config = OptimizerConfig.create({
repoRoot: REPO_ROOT,
watch,
@@ -99,6 +104,7 @@ run(
extraPluginScanDirs,
inspectWorkers,
includeCoreBundle,
+ filter,
});
let update$ = runOptimizer(config);
@@ -128,12 +134,13 @@ run(
'inspect-workers',
'report-stats',
],
- string: ['workers', 'scan-dir'],
+ string: ['workers', 'scan-dir', 'filter'],
default: {
core: true,
examples: true,
cache: true,
'inspect-workers': true,
+ filter: [],
},
help: `
--watch run the optimizer in watch mode
@@ -142,6 +149,7 @@ run(
--profile profile the webpack builds and write stats.json files to build outputs
--no-core disable generating the core bundle
--no-cache disable the cache
+ --filter comma-separated list of bundle id filters, results from multiple flags are merged, * and ! are supported
--no-examples don't build the example plugins
--dist create bundles that are suitable for inclusion in the Kibana distributable
--scan-dir add a directory to the list of directories scanned for plugins (specify as many times as necessary)
diff --git a/packages/kbn-optimizer/src/common/bundle.test.ts b/packages/kbn-optimizer/src/common/bundle.test.ts
index b209bbca25ac4..6197a08485854 100644
--- a/packages/kbn-optimizer/src/common/bundle.test.ts
+++ b/packages/kbn-optimizer/src/common/bundle.test.ts
@@ -50,6 +50,7 @@ it('creates cache keys', () => {
"spec": Object {
"contextDir": "/foo/bar",
"id": "bar",
+ "manifestPath": undefined,
"outputDir": "/foo/bar/target",
"publicDirNames": Array [
"public",
@@ -85,6 +86,7 @@ it('parses bundles from JSON specs', () => {
},
"contextDir": "/foo/bar",
"id": "bar",
+ "manifestPath": undefined,
"outputDir": "/foo/bar/target",
"publicDirNames": Array [
"public",
diff --git a/packages/kbn-optimizer/src/common/bundle.ts b/packages/kbn-optimizer/src/common/bundle.ts
index 80af94c30f8da..a354da7a21521 100644
--- a/packages/kbn-optimizer/src/common/bundle.ts
+++ b/packages/kbn-optimizer/src/common/bundle.ts
@@ -18,6 +18,7 @@
*/
import Path from 'path';
+import Fs from 'fs';
import { BundleCache } from './bundle_cache';
import { UnknownVals } from './ts_helpers';
@@ -25,6 +26,11 @@ import { includes, ascending, entriesToObject } from './array_helpers';
const VALID_BUNDLE_TYPES = ['plugin' as const, 'entry' as const];
+const DEFAULT_IMPLICIT_BUNDLE_DEPS = ['core'];
+
+const isStringArray = (input: any): input is string[] =>
+ Array.isArray(input) && input.every((x) => typeof x === 'string');
+
export interface BundleSpec {
readonly type: typeof VALID_BUNDLE_TYPES[0];
/** Unique id for this bundle */
@@ -37,6 +43,8 @@ export interface BundleSpec {
readonly sourceRoot: string;
/** Absolute path to the directory where output should be written */
readonly outputDir: string;
+ /** Absolute path to a kibana.json manifest file, if omitted we assume there are not dependenices */
+ readonly manifestPath?: string;
}
export class Bundle {
@@ -56,6 +64,12 @@ export class Bundle {
public readonly sourceRoot: BundleSpec['sourceRoot'];
/** Absolute path to the output directory for this bundle */
public readonly outputDir: BundleSpec['outputDir'];
+ /**
+ * Absolute path to a manifest file with "requiredBundles" which will be
+ * used to allow bundleRefs from this bundle to the exports of another bundle.
+ * Every bundle mentioned in the `requiredBundles` must be built together.
+ */
+ public readonly manifestPath: BundleSpec['manifestPath'];
public readonly cache: BundleCache;
@@ -66,6 +80,7 @@ export class Bundle {
this.contextDir = spec.contextDir;
this.sourceRoot = spec.sourceRoot;
this.outputDir = spec.outputDir;
+ this.manifestPath = spec.manifestPath;
this.cache = new BundleCache(Path.resolve(this.outputDir, '.kbn-optimizer-cache'));
}
@@ -96,8 +111,54 @@ export class Bundle {
contextDir: this.contextDir,
sourceRoot: this.sourceRoot,
outputDir: this.outputDir,
+ manifestPath: this.manifestPath,
};
}
+
+ readBundleDeps(): { implicit: string[]; explicit: string[] } {
+ if (!this.manifestPath) {
+ return {
+ implicit: [...DEFAULT_IMPLICIT_BUNDLE_DEPS],
+ explicit: [],
+ };
+ }
+
+ let json: string;
+ try {
+ json = Fs.readFileSync(this.manifestPath, 'utf8');
+ } catch (error) {
+ if (error.code !== 'ENOENT') {
+ throw error;
+ }
+
+ json = '{}';
+ }
+
+ let parsedManifest: { requiredPlugins?: string[]; requiredBundles?: string[] };
+ try {
+ parsedManifest = JSON.parse(json);
+ } catch (error) {
+ throw new Error(
+ `unable to parse manifest at [${this.manifestPath}], error: [${error.message}]`
+ );
+ }
+
+ if (typeof parsedManifest === 'object' && parsedManifest) {
+ const explicit = parsedManifest.requiredBundles || [];
+ const implicit = [...DEFAULT_IMPLICIT_BUNDLE_DEPS, ...(parsedManifest.requiredPlugins || [])];
+
+ if (isStringArray(explicit) && isStringArray(implicit)) {
+ return {
+ explicit,
+ implicit,
+ };
+ }
+ }
+
+ throw new Error(
+ `Expected "requiredBundles" and "requiredPlugins" in manifest file [${this.manifestPath}] to be arrays of strings`
+ );
+ }
}
/**
@@ -152,6 +213,13 @@ export function parseBundles(json: string) {
throw new Error('`bundles[]` must have an absolute path `outputDir` property');
}
+ const { manifestPath } = spec;
+ if (manifestPath !== undefined) {
+ if (!(typeof manifestPath === 'string' && Path.isAbsolute(manifestPath))) {
+ throw new Error('`bundles[]` must have an absolute path `manifestPath` property');
+ }
+ }
+
return new Bundle({
type,
id,
@@ -159,6 +227,7 @@ export function parseBundles(json: string) {
contextDir,
sourceRoot,
outputDir,
+ manifestPath,
});
}
);
diff --git a/packages/kbn-optimizer/src/common/bundle_cache.ts b/packages/kbn-optimizer/src/common/bundle_cache.ts
index 5ae3e4c28a201..7607e270b5b4f 100644
--- a/packages/kbn-optimizer/src/common/bundle_cache.ts
+++ b/packages/kbn-optimizer/src/common/bundle_cache.ts
@@ -24,6 +24,7 @@ export interface State {
optimizerCacheKey?: unknown;
cacheKey?: unknown;
moduleCount?: number;
+ workUnits?: number;
files?: string[];
bundleRefExportIds?: string[];
}
@@ -96,6 +97,10 @@ export class BundleCache {
return this.get().cacheKey;
}
+ public getWorkUnits() {
+ return this.get().workUnits;
+ }
+
public getOptimizerCacheKey() {
return this.get().optimizerCacheKey;
}
diff --git a/packages/kbn-optimizer/src/common/bundle_refs.ts b/packages/kbn-optimizer/src/common/bundle_refs.ts
index a5c60f2031c0b..85731f32f8991 100644
--- a/packages/kbn-optimizer/src/common/bundle_refs.ts
+++ b/packages/kbn-optimizer/src/common/bundle_refs.ts
@@ -114,6 +114,10 @@ export class BundleRefs {
constructor(private readonly refs: BundleRef[]) {}
+ public forBundleIds(bundleIds: string[]) {
+ return this.refs.filter((r) => bundleIds.includes(r.bundleId));
+ }
+
public filterByExportIds(exportIds: string[]) {
return this.refs.filter((r) => exportIds.includes(r.exportId));
}
diff --git a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap
index 211cfac3806ad..c52873ab7ec20 100644
--- a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap
+++ b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap
@@ -10,6 +10,7 @@ OptimizerConfig {
},
"contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar,
"id": "bar",
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/kibana.json,
"outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/target/public,
"publicDirNames": Array [
"public",
@@ -24,6 +25,7 @@ OptimizerConfig {
},
"contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo,
"id": "foo",
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/kibana.json,
"outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/target/public,
"publicDirNames": Array [
"public",
@@ -42,18 +44,21 @@ OptimizerConfig {
"extraPublicDirs": Array [],
"id": "bar",
"isUiPlugin": true,
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/kibana.json,
},
Object {
"directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo,
"extraPublicDirs": Array [],
"id": "foo",
"isUiPlugin": true,
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/kibana.json,
},
Object {
"directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/nested/baz,
"extraPublicDirs": Array [],
"id": "baz",
"isUiPlugin": false,
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/nested/baz/kibana.json,
},
],
"profileWebpack": false,
@@ -66,7 +71,7 @@ OptimizerConfig {
}
`;
-exports[`prepares assets for distribution: bar bundle 1`] = `"(function(modules){var installedModules={};function __webpack_require__(moduleId){if(installedModules[moduleId]){return installedModules[moduleId].exports}var module=installedModules[moduleId]={i:moduleId,l:false,exports:{}};modules[moduleId].call(module.exports,module,module.exports,__webpack_require__);module.l=true;return module.exports}__webpack_require__.m=modules;__webpack_require__.c=installedModules;__webpack_require__.d=function(exports,name,getter){if(!__webpack_require__.o(exports,name)){Object.defineProperty(exports,name,{enumerable:true,get:getter})}};__webpack_require__.r=function(exports){if(typeof Symbol!==\\"undefined\\"&&Symbol.toStringTag){Object.defineProperty(exports,Symbol.toStringTag,{value:\\"Module\\"})}Object.defineProperty(exports,\\"__esModule\\",{value:true})};__webpack_require__.t=function(value,mode){if(mode&1)value=__webpack_require__(value);if(mode&8)return value;if(mode&4&&typeof value===\\"object\\"&&value&&value.__esModule)return value;var ns=Object.create(null);__webpack_require__.r(ns);Object.defineProperty(ns,\\"default\\",{enumerable:true,value:value});if(mode&2&&typeof value!=\\"string\\")for(var key in value)__webpack_require__.d(ns,key,function(key){return value[key]}.bind(null,key));return ns};__webpack_require__.n=function(module){var getter=module&&module.__esModule?function getDefault(){return module[\\"default\\"]}:function getModuleExports(){return module};__webpack_require__.d(getter,\\"a\\",getter);return getter};__webpack_require__.o=function(object,property){return Object.prototype.hasOwnProperty.call(object,property)};__webpack_require__.p=\\"\\";return __webpack_require__(__webpack_require__.s=5)})([function(module,exports,__webpack_require__){\\"use strict\\";var isOldIE=function isOldIE(){var memo;return function memorize(){if(typeof memo===\\"undefined\\"){memo=Boolean(window&&document&&document.all&&!window.atob)}return memo}}();var getTarget=function getTarget(){var memo={};return function memorize(target){if(typeof memo[target]===\\"undefined\\"){var styleTarget=document.querySelector(target);if(window.HTMLIFrameElement&&styleTarget instanceof window.HTMLIFrameElement){try{styleTarget=styleTarget.contentDocument.head}catch(e){styleTarget=null}}memo[target]=styleTarget}return memo[target]}}();var stylesInDom=[];function getIndexByIdentifier(identifier){var result=-1;for(var i=0;i {
expect(foo.cache.getModuleCount()).toBe(6);
expect(foo.cache.getReferencedFiles()).toMatchInlineSnapshot(`
Array [
+ /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/kibana.json,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/async_import.ts,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/ext.ts,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/index.ts,
@@ -160,12 +161,17 @@ it('builds expected bundles, saves bundle counts to metadata', async () => {
Array [
/node_modules/css-loader/package.json,
/node_modules/style-loader/package.json,
+ /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/kibana.json,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/index.scss,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/index.ts,
+ /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/legacy/_other_styles.scss,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/legacy/styles.scss,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/lib.ts,
/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/src/legacy/ui/public/icon.svg,
+ /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/src/legacy/ui/public/styles/_globals_v7dark.scss,
+ /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/src/legacy/ui/public/styles/_globals_v7light.scss,
/packages/kbn-optimizer/target/worker/entry_point_creator.js,
+ /packages/kbn-optimizer/target/worker/postcss.config.js,
/packages/kbn-ui-shared-deps/public_path_module_creator.js,
]
`);
diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts
index 23767be610da4..20d98f74dbe86 100644
--- a/packages/kbn-optimizer/src/log_optimizer_state.ts
+++ b/packages/kbn-optimizer/src/log_optimizer_state.ts
@@ -54,12 +54,18 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) {
if (event?.type === 'worker started') {
let moduleCount = 0;
+ let workUnits = 0;
for (const bundle of event.bundles) {
moduleCount += bundle.cache.getModuleCount() ?? NaN;
+ workUnits += bundle.cache.getWorkUnits() ?? NaN;
}
- const mcString = isFinite(moduleCount) ? String(moduleCount) : '?';
- const bcString = String(event.bundles.length);
- log.info(`starting worker [${bcString} bundles, ${mcString} modules]`);
+
+ log.info(
+ `starting worker [${event.bundles.length} ${
+ event.bundles.length === 1 ? 'bundle' : 'bundles'
+ }]`
+ );
+ log.debug(`modules [${moduleCount}] work units [${workUnits}]`);
}
if (state.phase === 'reallocating') {
diff --git a/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts
index ca50a49e26913..5443a88eb1a63 100644
--- a/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts
+++ b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts
@@ -23,11 +23,11 @@ import { Bundle } from '../common';
import { assignBundlesToWorkers, Assignments } from './assign_bundles_to_workers';
-const hasModuleCount = (b: Bundle) => b.cache.getModuleCount() !== undefined;
-const noModuleCount = (b: Bundle) => b.cache.getModuleCount() === undefined;
+const hasWorkUnits = (b: Bundle) => b.cache.getWorkUnits() !== undefined;
+const noWorkUnits = (b: Bundle) => b.cache.getWorkUnits() === undefined;
const summarizeBundles = (w: Assignments) =>
[
- w.moduleCount ? `${w.moduleCount} known modules` : '',
+ w.workUnits ? `${w.workUnits} work units` : '',
w.newBundles ? `${w.newBundles} new bundles` : '',
]
.filter(Boolean)
@@ -42,15 +42,15 @@ const assertReturnVal = (workers: Assignments[]) => {
expect(workers).toBeInstanceOf(Array);
for (const worker of workers) {
expect(worker).toEqual({
- moduleCount: expect.any(Number),
+ workUnits: expect.any(Number),
newBundles: expect.any(Number),
bundles: expect.any(Array),
});
- expect(worker.bundles.filter(noModuleCount).length).toBe(worker.newBundles);
+ expect(worker.bundles.filter(noWorkUnits).length).toBe(worker.newBundles);
expect(
- worker.bundles.filter(hasModuleCount).reduce((sum, b) => sum + b.cache.getModuleCount()!, 0)
- ).toBe(worker.moduleCount);
+ worker.bundles.filter(hasWorkUnits).reduce((sum, b) => sum + b.cache.getWorkUnits()!, 0)
+ ).toBe(worker.workUnits);
}
};
@@ -76,7 +76,7 @@ const getBundles = ({
for (let i = 1; i <= withCounts; i++) {
const id = `foo${i}`;
const bundle = testBundle(id);
- bundle.cache.set({ moduleCount: i % 5 === 0 ? i * 10 : i });
+ bundle.cache.set({ workUnits: i % 5 === 0 ? i * 10 : i });
bundles.push(bundle);
}
@@ -95,8 +95,8 @@ it('creates less workers if maxWorkersCount is larger than bundle count', () =>
expect(workers.length).toBe(2);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (1 known modules) => foo1",
- "worker 1 (2 known modules) => foo2",
+ "worker 0 (1 work units) => foo1",
+ "worker 1 (2 work units) => foo2",
]
`);
});
@@ -121,10 +121,10 @@ it('distributes bundles without module counts evenly after assigning modules wit
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (78 known modules, 3 new bundles) => foo5,foo11,foo8,foo6,foo2,foo1,bar9,bar5,bar1",
- "worker 1 (78 known modules, 3 new bundles) => foo16,foo14,foo13,foo12,foo9,foo7,foo4,foo3,bar8,bar4,bar0",
- "worker 2 (100 known modules, 2 new bundles) => foo10,bar7,bar3",
- "worker 3 (150 known modules, 2 new bundles) => foo15,bar6,bar2",
+ "worker 0 (78 work units, 3 new bundles) => foo5,foo11,foo8,foo6,foo2,foo1,bar9,bar5,bar1",
+ "worker 1 (78 work units, 3 new bundles) => foo16,foo14,foo13,foo12,foo9,foo7,foo4,foo3,bar8,bar4,bar0",
+ "worker 2 (100 work units, 2 new bundles) => foo10,bar7,bar3",
+ "worker 3 (150 work units, 2 new bundles) => foo15,bar6,bar2",
]
`);
});
@@ -135,8 +135,8 @@ it('distributes 2 bundles to workers evenly', () => {
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (1 known modules) => foo1",
- "worker 1 (2 known modules) => foo2",
+ "worker 0 (1 work units) => foo1",
+ "worker 1 (2 work units) => foo2",
]
`);
});
@@ -147,10 +147,10 @@ it('distributes 5 bundles to workers evenly', () => {
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (3 known modules) => foo2,foo1",
- "worker 1 (3 known modules) => foo3",
- "worker 2 (4 known modules) => foo4",
- "worker 3 (50 known modules) => foo5",
+ "worker 0 (3 work units) => foo2,foo1",
+ "worker 1 (3 work units) => foo3",
+ "worker 2 (4 work units) => foo4",
+ "worker 3 (50 work units) => foo5",
]
`);
});
@@ -161,10 +161,10 @@ it('distributes 10 bundles to workers evenly', () => {
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (20 known modules) => foo9,foo6,foo4,foo1",
- "worker 1 (20 known modules) => foo8,foo7,foo3,foo2",
- "worker 2 (50 known modules) => foo5",
- "worker 3 (100 known modules) => foo10",
+ "worker 0 (20 work units) => foo9,foo6,foo4,foo1",
+ "worker 1 (20 work units) => foo8,foo7,foo3,foo2",
+ "worker 2 (50 work units) => foo5",
+ "worker 3 (100 work units) => foo10",
]
`);
});
@@ -175,10 +175,10 @@ it('distributes 15 bundles to workers evenly', () => {
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (70 known modules) => foo14,foo13,foo12,foo11,foo9,foo6,foo4,foo1",
- "worker 1 (70 known modules) => foo5,foo8,foo7,foo3,foo2",
- "worker 2 (100 known modules) => foo10",
- "worker 3 (150 known modules) => foo15",
+ "worker 0 (70 work units) => foo14,foo13,foo12,foo11,foo9,foo6,foo4,foo1",
+ "worker 1 (70 work units) => foo5,foo8,foo7,foo3,foo2",
+ "worker 2 (100 work units) => foo10",
+ "worker 3 (150 work units) => foo15",
]
`);
});
@@ -189,10 +189,10 @@ it('distributes 20 bundles to workers evenly', () => {
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (153 known modules) => foo15,foo3",
- "worker 1 (153 known modules) => foo10,foo16,foo13,foo11,foo7,foo6",
- "worker 2 (154 known modules) => foo5,foo19,foo18,foo17,foo14,foo12,foo9,foo8,foo4,foo2,foo1",
- "worker 3 (200 known modules) => foo20",
+ "worker 0 (153 work units) => foo15,foo3",
+ "worker 1 (153 work units) => foo10,foo16,foo13,foo11,foo7,foo6",
+ "worker 2 (154 work units) => foo5,foo19,foo18,foo17,foo14,foo12,foo9,foo8,foo4,foo2,foo1",
+ "worker 3 (200 work units) => foo20",
]
`);
});
@@ -203,10 +203,10 @@ it('distributes 25 bundles to workers evenly', () => {
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (250 known modules) => foo20,foo17,foo13,foo9,foo8,foo2,foo1",
- "worker 1 (250 known modules) => foo15,foo23,foo22,foo18,foo16,foo11,foo7,foo3",
- "worker 2 (250 known modules) => foo10,foo5,foo24,foo21,foo19,foo14,foo12,foo6,foo4",
- "worker 3 (250 known modules) => foo25",
+ "worker 0 (250 work units) => foo20,foo17,foo13,foo9,foo8,foo2,foo1",
+ "worker 1 (250 work units) => foo15,foo23,foo22,foo18,foo16,foo11,foo7,foo3",
+ "worker 2 (250 work units) => foo10,foo5,foo24,foo21,foo19,foo14,foo12,foo6,foo4",
+ "worker 3 (250 work units) => foo25",
]
`);
});
@@ -217,10 +217,10 @@ it('distributes 30 bundles to workers evenly', () => {
assertReturnVal(workers);
expect(readConfigs(workers)).toMatchInlineSnapshot(`
Array [
- "worker 0 (352 known modules) => foo30,foo22,foo14,foo11,foo4,foo1",
- "worker 1 (352 known modules) => foo15,foo10,foo28,foo24,foo19,foo16,foo9,foo6",
- "worker 2 (353 known modules) => foo20,foo5,foo29,foo23,foo21,foo13,foo12,foo3,foo2",
- "worker 3 (353 known modules) => foo25,foo27,foo26,foo18,foo17,foo8,foo7",
+ "worker 0 (352 work units) => foo30,foo22,foo14,foo11,foo4,foo1",
+ "worker 1 (352 work units) => foo15,foo10,foo28,foo24,foo19,foo16,foo9,foo6",
+ "worker 2 (353 work units) => foo20,foo5,foo29,foo23,foo21,foo13,foo12,foo3,foo2",
+ "worker 3 (353 work units) => foo25,foo27,foo26,foo18,foo17,foo8,foo7",
]
`);
});
diff --git a/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts
index e1bcb22230bf9..44a3b21c5fd47 100644
--- a/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts
+++ b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts
@@ -20,19 +20,18 @@
import { Bundle, descending, ascending } from '../common';
// helper types used inside getWorkerConfigs so we don't have
-// to calculate moduleCounts over and over
-
+// to calculate workUnits over and over
export interface Assignments {
- moduleCount: number;
+ workUnits: number;
newBundles: number;
bundles: Bundle[];
}
/** assign a wrapped bundle to a worker */
const assignBundle = (worker: Assignments, bundle: Bundle) => {
- const moduleCount = bundle.cache.getModuleCount();
- if (moduleCount !== undefined) {
- worker.moduleCount += moduleCount;
+ const workUnits = bundle.cache.getWorkUnits();
+ if (workUnits !== undefined) {
+ worker.workUnits += workUnits;
} else {
worker.newBundles += 1;
}
@@ -59,7 +58,7 @@ export function assignBundlesToWorkers(bundles: Bundle[], maxWorkerCount: number
const workers: Assignments[] = [];
for (let i = 0; i < workerCount; i++) {
workers.push({
- moduleCount: 0,
+ workUnits: 0,
newBundles: 0,
bundles: [],
});
@@ -67,18 +66,18 @@ export function assignBundlesToWorkers(bundles: Bundle[], maxWorkerCount: number
/**
* separate the bundles which do and don't have module
- * counts and sort them by [moduleCount, id]
+ * counts and sort them by [workUnits, id]
*/
const bundlesWithCountsDesc = bundles
- .filter((b) => b.cache.getModuleCount() !== undefined)
+ .filter((b) => b.cache.getWorkUnits() !== undefined)
.sort(
descending(
- (b) => b.cache.getModuleCount(),
+ (b) => b.cache.getWorkUnits(),
(b) => b.id
)
);
const bundlesWithoutModuleCounts = bundles
- .filter((b) => b.cache.getModuleCount() === undefined)
+ .filter((b) => b.cache.getWorkUnits() === undefined)
.sort(descending((b) => b.id));
/**
@@ -87,9 +86,9 @@ export function assignBundlesToWorkers(bundles: Bundle[], maxWorkerCount: number
* with module counts are assigned
*/
while (bundlesWithCountsDesc.length) {
- const [smallestWorker, nextSmallestWorker] = workers.sort(ascending((w) => w.moduleCount));
+ const [smallestWorker, nextSmallestWorker] = workers.sort(ascending((w) => w.workUnits));
- while (!nextSmallestWorker || smallestWorker.moduleCount <= nextSmallestWorker.moduleCount) {
+ while (!nextSmallestWorker || smallestWorker.workUnits <= nextSmallestWorker.workUnits) {
const bundle = bundlesWithCountsDesc.shift();
if (!bundle) {
@@ -104,7 +103,7 @@ export function assignBundlesToWorkers(bundles: Bundle[], maxWorkerCount: number
* assign bundles without module counts to workers round-robin
* starting with the smallest workers
*/
- workers.sort(ascending((w) => w.moduleCount));
+ workers.sort(ascending((w) => w.workUnits));
while (bundlesWithoutModuleCounts.length) {
for (const worker of workers) {
const bundle = bundlesWithoutModuleCounts.shift();
diff --git a/packages/kbn-optimizer/src/optimizer/filter_by_id.test.ts b/packages/kbn-optimizer/src/optimizer/filter_by_id.test.ts
new file mode 100644
index 0000000000000..3e848fe616b49
--- /dev/null
+++ b/packages/kbn-optimizer/src/optimizer/filter_by_id.test.ts
@@ -0,0 +1,72 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { filterById, HasId } from './filter_by_id';
+
+const bundles: HasId[] = [
+ { id: 'foo' },
+ { id: 'bar' },
+ { id: 'abc' },
+ { id: 'abcd' },
+ { id: 'abcde' },
+ { id: 'example_a' },
+];
+
+const print = (result: HasId[]) =>
+ result
+ .map((b) => b.id)
+ .sort((a, b) => a.localeCompare(b))
+ .join(', ');
+
+it('[] matches everything', () => {
+ expect(print(filterById([], bundles))).toMatchInlineSnapshot(
+ `"abc, abcd, abcde, bar, example_a, foo"`
+ );
+});
+
+it('* matches everything', () => {
+ expect(print(filterById(['*'], bundles))).toMatchInlineSnapshot(
+ `"abc, abcd, abcde, bar, example_a, foo"`
+ );
+});
+
+it('combines mutliple filters to select any bundle which is matched', () => {
+ expect(print(filterById(['foo', 'bar'], bundles))).toMatchInlineSnapshot(`"bar, foo"`);
+ expect(print(filterById(['bar', 'abc*'], bundles))).toMatchInlineSnapshot(
+ `"abc, abcd, abcde, bar"`
+ );
+});
+
+it('matches everything if any filter is *', () => {
+ expect(print(filterById(['*', '!abc*'], bundles))).toMatchInlineSnapshot(
+ `"abc, abcd, abcde, bar, example_a, foo"`
+ );
+});
+
+it('only matches bundles which are matched by an entire single filter', () => {
+ expect(print(filterById(['*,!abc*'], bundles))).toMatchInlineSnapshot(`"bar, example_a, foo"`);
+});
+
+it('handles purely positive filters', () => {
+ expect(print(filterById(['abc*'], bundles))).toMatchInlineSnapshot(`"abc, abcd, abcde"`);
+});
+
+it('handles purely negative filters', () => {
+ expect(print(filterById(['!abc*'], bundles))).toMatchInlineSnapshot(`"bar, example_a, foo"`);
+});
diff --git a/packages/kbn-optimizer/src/optimizer/filter_by_id.ts b/packages/kbn-optimizer/src/optimizer/filter_by_id.ts
new file mode 100644
index 0000000000000..ccf61a9efc880
--- /dev/null
+++ b/packages/kbn-optimizer/src/optimizer/filter_by_id.ts
@@ -0,0 +1,48 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export interface HasId {
+ id: string;
+}
+
+function parseFilter(filter: string) {
+ const positive: RegExp[] = [];
+ const negative: RegExp[] = [];
+
+ for (const segment of filter.split(',')) {
+ let trimmed = segment.trim();
+ let list = positive;
+
+ if (trimmed.startsWith('!')) {
+ trimmed = trimmed.slice(1);
+ list = negative;
+ }
+
+ list.push(new RegExp(`^${trimmed.split('*').join('.*')}$`));
+ }
+
+ return (bundle: HasId) =>
+ (!positive.length || positive.some((p) => p.test(bundle.id))) &&
+ (!negative.length || !negative.some((p) => p.test(bundle.id)));
+}
+
+export function filterById(filterStrings: string[], bundles: T[]) {
+ const filters = filterStrings.map(parseFilter);
+ return bundles.filter((b) => !filters.length || filters.some((f) => f(b)));
+}
diff --git a/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.test.ts b/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.test.ts
index bbd3ddc11f448..a70cfc759dd55 100644
--- a/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.test.ts
+++ b/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.test.ts
@@ -32,18 +32,21 @@ it('returns a bundle for core and each plugin', () => {
id: 'foo',
isUiPlugin: true,
extraPublicDirs: [],
+ manifestPath: '/repo/plugins/foo/kibana.json',
},
{
directory: '/repo/plugins/bar',
id: 'bar',
isUiPlugin: false,
extraPublicDirs: [],
+ manifestPath: '/repo/plugins/bar/kibana.json',
},
{
directory: '/outside/of/repo/plugins/baz',
id: 'baz',
isUiPlugin: true,
extraPublicDirs: [],
+ manifestPath: '/outside/of/repo/plugins/baz/kibana.json',
},
],
'/repo'
@@ -53,6 +56,7 @@ it('returns a bundle for core and each plugin', () => {
Object {
"contextDir": /plugins/foo,
"id": "foo",
+ "manifestPath": /plugins/foo/kibana.json,
"outputDir": /plugins/foo/target/public,
"publicDirNames": Array [
"public",
@@ -63,6 +67,7 @@ it('returns a bundle for core and each plugin', () => {
Object {
"contextDir": "/outside/of/repo/plugins/baz",
"id": "baz",
+ "manifestPath": "/outside/of/repo/plugins/baz/kibana.json",
"outputDir": "/outside/of/repo/plugins/baz/target/public",
"publicDirNames": Array [
"public",
diff --git a/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.ts b/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.ts
index 2635289088725..04ab992addeec 100644
--- a/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.ts
+++ b/packages/kbn-optimizer/src/optimizer/get_plugin_bundles.ts
@@ -35,6 +35,7 @@ export function getPluginBundles(plugins: KibanaPlatformPlugin[], repoRoot: stri
sourceRoot: repoRoot,
contextDir: p.directory,
outputDir: Path.resolve(p.directory, 'target/public'),
+ manifestPath: p.manifestPath,
})
);
}
diff --git a/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts
index f7b457ca42c6d..06fffc953f58b 100644
--- a/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts
+++ b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts
@@ -40,24 +40,28 @@ it('parses kibana.json files of plugins found in pluginDirs', () => {
"extraPublicDirs": Array [],
"id": "bar",
"isUiPlugin": true,
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json,
},
Object {
"directory": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo,
"extraPublicDirs": Array [],
"id": "foo",
"isUiPlugin": true,
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/kibana.json,
},
Object {
"directory": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz,
"extraPublicDirs": Array [],
"id": "baz",
"isUiPlugin": false,
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz/kibana.json,
},
Object {
"directory": /packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz,
"extraPublicDirs": Array [],
"id": "test_baz",
"isUiPlugin": false,
+ "manifestPath": /packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/kibana.json,
},
]
`);
diff --git a/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts
index 83637691004f4..b489c53be47b9 100644
--- a/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts
+++ b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts
@@ -24,6 +24,7 @@ import loadJsonFile from 'load-json-file';
export interface KibanaPlatformPlugin {
readonly directory: string;
+ readonly manifestPath: string;
readonly id: string;
readonly isUiPlugin: boolean;
readonly extraPublicDirs: string[];
@@ -92,6 +93,7 @@ function readKibanaPlatformPlugin(manifestPath: string): KibanaPlatformPlugin {
return {
directory: Path.dirname(manifestPath),
+ manifestPath,
id: manifest.id,
isUiPlugin: !!manifest.ui,
extraPublicDirs: extraPublicDirs || [],
diff --git a/packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts b/packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts
index 5b46d67479fd5..f97646e2bbbd3 100644
--- a/packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts
+++ b/packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts
@@ -21,6 +21,7 @@ jest.mock('./assign_bundles_to_workers.ts');
jest.mock('./kibana_platform_plugins.ts');
jest.mock('./get_plugin_bundles.ts');
jest.mock('../common/theme_tags.ts');
+jest.mock('./filter_by_id.ts');
import Path from 'path';
import Os from 'os';
@@ -113,6 +114,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": true,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@@ -139,6 +141,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": false,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@@ -165,6 +168,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": true,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@@ -193,6 +197,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": true,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@@ -218,6 +223,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": true,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 2,
@@ -243,6 +249,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": true,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@@ -265,6 +272,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": false,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@@ -287,6 +295,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": false,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@@ -310,6 +319,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": false,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@@ -333,6 +343,7 @@ describe('OptimizerConfig::parseOptions()', () => {
Object {
"cache": true,
"dist": false,
+ "filters": Array [],
"includeCoreBundle": false,
"inspectWorkers": false,
"maxWorkerCount": 100,
@@ -358,6 +369,7 @@ describe('OptimizerConfig::create()', () => {
const findKibanaPlatformPlugins: jest.Mock = jest.requireMock('./kibana_platform_plugins.ts')
.findKibanaPlatformPlugins;
const getPluginBundles: jest.Mock = jest.requireMock('./get_plugin_bundles.ts').getPluginBundles;
+ const filterById: jest.Mock = jest.requireMock('./filter_by_id.ts').filterById;
beforeEach(() => {
if ('mock' in OptimizerConfig.parseOptions) {
@@ -370,6 +382,7 @@ describe('OptimizerConfig::create()', () => {
]);
findKibanaPlatformPlugins.mockReturnValue(Symbol('new platform plugins'));
getPluginBundles.mockReturnValue([Symbol('bundle1'), Symbol('bundle2')]);
+ filterById.mockReturnValue(Symbol('filtered bundles'));
jest.spyOn(OptimizerConfig, 'parseOptions').mockImplementation((): any => ({
cache: Symbol('parsed cache'),
@@ -382,6 +395,7 @@ describe('OptimizerConfig::create()', () => {
themeTags: Symbol('theme tags'),
inspectWorkers: Symbol('parsed inspect workers'),
profileWebpack: Symbol('parsed profile webpack'),
+ filters: [],
}));
});
@@ -392,10 +406,7 @@ describe('OptimizerConfig::create()', () => {
expect(config).toMatchInlineSnapshot(`
OptimizerConfig {
- "bundles": Array [
- Symbol(bundle1),
- Symbol(bundle2),
- ],
+ "bundles": Symbol(filtered bundles),
"cache": Symbol(parsed cache),
"dist": Symbol(parsed dist),
"inspectWorkers": Symbol(parsed inspect workers),
@@ -431,6 +442,32 @@ describe('OptimizerConfig::create()', () => {
}
`);
+ expect(filterById.mock).toMatchInlineSnapshot(`
+ Object {
+ "calls": Array [
+ Array [
+ Array [],
+ Array [
+ Symbol(bundle1),
+ Symbol(bundle2),
+ ],
+ ],
+ ],
+ "instances": Array [
+ [Window],
+ ],
+ "invocationCallOrder": Array [
+ 23,
+ ],
+ "results": Array [
+ Object {
+ "type": "return",
+ "value": Symbol(filtered bundles),
+ },
+ ],
+ }
+ `);
+
expect(getPluginBundles.mock).toMatchInlineSnapshot(`
Object {
"calls": Array [
diff --git a/packages/kbn-optimizer/src/optimizer/optimizer_config.ts b/packages/kbn-optimizer/src/optimizer/optimizer_config.ts
index 7757004139d0d..0e588ab36238b 100644
--- a/packages/kbn-optimizer/src/optimizer/optimizer_config.ts
+++ b/packages/kbn-optimizer/src/optimizer/optimizer_config.ts
@@ -31,6 +31,7 @@ import {
import { findKibanaPlatformPlugins, KibanaPlatformPlugin } from './kibana_platform_plugins';
import { getPluginBundles } from './get_plugin_bundles';
+import { filterById } from './filter_by_id';
function pickMaxWorkerCount(dist: boolean) {
// don't break if cpus() returns nothing, or an empty array
@@ -77,6 +78,18 @@ interface Options {
pluginScanDirs?: string[];
/** absolute paths that should be added to the default scan dirs */
extraPluginScanDirs?: string[];
+ /**
+ * array of comma separated patterns that will be matched against bundle ids.
+ * bundles will only be built if they match one of the specified patterns.
+ * `*` can exist anywhere in each pattern and will match anything, `!` inverts the pattern
+ *
+ * examples:
+ * --filter foo --filter bar # [foo, bar], excludes [foobar]
+ * --filter foo,bar # [foo, bar], excludes [foobar]
+ * --filter foo* # [foo, foobar], excludes [bar]
+ * --filter f*r # [foobar], excludes [foo, bar]
+ */
+ filter?: string[];
/** flag that causes the core bundle to be built along with plugins */
includeCoreBundle?: boolean;
@@ -103,6 +116,7 @@ interface ParsedOptions {
dist: boolean;
pluginPaths: string[];
pluginScanDirs: string[];
+ filters: string[];
inspectWorkers: boolean;
includeCoreBundle: boolean;
themeTags: ThemeTags;
@@ -118,6 +132,7 @@ export class OptimizerConfig {
const inspectWorkers = !!options.inspectWorkers;
const cache = options.cache !== false && !process.env.KBN_OPTIMIZER_NO_CACHE;
const includeCoreBundle = !!options.includeCoreBundle;
+ const filters = options.filter || [];
const repoRoot = options.repoRoot;
if (!Path.isAbsolute(repoRoot)) {
@@ -172,6 +187,7 @@ export class OptimizerConfig {
cache,
pluginScanDirs,
pluginPaths,
+ filters,
inspectWorkers,
includeCoreBundle,
themeTags,
@@ -198,7 +214,7 @@ export class OptimizerConfig {
];
return new OptimizerConfig(
- bundles,
+ filterById(options.filters, bundles),
options.cache,
options.watch,
options.inspectWorkers,
diff --git a/packages/kbn-optimizer/src/worker/bundle_ref_module.ts b/packages/kbn-optimizer/src/worker/bundle_ref_module.ts
index cde25564cf528..563b4ecb4bc37 100644
--- a/packages/kbn-optimizer/src/worker/bundle_ref_module.ts
+++ b/packages/kbn-optimizer/src/worker/bundle_ref_module.ts
@@ -10,6 +10,7 @@
// @ts-ignore not typed by @types/webpack
import Module from 'webpack/lib/Module';
+import { BundleRef } from '../common';
export class BundleRefModule extends Module {
public built = false;
@@ -17,12 +18,12 @@ export class BundleRefModule extends Module {
public buildInfo?: any;
public exportsArgument = '__webpack_exports__';
- constructor(public readonly exportId: string) {
+ constructor(public readonly ref: BundleRef) {
super('kbn/bundleRef', null);
}
libIdent() {
- return this.exportId;
+ return this.ref.exportId;
}
chunkCondition(chunk: any) {
@@ -30,7 +31,7 @@ export class BundleRefModule extends Module {
}
identifier() {
- return '@kbn/bundleRef ' + JSON.stringify(this.exportId);
+ return '@kbn/bundleRef ' + JSON.stringify(this.ref.exportId);
}
readableIdentifier() {
@@ -51,7 +52,7 @@ export class BundleRefModule extends Module {
source() {
return `
__webpack_require__.r(__webpack_exports__);
- var ns = __kbnBundles__.get('${this.exportId}');
+ var ns = __kbnBundles__.get('${this.ref.exportId}');
Object.defineProperties(__webpack_exports__, Object.getOwnPropertyDescriptors(ns))
`;
}
diff --git a/packages/kbn-optimizer/src/worker/bundle_refs_plugin.ts b/packages/kbn-optimizer/src/worker/bundle_refs_plugin.ts
index 9c4d5ed7f8a98..5396d11726f7a 100644
--- a/packages/kbn-optimizer/src/worker/bundle_refs_plugin.ts
+++ b/packages/kbn-optimizer/src/worker/bundle_refs_plugin.ts
@@ -44,6 +44,7 @@ export class BundleRefsPlugin {
private readonly resolvedRefEntryCache = new Map>();
private readonly resolvedRequestCache = new Map>();
private readonly ignorePrefix = Path.resolve(this.bundle.contextDir) + Path.sep;
+ private allowedBundleIds = new Set();
constructor(private readonly bundle: Bundle, private readonly bundleRefs: BundleRefs) {}
@@ -81,6 +82,45 @@ export class BundleRefsPlugin {
}
);
});
+
+ compiler.hooks.compilation.tap('BundleRefsPlugin/getRequiredBundles', (compilation) => {
+ this.allowedBundleIds.clear();
+
+ const manifestPath = this.bundle.manifestPath;
+ if (!manifestPath) {
+ return;
+ }
+
+ const deps = this.bundle.readBundleDeps();
+ for (const ref of this.bundleRefs.forBundleIds([...deps.explicit, ...deps.implicit])) {
+ this.allowedBundleIds.add(ref.bundleId);
+ }
+
+ compilation.hooks.additionalAssets.tap('BundleRefsPlugin/watchManifest', () => {
+ compilation.fileDependencies.add(manifestPath);
+ });
+
+ compilation.hooks.finishModules.tapPromise(
+ 'BundleRefsPlugin/finishModules',
+ async (modules) => {
+ const usedBundleIds = (modules as any[])
+ .filter((m: any): m is BundleRefModule => m instanceof BundleRefModule)
+ .map((m) => m.ref.bundleId);
+
+ const unusedBundleIds = deps.explicit
+ .filter((id) => !usedBundleIds.includes(id))
+ .join(', ');
+
+ if (unusedBundleIds) {
+ const error = new Error(
+ `Bundle for [${this.bundle.id}] lists [${unusedBundleIds}] as a required bundle, but does not use it. Please remove it.`
+ );
+ (error as any).file = manifestPath;
+ compilation.errors.push(error);
+ }
+ }
+ );
+ });
}
private cachedResolveRefEntry(ref: BundleRef) {
@@ -170,21 +210,29 @@ export class BundleRefsPlugin {
return;
}
- const eligibleRefs = this.bundleRefs.filterByContextPrefix(this.bundle, resolved);
- if (!eligibleRefs.length) {
+ const possibleRefs = this.bundleRefs.filterByContextPrefix(this.bundle, resolved);
+ if (!possibleRefs.length) {
// import doesn't match a bundle context
return;
}
- for (const ref of eligibleRefs) {
+ for (const ref of possibleRefs) {
const resolvedEntry = await this.cachedResolveRefEntry(ref);
- if (resolved === resolvedEntry) {
- return new BundleRefModule(ref.exportId);
+ if (resolved !== resolvedEntry) {
+ continue;
}
+
+ if (!this.allowedBundleIds.has(ref.bundleId)) {
+ throw new Error(
+ `import [${request}] references a public export of the [${ref.bundleId}] bundle, but that bundle is not in the "requiredPlugins" or "requiredBundles" list in the plugin manifest [${this.bundle.manifestPath}]`
+ );
+ }
+
+ return new BundleRefModule(ref);
}
- const bundleId = Array.from(new Set(eligibleRefs.map((r) => r.bundleId))).join(', ');
- const publicDir = eligibleRefs.map((r) => r.entry).join(', ');
+ const bundleId = Array.from(new Set(possibleRefs.map((r) => r.bundleId))).join(', ');
+ const publicDir = possibleRefs.map((r) => r.entry).join(', ');
throw new Error(
`import [${request}] references a non-public export of the [${bundleId}] bundle and must point to one of the public directories: [${publicDir}]`
);
diff --git a/packages/kbn-optimizer/src/worker/run_compilers.ts b/packages/kbn-optimizer/src/worker/run_compilers.ts
index ca7673748bde9..c7be943d65a48 100644
--- a/packages/kbn-optimizer/src/worker/run_compilers.ts
+++ b/packages/kbn-optimizer/src/worker/run_compilers.ts
@@ -50,6 +50,15 @@ import {
const PLUGIN_NAME = '@kbn/optimizer';
+/**
+ * sass-loader creates about a 40% overhead on the overall optimizer runtime, and
+ * so this constant is used to indicate to assignBundlesToWorkers() that there is
+ * extra work done in a bundle that has a lot of scss imports. The value is
+ * arbitrary and just intended to weigh the bundles so that they are distributed
+ * across mulitple workers on machines with lots of cores.
+ */
+const EXTRA_SCSS_WORK_UNITS = 100;
+
/**
* Create an Observable for a specific child compiler + bundle
*/
@@ -102,6 +111,11 @@ const observeCompiler = (
const bundleRefExportIds: string[] = [];
const referencedFiles = new Set();
let normalModuleCount = 0;
+ let workUnits = stats.compilation.fileDependencies.size;
+
+ if (bundle.manifestPath) {
+ referencedFiles.add(bundle.manifestPath);
+ }
for (const module of stats.compilation.modules) {
if (isNormalModule(module)) {
@@ -111,6 +125,15 @@ const observeCompiler = (
if (!parsedPath.dirs.includes('node_modules')) {
referencedFiles.add(path);
+
+ if (path.endsWith('.scss')) {
+ workUnits += EXTRA_SCSS_WORK_UNITS;
+
+ for (const depPath of module.buildInfo.fileDependencies) {
+ referencedFiles.add(depPath);
+ }
+ }
+
continue;
}
@@ -127,7 +150,7 @@ const observeCompiler = (
}
if (module instanceof BundleRefModule) {
- bundleRefExportIds.push(module.exportId);
+ bundleRefExportIds.push(module.ref.exportId);
continue;
}
@@ -158,6 +181,7 @@ const observeCompiler = (
optimizerCacheKey: workerConfig.optimizerCacheKey,
cacheKey: bundle.createCacheKey(files, mtimes),
moduleCount: normalModuleCount,
+ workUnits,
files,
});
diff --git a/src/core/public/plugins/plugin.test.ts b/src/core/public/plugins/plugin.test.ts
index 3f77161f8c34d..7331157951dec 100644
--- a/src/core/public/plugins/plugin.test.ts
+++ b/src/core/public/plugins/plugin.test.ts
@@ -32,6 +32,7 @@ function createManifest(
configPath: ['path'],
requiredPlugins: required,
optionalPlugins: optional,
+ requiredBundles: [],
} as DiscoveredPlugin;
}
diff --git a/src/core/public/plugins/plugins_service.test.ts b/src/core/public/plugins/plugins_service.test.ts
index 7dc5f3655fca0..28cbfce3fd651 100644
--- a/src/core/public/plugins/plugins_service.test.ts
+++ b/src/core/public/plugins/plugins_service.test.ts
@@ -73,6 +73,7 @@ function createManifest(
configPath: ['path'],
requiredPlugins: required,
optionalPlugins: optional,
+ requiredBundles: [],
};
}
diff --git a/src/core/server/legacy/legacy_service.test.ts b/src/core/server/legacy/legacy_service.test.ts
index ae4cf612e92ce..f8f04c59766b3 100644
--- a/src/core/server/legacy/legacy_service.test.ts
+++ b/src/core/server/legacy/legacy_service.test.ts
@@ -109,6 +109,7 @@ beforeEach(() => {
[
'plugin-id',
{
+ requiredBundles: [],
publicTargetDir: 'path/to/target/public',
publicAssetsDir: '/plugins/name/assets/',
},
diff --git a/src/core/server/plugins/discovery/plugin_manifest_parser.test.ts b/src/core/server/plugins/discovery/plugin_manifest_parser.test.ts
index 5ffdef88104c8..64d1256be2f30 100644
--- a/src/core/server/plugins/discovery/plugin_manifest_parser.test.ts
+++ b/src/core/server/plugins/discovery/plugin_manifest_parser.test.ts
@@ -302,6 +302,7 @@ test('set defaults for all missing optional fields', async () => {
kibanaVersion: '7.0.0',
optionalPlugins: [],
requiredPlugins: [],
+ requiredBundles: [],
server: true,
ui: false,
});
@@ -331,6 +332,7 @@ test('return all set optional fields as they are in manifest', async () => {
version: 'some-version',
kibanaVersion: '7.0.0',
optionalPlugins: ['some-optional-plugin'],
+ requiredBundles: [],
requiredPlugins: ['some-required-plugin', 'some-required-plugin-2'],
server: false,
ui: true,
@@ -361,6 +363,7 @@ test('return manifest when plugin expected Kibana version matches actual version
kibanaVersion: '7.0.0-alpha2',
optionalPlugins: [],
requiredPlugins: ['some-required-plugin'],
+ requiredBundles: [],
server: true,
ui: false,
});
@@ -390,6 +393,7 @@ test('return manifest when plugin expected Kibana version is `kibana`', async ()
kibanaVersion: 'kibana',
optionalPlugins: [],
requiredPlugins: ['some-required-plugin'],
+ requiredBundles: [],
server: true,
ui: true,
});
diff --git a/src/core/server/plugins/discovery/plugin_manifest_parser.ts b/src/core/server/plugins/discovery/plugin_manifest_parser.ts
index f2c3a29eca0ac..0d33e266c37db 100644
--- a/src/core/server/plugins/discovery/plugin_manifest_parser.ts
+++ b/src/core/server/plugins/discovery/plugin_manifest_parser.ts
@@ -58,6 +58,7 @@ const KNOWN_MANIFEST_FIELDS = (() => {
ui: true,
server: true,
extraPublicDirs: true,
+ requiredBundles: true,
};
return new Set(Object.keys(manifestFields));
@@ -191,6 +192,7 @@ export async function parseManifest(
configPath: manifest.configPath || snakeCase(manifest.id),
requiredPlugins: Array.isArray(manifest.requiredPlugins) ? manifest.requiredPlugins : [],
optionalPlugins: Array.isArray(manifest.optionalPlugins) ? manifest.optionalPlugins : [],
+ requiredBundles: Array.isArray(manifest.requiredBundles) ? manifest.requiredBundles : [],
ui: includesUiPlugin,
server: includesServerPlugin,
extraPublicDirs: manifest.extraPublicDirs,
diff --git a/src/core/server/plugins/integration_tests/plugins_service.test.ts b/src/core/server/plugins/integration_tests/plugins_service.test.ts
index e676c789449ca..49c129d0ae67d 100644
--- a/src/core/server/plugins/integration_tests/plugins_service.test.ts
+++ b/src/core/server/plugins/integration_tests/plugins_service.test.ts
@@ -43,6 +43,7 @@ describe('PluginsService', () => {
disabled = false,
version = 'some-version',
requiredPlugins = [],
+ requiredBundles = [],
optionalPlugins = [],
kibanaVersion = '7.0.0',
configPath = [path],
@@ -53,6 +54,7 @@ describe('PluginsService', () => {
disabled?: boolean;
version?: string;
requiredPlugins?: string[];
+ requiredBundles?: string[];
optionalPlugins?: string[];
kibanaVersion?: string;
configPath?: ConfigPath;
@@ -68,6 +70,7 @@ describe('PluginsService', () => {
configPath: `${configPath}${disabled ? '-disabled' : ''}`,
kibanaVersion,
requiredPlugins,
+ requiredBundles,
optionalPlugins,
server,
ui,
diff --git a/src/core/server/plugins/plugin.test.ts b/src/core/server/plugins/plugin.test.ts
index ec0a3986b4877..4f26686e1f5e0 100644
--- a/src/core/server/plugins/plugin.test.ts
+++ b/src/core/server/plugins/plugin.test.ts
@@ -54,6 +54,7 @@ function createPluginManifest(manifestProps: Partial = {}): Plug
kibanaVersion: '7.0.0',
requiredPlugins: ['some-required-dep'],
optionalPlugins: ['some-optional-dep'],
+ requiredBundles: [],
server: true,
ui: true,
...manifestProps,
diff --git a/src/core/server/plugins/plugin.ts b/src/core/server/plugins/plugin.ts
index 2e5881c651843..8bd9840855654 100644
--- a/src/core/server/plugins/plugin.ts
+++ b/src/core/server/plugins/plugin.ts
@@ -53,6 +53,7 @@ export class PluginWrapper<
public readonly configPath: PluginManifest['configPath'];
public readonly requiredPlugins: PluginManifest['requiredPlugins'];
public readonly optionalPlugins: PluginManifest['optionalPlugins'];
+ public readonly requiredBundles: PluginManifest['requiredBundles'];
public readonly includesServerPlugin: PluginManifest['server'];
public readonly includesUiPlugin: PluginManifest['ui'];
@@ -81,6 +82,7 @@ export class PluginWrapper<
this.configPath = params.manifest.configPath;
this.requiredPlugins = params.manifest.requiredPlugins;
this.optionalPlugins = params.manifest.optionalPlugins;
+ this.requiredBundles = params.manifest.requiredBundles;
this.includesServerPlugin = params.manifest.server;
this.includesUiPlugin = params.manifest.ui;
}
diff --git a/src/core/server/plugins/plugin_context.test.ts b/src/core/server/plugins/plugin_context.test.ts
index 69b354661abc9..ebd068caadfb9 100644
--- a/src/core/server/plugins/plugin_context.test.ts
+++ b/src/core/server/plugins/plugin_context.test.ts
@@ -43,6 +43,7 @@ function createPluginManifest(manifestProps: Partial = {}): Plug
configPath: 'path',
kibanaVersion: '7.0.0',
requiredPlugins: ['some-required-dep'],
+ requiredBundles: [],
optionalPlugins: ['some-optional-dep'],
server: true,
ui: true,
diff --git a/src/core/server/plugins/plugins_service.test.ts b/src/core/server/plugins/plugins_service.test.ts
index 46fd2b00c2304..aa77335991e2c 100644
--- a/src/core/server/plugins/plugins_service.test.ts
+++ b/src/core/server/plugins/plugins_service.test.ts
@@ -64,6 +64,7 @@ const createPlugin = (
disabled = false,
version = 'some-version',
requiredPlugins = [],
+ requiredBundles = [],
optionalPlugins = [],
kibanaVersion = '7.0.0',
configPath = [path],
@@ -74,6 +75,7 @@ const createPlugin = (
disabled?: boolean;
version?: string;
requiredPlugins?: string[];
+ requiredBundles?: string[];
optionalPlugins?: string[];
kibanaVersion?: string;
configPath?: ConfigPath;
@@ -89,6 +91,7 @@ const createPlugin = (
configPath: `${configPath}${disabled ? '-disabled' : ''}`,
kibanaVersion,
requiredPlugins,
+ requiredBundles,
optionalPlugins,
server,
ui,
@@ -460,6 +463,7 @@ describe('PluginsService', () => {
id: plugin.name,
configPath: plugin.manifest.configPath,
requiredPlugins: [],
+ requiredBundles: [],
optionalPlugins: [],
},
];
@@ -563,10 +567,12 @@ describe('PluginsService', () => {
"plugin-1" => Object {
"publicAssetsDir": /path-1/public/assets,
"publicTargetDir": /path-1/target/public,
+ "requiredBundles": Array [],
},
"plugin-2" => Object {
"publicAssetsDir": /path-2/public/assets,
"publicTargetDir": /path-2/target/public,
+ "requiredBundles": Array [],
},
}
`);
diff --git a/src/core/server/plugins/plugins_service.ts b/src/core/server/plugins/plugins_service.ts
index 5d1261e697bc0..06de48a215881 100644
--- a/src/core/server/plugins/plugins_service.ts
+++ b/src/core/server/plugins/plugins_service.ts
@@ -228,6 +228,7 @@ export class PluginsService implements CoreService
uiPluginNames.includes(p)
),
+ requiredBundles: plugin.manifest.requiredBundles,
},
];
})
diff --git a/src/core/server/plugins/types.ts b/src/core/server/plugins/types.ts
index 9e86ee22c607b..9695c9171a771 100644
--- a/src/core/server/plugins/types.ts
+++ b/src/core/server/plugins/types.ts
@@ -136,6 +136,18 @@ export interface PluginManifest {
*/
readonly requiredPlugins: readonly PluginName[];
+ /**
+ * List of plugin ids that this plugin's UI code imports modules from that are
+ * not in `requiredPlugins`.
+ *
+ * @remarks
+ * The plugins listed here will be loaded in the browser, even if the plugin is
+ * disabled. Required by `@kbn/optimizer` to support cross-plugin imports.
+ * "core" and plugins already listed in `requiredPlugins` do not need to be
+ * duplicated here.
+ */
+ readonly requiredBundles: readonly string[];
+
/**
* An optional list of the other plugins that if installed and enabled **may be**
* leveraged by this plugin for some additional functionality but otherwise are
@@ -191,12 +203,28 @@ export interface DiscoveredPlugin {
* not required for this plugin to work properly.
*/
readonly optionalPlugins: readonly PluginName[];
+
+ /**
+ * List of plugin ids that this plugin's UI code imports modules from that are
+ * not in `requiredPlugins`.
+ *
+ * @remarks
+ * The plugins listed here will be loaded in the browser, even if the plugin is
+ * disabled. Required by `@kbn/optimizer` to support cross-plugin imports.
+ * "core" and plugins already listed in `requiredPlugins` do not need to be
+ * duplicated here.
+ */
+ readonly requiredBundles: readonly PluginName[];
}
/**
* @internal
*/
export interface InternalPluginInfo {
+ /**
+ * Bundles that must be loaded for this plugoin
+ */
+ readonly requiredBundles: readonly string[];
/**
* Path to the target/public directory of the plugin which should be
* served
diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md
index 95912c3af63e5..3d3e1905577d9 100644
--- a/src/core/server/server.api.md
+++ b/src/core/server/server.api.md
@@ -637,6 +637,7 @@ export interface DiscoveredPlugin {
readonly configPath: ConfigPath;
readonly id: PluginName;
readonly optionalPlugins: readonly PluginName[];
+ readonly requiredBundles: readonly PluginName[];
readonly requiredPlugins: readonly PluginName[];
}
@@ -1684,6 +1685,7 @@ export interface PluginManifest {
readonly id: PluginName;
readonly kibanaVersion: string;
readonly optionalPlugins: readonly PluginName[];
+ readonly requiredBundles: readonly string[];
readonly requiredPlugins: readonly PluginName[];
readonly server: boolean;
readonly ui: boolean;
@@ -2706,8 +2708,8 @@ export const validBodyOutput: readonly ["data", "stream"];
// src/core/server/legacy/types.ts:165:3 - (ae-forgotten-export) The symbol "LegacyNavLinkSpec" needs to be exported by the entry point index.d.ts
// src/core/server/legacy/types.ts:166:3 - (ae-forgotten-export) The symbol "LegacyAppSpec" needs to be exported by the entry point index.d.ts
// src/core/server/legacy/types.ts:167:16 - (ae-forgotten-export) The symbol "LegacyPluginSpec" needs to be exported by the entry point index.d.ts
-// src/core/server/plugins/types.ts:238:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts
-// src/core/server/plugins/types.ts:238:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts
-// src/core/server/plugins/types.ts:240:3 - (ae-forgotten-export) The symbol "PathConfigType" needs to be exported by the entry point index.d.ts
+// src/core/server/plugins/types.ts:266:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts
+// src/core/server/plugins/types.ts:266:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts
+// src/core/server/plugins/types.ts:268:3 - (ae-forgotten-export) The symbol "PathConfigType" needs to be exported by the entry point index.d.ts
```
diff --git a/src/legacy/ui/ui_render/ui_render_mixin.js b/src/legacy/ui/ui_render/ui_render_mixin.js
index b4b18e086e809..168dddf0253d9 100644
--- a/src/legacy/ui/ui_render/ui_render_mixin.js
+++ b/src/legacy/ui/ui_render/ui_render_mixin.js
@@ -150,7 +150,23 @@ export function uiRenderMixin(kbnServer, server, config) {
]),
];
- const kpPluginIds = Array.from(kbnServer.newPlatform.__internals.uiPlugins.public.keys());
+ const kpUiPlugins = kbnServer.newPlatform.__internals.uiPlugins;
+ const kpPluginPublicPaths = new Map();
+ const kpPluginBundlePaths = new Set();
+
+ // recursively iterate over the kpUiPlugin ids and their required bundles
+ // to populate kpPluginPublicPaths and kpPluginBundlePaths
+ (function readKpPlugins(ids) {
+ for (const id of ids) {
+ if (kpPluginPublicPaths.has(id)) {
+ continue;
+ }
+
+ kpPluginPublicPaths.set(id, `${regularBundlePath}/plugin/${id}/`);
+ kpPluginBundlePaths.add(`${regularBundlePath}/plugin/${id}/${id}.plugin.js`);
+ readKpPlugins(kpUiPlugins.internal.get(id).requiredBundles);
+ }
+ })(kpUiPlugins.public.keys());
const jsDependencyPaths = [
...UiSharedDeps.jsDepFilenames.map(
@@ -160,9 +176,7 @@ export function uiRenderMixin(kbnServer, server, config) {
...(isCore ? [] : [`${dllBundlePath}/vendors_runtime.bundle.dll.js`, ...dllJsChunks]),
`${regularBundlePath}/core/core.entry.js`,
- ...kpPluginIds.map(
- (pluginId) => `${regularBundlePath}/plugin/${pluginId}/${pluginId}.plugin.js`
- ),
+ ...kpPluginBundlePaths,
];
// These paths should align with the bundle routes configured in
@@ -170,13 +184,7 @@ export function uiRenderMixin(kbnServer, server, config) {
const publicPathMap = JSON.stringify({
core: `${regularBundlePath}/core/`,
'kbn-ui-shared-deps': `${regularBundlePath}/kbn-ui-shared-deps/`,
- ...kpPluginIds.reduce(
- (acc, pluginId) => ({
- ...acc,
- [pluginId]: `${regularBundlePath}/plugin/${pluginId}/`,
- }),
- {}
- ),
+ ...Object.fromEntries(kpPluginPublicPaths),
});
const bootstrap = new AppBootstrap({
diff --git a/src/plugins/advanced_settings/kibana.json b/src/plugins/advanced_settings/kibana.json
index e6ca6e797ba45..8cf9b9c656d8f 100644
--- a/src/plugins/advanced_settings/kibana.json
+++ b/src/plugins/advanced_settings/kibana.json
@@ -3,5 +3,6 @@
"version": "kibana",
"server": true,
"ui": true,
- "requiredPlugins": ["management"]
+ "requiredPlugins": ["management"],
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/src/plugins/bfetch/kibana.json b/src/plugins/bfetch/kibana.json
index 462d2f4b8bb7d..9f9f2176af671 100644
--- a/src/plugins/bfetch/kibana.json
+++ b/src/plugins/bfetch/kibana.json
@@ -2,5 +2,6 @@
"id": "bfetch",
"version": "kibana",
"server": true,
- "ui": true
+ "ui": true,
+ "requiredBundles": ["kibanaUtils"]
}
diff --git a/src/plugins/charts/kibana.json b/src/plugins/charts/kibana.json
index 9f4433e7099d8..c4643d541c31c 100644
--- a/src/plugins/charts/kibana.json
+++ b/src/plugins/charts/kibana.json
@@ -2,5 +2,6 @@
"id": "charts",
"version": "kibana",
"server": true,
- "ui": true
+ "ui": true,
+ "requiredBundles": ["kibanaUtils", "kibanaReact", "data"]
}
diff --git a/src/plugins/console/kibana.json b/src/plugins/console/kibana.json
index 57de385ba565c..031aa00eb6613 100644
--- a/src/plugins/console/kibana.json
+++ b/src/plugins/console/kibana.json
@@ -4,5 +4,6 @@
"server": true,
"ui": true,
"requiredPlugins": ["devTools", "home"],
- "optionalPlugins": ["usageCollection"]
+ "optionalPlugins": ["usageCollection"],
+ "requiredBundles": ["esUiShared", "kibanaReact", "kibanaUtils"]
}
diff --git a/src/plugins/dashboard/kibana.json b/src/plugins/dashboard/kibana.json
index 4cd8f3c7d981f..1b38c6d124fe1 100644
--- a/src/plugins/dashboard/kibana.json
+++ b/src/plugins/dashboard/kibana.json
@@ -12,5 +12,6 @@
],
"optionalPlugins": ["home", "share", "usageCollection"],
"server": true,
- "ui": true
+ "ui": true,
+ "requiredBundles": ["kibanaUtils", "kibanaReact", "home"]
}
diff --git a/src/plugins/data/kibana.json b/src/plugins/data/kibana.json
index 3e5d96a4bc47b..2ffd0688b134e 100644
--- a/src/plugins/data/kibana.json
+++ b/src/plugins/data/kibana.json
@@ -8,5 +8,11 @@
"uiActions"
],
"optionalPlugins": ["usageCollection"],
- "extraPublicDirs": ["common", "common/utils/abort_utils"]
+ "extraPublicDirs": ["common", "common/utils/abort_utils"],
+ "requiredBundles": [
+ "kibanaUtils",
+ "kibanaReact",
+ "kibanaLegacy",
+ "inspector"
+ ]
}
diff --git a/src/plugins/discover/kibana.json b/src/plugins/discover/kibana.json
index 14dd399697b56..041f362bf0623 100644
--- a/src/plugins/discover/kibana.json
+++ b/src/plugins/discover/kibana.json
@@ -1,7 +1,6 @@
{
"id": "discover",
"version": "kibana",
- "optionalPlugins": ["share"],
"server": true,
"ui": true,
"requiredPlugins": [
@@ -14,5 +13,11 @@
"uiActions",
"visualizations"
],
- "optionalPlugins": ["home", "share"]
+ "optionalPlugins": ["home", "share"],
+ "requiredBundles": [
+ "kibanaUtils",
+ "home",
+ "savedObjects",
+ "kibanaReact"
+ ]
}
diff --git a/src/plugins/embeddable/kibana.json b/src/plugins/embeddable/kibana.json
index 332237d19e218..3163c4bde4704 100644
--- a/src/plugins/embeddable/kibana.json
+++ b/src/plugins/embeddable/kibana.json
@@ -10,5 +10,9 @@
],
"extraPublicDirs": [
"public/lib/test_samples"
+ ],
+ "requiredBundles": [
+ "savedObjects",
+ "kibanaReact"
]
}
diff --git a/src/plugins/es_ui_shared/kibana.json b/src/plugins/es_ui_shared/kibana.json
index 980f43ea46a68..eab7355d66f09 100644
--- a/src/plugins/es_ui_shared/kibana.json
+++ b/src/plugins/es_ui_shared/kibana.json
@@ -10,5 +10,8 @@
"static/forms/helpers",
"static/forms/components",
"static/forms/helpers/field_validators/types"
+ ],
+ "requiredBundles": [
+ "data"
]
}
diff --git a/src/plugins/expressions/kibana.json b/src/plugins/expressions/kibana.json
index 4774c69cc29ff..5163331088103 100644
--- a/src/plugins/expressions/kibana.json
+++ b/src/plugins/expressions/kibana.json
@@ -6,5 +6,10 @@
"requiredPlugins": [
"bfetch"
],
- "extraPublicDirs": ["common", "common/fonts"]
+ "extraPublicDirs": ["common", "common/fonts"],
+ "requiredBundles": [
+ "kibanaUtils",
+ "inspector",
+ "data"
+ ]
}
diff --git a/src/plugins/home/kibana.json b/src/plugins/home/kibana.json
index 1c4b44a946e62..74bd3625ca964 100644
--- a/src/plugins/home/kibana.json
+++ b/src/plugins/home/kibana.json
@@ -4,5 +4,8 @@
"server": true,
"ui": true,
"requiredPlugins": ["data", "kibanaLegacy"],
- "optionalPlugins": ["usageCollection", "telemetry"]
+ "optionalPlugins": ["usageCollection", "telemetry"],
+ "requiredBundles": [
+ "kibanaReact"
+ ]
}
diff --git a/src/plugins/index_pattern_management/kibana.json b/src/plugins/index_pattern_management/kibana.json
index 23adef2626a72..d0ad6a96065c3 100644
--- a/src/plugins/index_pattern_management/kibana.json
+++ b/src/plugins/index_pattern_management/kibana.json
@@ -3,5 +3,6 @@
"version": "kibana",
"server": true,
"ui": true,
- "requiredPlugins": ["management", "data", "kibanaLegacy"]
+ "requiredPlugins": ["management", "data", "kibanaLegacy"],
+ "requiredBundles": ["kibanaReact", "kibanaUtils"]
}
diff --git a/src/plugins/input_control_vis/kibana.json b/src/plugins/input_control_vis/kibana.json
index 4a4ec328c1352..6928eb19d02e1 100644
--- a/src/plugins/input_control_vis/kibana.json
+++ b/src/plugins/input_control_vis/kibana.json
@@ -4,5 +4,6 @@
"kibanaVersion": "kibana",
"server": true,
"ui": true,
- "requiredPlugins": ["data", "expressions", "visualizations"]
+ "requiredPlugins": ["data", "expressions", "visualizations"],
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/src/plugins/inspector/kibana.json b/src/plugins/inspector/kibana.json
index 99a38d2928df6..90e5d60250728 100644
--- a/src/plugins/inspector/kibana.json
+++ b/src/plugins/inspector/kibana.json
@@ -3,5 +3,6 @@
"version": "kibana",
"server": false,
"ui": true,
- "extraPublicDirs": ["common", "common/adapters/request"]
+ "extraPublicDirs": ["common", "common/adapters/request"],
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/src/plugins/kibana_react/kibana.json b/src/plugins/kibana_react/kibana.json
index 0add1bee84ae0..a507fe457b633 100644
--- a/src/plugins/kibana_react/kibana.json
+++ b/src/plugins/kibana_react/kibana.json
@@ -1,5 +1,6 @@
{
"id": "kibanaReact",
"version": "kibana",
- "ui": true
+ "ui": true,
+ "requiredBundles": ["kibanaUtils"]
}
diff --git a/src/plugins/management/kibana.json b/src/plugins/management/kibana.json
index cc411a8c6a25c..f48158e98ff3f 100644
--- a/src/plugins/management/kibana.json
+++ b/src/plugins/management/kibana.json
@@ -3,5 +3,6 @@
"version": "kibana",
"server": true,
"ui": true,
- "requiredPlugins": ["kibanaLegacy", "home"]
+ "requiredPlugins": ["kibanaLegacy", "home"],
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/src/plugins/maps_legacy/kibana.json b/src/plugins/maps_legacy/kibana.json
index cd503883164ac..d9bf33e661368 100644
--- a/src/plugins/maps_legacy/kibana.json
+++ b/src/plugins/maps_legacy/kibana.json
@@ -4,5 +4,6 @@
"kibanaVersion": "kibana",
"configPath": ["map"],
"ui": true,
- "server": true
+ "server": true,
+ "requiredBundles": ["kibanaReact", "charts"]
}
diff --git a/src/plugins/region_map/kibana.json b/src/plugins/region_map/kibana.json
index ac7e1f8659d66..6e1980c327dc0 100644
--- a/src/plugins/region_map/kibana.json
+++ b/src/plugins/region_map/kibana.json
@@ -11,5 +11,10 @@
"mapsLegacy",
"kibanaLegacy",
"data"
+ ],
+ "requiredBundles": [
+ "kibanaUtils",
+ "kibanaReact",
+ "charts"
]
}
diff --git a/src/plugins/saved_objects/kibana.json b/src/plugins/saved_objects/kibana.json
index 7ae1b84eecad8..589aafbd2aaf5 100644
--- a/src/plugins/saved_objects/kibana.json
+++ b/src/plugins/saved_objects/kibana.json
@@ -3,5 +3,9 @@
"version": "kibana",
"server": true,
"ui": true,
- "requiredPlugins": ["data"]
+ "requiredPlugins": ["data"],
+ "requiredBundles": [
+ "kibanaUtils",
+ "kibanaReact"
+ ]
}
diff --git a/src/plugins/saved_objects_management/kibana.json b/src/plugins/saved_objects_management/kibana.json
index 6184d890c415c..0270c1d8f5d39 100644
--- a/src/plugins/saved_objects_management/kibana.json
+++ b/src/plugins/saved_objects_management/kibana.json
@@ -5,5 +5,6 @@
"ui": true,
"requiredPlugins": ["home", "management", "data"],
"optionalPlugins": ["dashboard", "visualizations", "discover"],
- "extraPublicDirs": ["public/lib"]
+ "extraPublicDirs": ["public/lib"],
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/src/plugins/share/kibana.json b/src/plugins/share/kibana.json
index dce2ac9281aba..7760ea321992d 100644
--- a/src/plugins/share/kibana.json
+++ b/src/plugins/share/kibana.json
@@ -2,5 +2,6 @@
"id": "share",
"version": "kibana",
"server": true,
- "ui": true
+ "ui": true,
+ "requiredBundles": ["kibanaUtils"]
}
diff --git a/src/plugins/telemetry/kibana.json b/src/plugins/telemetry/kibana.json
index a497597762520..520ca6076dbbd 100644
--- a/src/plugins/telemetry/kibana.json
+++ b/src/plugins/telemetry/kibana.json
@@ -9,5 +9,9 @@
],
"extraPublicDirs": [
"common/constants"
+ ],
+ "requiredBundles": [
+ "kibanaUtils",
+ "kibanaReact"
]
}
diff --git a/src/plugins/tile_map/kibana.json b/src/plugins/tile_map/kibana.json
index bb8ef5a246549..9881a2dd72308 100644
--- a/src/plugins/tile_map/kibana.json
+++ b/src/plugins/tile_map/kibana.json
@@ -11,5 +11,10 @@
"mapsLegacy",
"kibanaLegacy",
"data"
+ ],
+ "requiredBundles": [
+ "kibanaUtils",
+ "kibanaReact",
+ "charts"
]
}
diff --git a/src/plugins/ui_actions/kibana.json b/src/plugins/ui_actions/kibana.json
index 907cbabbdf9c9..7b24b3cc5c48b 100644
--- a/src/plugins/ui_actions/kibana.json
+++ b/src/plugins/ui_actions/kibana.json
@@ -5,5 +5,8 @@
"ui": true,
"extraPublicDirs": [
"public/tests/test_samples"
+ ],
+ "requiredBundles": [
+ "kibanaReact"
]
}
diff --git a/src/plugins/usage_collection/kibana.json b/src/plugins/usage_collection/kibana.json
index ae86b6c5d7ad1..6ef78018c7d7f 100644
--- a/src/plugins/usage_collection/kibana.json
+++ b/src/plugins/usage_collection/kibana.json
@@ -3,5 +3,8 @@
"configPath": ["usageCollection"],
"version": "kibana",
"server": true,
- "ui": true
+ "ui": true,
+ "requiredBundles": [
+ "kibanaUtils"
+ ]
}
diff --git a/src/plugins/vis_type_markdown/kibana.json b/src/plugins/vis_type_markdown/kibana.json
index d52e22118ccf0..9241f5eeee837 100644
--- a/src/plugins/vis_type_markdown/kibana.json
+++ b/src/plugins/vis_type_markdown/kibana.json
@@ -3,5 +3,6 @@
"version": "kibana",
"ui": true,
"server": true,
- "requiredPlugins": ["expressions", "visualizations"]
+ "requiredPlugins": ["expressions", "visualizations"],
+ "requiredBundles": ["kibanaUtils", "kibanaReact", "data", "charts"]
}
diff --git a/src/plugins/vis_type_metric/kibana.json b/src/plugins/vis_type_metric/kibana.json
index 24135d257b317..b2ebc91471e9d 100644
--- a/src/plugins/vis_type_metric/kibana.json
+++ b/src/plugins/vis_type_metric/kibana.json
@@ -4,5 +4,6 @@
"kibanaVersion": "kibana",
"server": true,
"ui": true,
- "requiredPlugins": ["data", "visualizations", "charts","expressions"]
+ "requiredPlugins": ["data", "visualizations", "charts","expressions"],
+ "requiredBundles": ["kibanaUtils", "kibanaReact"]
}
diff --git a/src/plugins/vis_type_table/kibana.json b/src/plugins/vis_type_table/kibana.json
index ed098d7161403..b3c1556429077 100644
--- a/src/plugins/vis_type_table/kibana.json
+++ b/src/plugins/vis_type_table/kibana.json
@@ -8,5 +8,11 @@
"visualizations",
"data",
"kibanaLegacy"
+ ],
+ "requiredBundles": [
+ "kibanaUtils",
+ "kibanaReact",
+ "share",
+ "charts"
]
}
diff --git a/src/plugins/vis_type_tagcloud/kibana.json b/src/plugins/vis_type_tagcloud/kibana.json
index dbc9a1b9ef692..86f72ebfa936d 100644
--- a/src/plugins/vis_type_tagcloud/kibana.json
+++ b/src/plugins/vis_type_tagcloud/kibana.json
@@ -3,5 +3,6 @@
"version": "kibana",
"ui": true,
"server": true,
- "requiredPlugins": ["data", "expressions", "visualizations", "charts"]
+ "requiredPlugins": ["data", "expressions", "visualizations", "charts"],
+ "requiredBundles": ["kibanaUtils", "kibanaReact"]
}
diff --git a/src/plugins/vis_type_timelion/kibana.json b/src/plugins/vis_type_timelion/kibana.json
index 85c282c51a2e7..6946568f5d809 100644
--- a/src/plugins/vis_type_timelion/kibana.json
+++ b/src/plugins/vis_type_timelion/kibana.json
@@ -4,5 +4,6 @@
"kibanaVersion": "kibana",
"server": true,
"ui": true,
- "requiredPlugins": ["visualizations", "data", "expressions"]
+ "requiredPlugins": ["visualizations", "data", "expressions"],
+ "requiredBundles": ["kibanaUtils", "kibanaReact"]
}
diff --git a/src/plugins/vis_type_timeseries/kibana.json b/src/plugins/vis_type_timeseries/kibana.json
index 9053d2543e0d0..f2284726c463f 100644
--- a/src/plugins/vis_type_timeseries/kibana.json
+++ b/src/plugins/vis_type_timeseries/kibana.json
@@ -5,5 +5,6 @@
"server": true,
"ui": true,
"requiredPlugins": ["charts", "data", "expressions", "visualizations"],
- "optionalPlugins": ["usageCollection"]
+ "optionalPlugins": ["usageCollection"],
+ "requiredBundles": ["kibanaUtils", "kibanaReact"]
}
diff --git a/src/plugins/vis_type_vega/kibana.json b/src/plugins/vis_type_vega/kibana.json
index f1f82e7f5b7ad..d7a92de627a99 100644
--- a/src/plugins/vis_type_vega/kibana.json
+++ b/src/plugins/vis_type_vega/kibana.json
@@ -3,5 +3,6 @@
"version": "kibana",
"server": true,
"ui": true,
- "requiredPlugins": ["data", "visualizations", "mapsLegacy", "expressions"]
+ "requiredPlugins": ["data", "visualizations", "mapsLegacy", "expressions"],
+ "requiredBundles": ["kibanaUtils", "kibanaReact"]
}
diff --git a/src/plugins/vis_type_vislib/kibana.json b/src/plugins/vis_type_vislib/kibana.json
index cad0ebe01494a..7cba2e0d6a6b4 100644
--- a/src/plugins/vis_type_vislib/kibana.json
+++ b/src/plugins/vis_type_vislib/kibana.json
@@ -4,5 +4,6 @@
"server": true,
"ui": true,
"requiredPlugins": ["charts", "data", "expressions", "visualizations", "kibanaLegacy"],
- "optionalPlugins": ["visTypeXy"]
+ "optionalPlugins": ["visTypeXy"],
+ "requiredBundles": ["kibanaUtils", "kibanaReact"]
}
diff --git a/src/plugins/visualizations/kibana.json b/src/plugins/visualizations/kibana.json
index f3f9cbd8341ec..da3edfbdd3bf5 100644
--- a/src/plugins/visualizations/kibana.json
+++ b/src/plugins/visualizations/kibana.json
@@ -3,5 +3,6 @@
"version": "kibana",
"server": true,
"ui": true,
- "requiredPlugins": ["data", "expressions", "uiActions", "embeddable", "usageCollection", "inspector"]
+ "requiredPlugins": ["data", "expressions", "uiActions", "embeddable", "usageCollection", "inspector"],
+ "requiredBundles": ["kibanaUtils", "discover", "savedObjects"]
}
diff --git a/src/plugins/visualize/kibana.json b/src/plugins/visualize/kibana.json
index c27cfec24b332..520d1e1daa6fe 100644
--- a/src/plugins/visualize/kibana.json
+++ b/src/plugins/visualize/kibana.json
@@ -11,5 +11,11 @@
"visualizations",
"embeddable"
],
- "optionalPlugins": ["home", "share"]
+ "optionalPlugins": ["home", "share"],
+ "requiredBundles": [
+ "kibanaUtils",
+ "kibanaReact",
+ "home",
+ "discover"
+ ]
}
diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts
index 867e78dfad8dc..0611c80f59b92 100644
--- a/test/functional/services/remote/webdriver.ts
+++ b/test/functional/services/remote/webdriver.ts
@@ -28,7 +28,7 @@ import { delay } from 'bluebird';
import chromeDriver from 'chromedriver';
// @ts-ignore types not available
import geckoDriver from 'geckodriver';
-import { Builder, Capabilities, logging } from 'selenium-webdriver';
+import { Builder, logging } from 'selenium-webdriver';
import chrome from 'selenium-webdriver/chrome';
import firefox from 'selenium-webdriver/firefox';
import edge from 'selenium-webdriver/edge';
diff --git a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/kibana.json b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/kibana.json
index f0c1c3a34fbc0..7eafb185617c4 100644
--- a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/kibana.json
+++ b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/kibana.json
@@ -9,5 +9,8 @@
"expressions"
],
"server": false,
- "ui": true
+ "ui": true,
+ "requiredBundles": [
+ "inspector"
+ ]
}
diff --git a/test/plugin_functional/plugins/app_link_test/kibana.json b/test/plugin_functional/plugins/app_link_test/kibana.json
index 8cdc464abfec1..5384d4fee1508 100644
--- a/test/plugin_functional/plugins/app_link_test/kibana.json
+++ b/test/plugin_functional/plugins/app_link_test/kibana.json
@@ -3,5 +3,6 @@
"version": "0.0.1",
"kibanaVersion": "kibana",
"server": false,
- "ui": true
+ "ui": true,
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/test/plugin_functional/plugins/kbn_sample_panel_action/kibana.json b/test/plugin_functional/plugins/kbn_sample_panel_action/kibana.json
index 109afbcd5dabd..08ce182aa0293 100644
--- a/test/plugin_functional/plugins/kbn_sample_panel_action/kibana.json
+++ b/test/plugin_functional/plugins/kbn_sample_panel_action/kibana.json
@@ -5,5 +5,6 @@
"configPath": ["kbn_sample_panel_action"],
"server": false,
"ui": true,
- "requiredPlugins": ["uiActions", "embeddable"]
-}
\ No newline at end of file
+ "requiredPlugins": ["uiActions", "embeddable"],
+ "requiredBundles": ["kibanaReact"]
+}
diff --git a/test/scripts/jenkins_build_kibana.sh b/test/scripts/jenkins_build_kibana.sh
index 3e49edc8e6ae5..2310a35f94f33 100755
--- a/test/scripts/jenkins_build_kibana.sh
+++ b/test/scripts/jenkins_build_kibana.sh
@@ -2,16 +2,10 @@
source src/dev/ci_setup/setup_env.sh
-echo " -> building examples separate from test plugins"
+echo " -> building kibana platform plugins"
node scripts/build_kibana_platform_plugins \
--oss \
- --examples \
- --verbose;
-
-echo " -> building test plugins"
-node scripts/build_kibana_platform_plugins \
- --oss \
- --no-examples \
+ --filter '!alertingExample' \
--scan-dir "$KIBANA_DIR/test/plugin_functional/plugins" \
--scan-dir "$KIBANA_DIR/test/interpreter_functional/plugins" \
--verbose;
diff --git a/test/scripts/jenkins_xpack_build_kibana.sh b/test/scripts/jenkins_xpack_build_kibana.sh
index 58ef6a42d3fe4..c962b962b1e5e 100755
--- a/test/scripts/jenkins_xpack_build_kibana.sh
+++ b/test/scripts/jenkins_xpack_build_kibana.sh
@@ -3,14 +3,8 @@
cd "$KIBANA_DIR"
source src/dev/ci_setup/setup_env.sh
-echo " -> building examples separate from test plugins"
+echo " -> building kibana platform plugins"
node scripts/build_kibana_platform_plugins \
- --examples \
- --verbose;
-
-echo " -> building test plugins"
-node scripts/build_kibana_platform_plugins \
- --no-examples \
--scan-dir "$KIBANA_DIR/test/plugin_functional/plugins" \
--scan-dir "$XPACK_DIR/test/plugin_functional/plugins" \
--scan-dir "$XPACK_DIR/test/functional_with_es_ssl/fixtures/plugins" \
diff --git a/test/scripts/jenkins_xpack_visual_regression.sh b/test/scripts/jenkins_xpack_visual_regression.sh
index 930d4a74345d9..ac567a188a6d4 100755
--- a/test/scripts/jenkins_xpack_visual_regression.sh
+++ b/test/scripts/jenkins_xpack_visual_regression.sh
@@ -5,7 +5,7 @@ source "$KIBANA_DIR/src/dev/ci_setup/setup_percy.sh"
echo " -> building and extracting default Kibana distributable"
cd "$KIBANA_DIR"
-node scripts/build --debug
+node scripts/build --debug --no-oss
linuxBuild="$(find "$KIBANA_DIR/target" -name 'kibana-*-linux-x86_64.tar.gz')"
installDir="$PARENT_DIR/install/kibana"
mkdir -p "$installDir"
@@ -22,5 +22,5 @@ yarn percy exec -t 10000 -- -- \
# cd "$KIBANA_DIR"
# source "test/scripts/jenkins_xpack_page_load_metrics.sh"
-cd "$XPACK_DIR"
-source "$KIBANA_DIR/test/scripts/jenkins_xpack_saved_objects_field_metrics.sh"
+cd "$KIBANA_DIR"
+source "test/scripts/jenkins_xpack_saved_objects_field_metrics.sh"
diff --git a/x-pack/examples/ui_actions_enhanced_examples/kibana.json b/x-pack/examples/ui_actions_enhanced_examples/kibana.json
index a1cd895bb3cd6..160352a9afd66 100644
--- a/x-pack/examples/ui_actions_enhanced_examples/kibana.json
+++ b/x-pack/examples/ui_actions_enhanced_examples/kibana.json
@@ -6,5 +6,9 @@
"server": false,
"ui": true,
"requiredPlugins": ["uiActionsEnhanced", "data", "discover"],
- "optionalPlugins": []
+ "optionalPlugins": [],
+ "requiredBundles": [
+ "kibanaUtils",
+ "kibanaReact"
+ ]
}
diff --git a/x-pack/plugins/actions/README.md b/x-pack/plugins/actions/README.md
index 494f2f38e8bff..9e07727204f88 100644
--- a/x-pack/plugins/actions/README.md
+++ b/x-pack/plugins/actions/README.md
@@ -26,15 +26,19 @@ Table of Contents
- [Executor](#executor)
- [Example](#example)
- [RESTful API](#restful-api)
- - [`POST /api/actions/action`: Create action](#post-apiaction-create-action)
- - [`DELETE /api/actions/action/{id}`: Delete action](#delete-apiactionid-delete-action)
- - [`GET /api/actions`: Get all actions](#get-apiactiongetall-get-all-actions)
- - [`GET /api/actions/action/{id}`: Get action](#get-apiactionid-get-action)
- - [`GET /api/actions/list_action_types`: List action types](#get-apiactiontypes-list-action-types)
- - [`PUT /api/actions/action/{id}`: Update action](#put-apiactionid-update-action)
- - [`POST /api/actions/action/{id}/_execute`: Execute action](#post-apiactionidexecute-execute-action)
+ - [`POST /api/actions/action`: Create action](#post-apiactionsaction-create-action)
+ - [`DELETE /api/actions/action/{id}`: Delete action](#delete-apiactionsactionid-delete-action)
+ - [`GET /api/actions`: Get all actions](#get-apiactions-get-all-actions)
+ - [`GET /api/actions/action/{id}`: Get action](#get-apiactionsactionid-get-action)
+ - [`GET /api/actions/list_action_types`: List action types](#get-apiactionslist_action_types-list-action-types)
+ - [`PUT /api/actions/action/{id}`: Update action](#put-apiactionsactionid-update-action)
+ - [`POST /api/actions/action/{id}/_execute`: Execute action](#post-apiactionsactionid_execute-execute-action)
- [Firing actions](#firing-actions)
+ - [Accessing a scoped ActionsClient](#accessing-a-scoped-actionsclient)
+ - [actionsClient.enqueueExecution(options)](#actionsclientenqueueexecutionoptions)
- [Example](#example-1)
+ - [actionsClient.execute(options)](#actionsclientexecuteoptions)
+ - [Example](#example-2)
- [Built-in Action Types](#built-in-action-types)
- [Server log](#server-log)
- [`config`](#config)
@@ -70,6 +74,11 @@ Table of Contents
- [`secrets`](#secrets-7)
- [`params`](#params-7)
- [`subActionParams (pushToService)`](#subactionparams-pushtoservice-1)
+ - [IBM Resilient](#ibm-resilient)
+ - [`config`](#config-8)
+ - [`secrets`](#secrets-8)
+ - [`params`](#params-8)
+ - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-2)
- [Command Line Utility](#command-line-utility)
- [Developing New Action Types](#developing-new-action-types)
@@ -99,7 +108,7 @@ Built-In-Actions are configured using the _xpack.actions_ namespoace under _kiba
| _xpack.actions._**enabled** | Feature toggle which enabled Actions in Kibana. | boolean |
| _xpack.actions._**whitelistedHosts** | Which _hostnames_ are whitelisted for the Built-In-Action? This list should contain hostnames of every external service you wish to interact with using Webhooks, Email or any other built in Action. Note that you may use the string "\*" in place of a specific hostname to enable Kibana to target any URL, but keep in mind the potential use of such a feature to execute [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) attacks from your server. | Array |
| _xpack.actions._**enabledActionTypes** | A list of _actionTypes_ id's that are enabled. A "\*" may be used as an element to indicate all registered actionTypes should be enabled. The actionTypes registered for Kibana are `.server-log`, `.slack`, `.email`, `.index`, `.pagerduty`, `.webhook`. Default: `["*"]` | Array |
-| _xpack.actions._**preconfigured** | A object of action id / preconfigured actions. Default: `{}` | Array