Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[kbn/optimizer] share all plugin bundles #68986

Merged
merged 46 commits into from
Jun 16, 2020
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
306892d
add support for bundle references
spalger Jun 12, 2020
4280135
add some debugging scripts
spalger Jun 12, 2020
1929413
mesh the bundles together so that module are loaded as needed
spalger Jun 12, 2020
a4d1fd7
split up BundleRefs and resolver logic
spalger Jun 12, 2020
5d1e453
add references used by test plugins
spalger Jun 12, 2020
aefcd45
import from public dir
spalger Jun 12, 2020
c7ad86f
use custom module type so we can scan for bundleRef modules and avoid…
spalger Jun 13, 2020
4029278
implement actual resolution
spalger Jun 13, 2020
d92de6d
remove specific load order
spalger Jun 13, 2020
e1f4d08
copy all properties from exported bundle into local bundle
spalger Jun 13, 2020
78fd12a
update snapshot
spalger Jun 13, 2020
66e7911
build examples separate from test plugins
spalger Jun 13, 2020
55351f6
restore --oss flags for --oss example builds
spalger Jun 13, 2020
59a3af0
fix mapsLegacy leaflet wrapper, it used to rely on multiple instances…
spalger Jun 13, 2020
eeb8c1b
avoid mutable export
spalger Jun 13, 2020
977e0db
remove test scripts
spalger Jun 13, 2020
fdd8d36
remove unused import
spalger Jun 13, 2020
d670322
fix __kbnBundles__ stub
spalger Jun 13, 2020
95c65bd
fix manifest parsing
spalger Jun 13, 2020
a73e37f
update server api docs
spalger Jun 13, 2020
b301096
Merge branch 'master' into implement/share-all-plugin-bundles
elasticmachine Jun 13, 2020
afc3f4a
Merge branch 'master' into implement/share-all-plugin-bundles
elasticmachine Jun 13, 2020
e5309aa
Merge branch 'master' into implement/share-all-plugin-bundles
elasticmachine Jun 14, 2020
cd0767c
Merge branch 'master' into implement/share-all-plugin-bundles
elasticmachine Jun 14, 2020
0d840d7
Merge branch 'master' into implement/share-all-plugin-bundles
elasticmachine Jun 14, 2020
cd971b1
Merge branch 'master' into implement/share-all-plugin-bundles
elasticmachine Jun 14, 2020
227a7c7
Merge branch 'master' of github.com:elastic/kibana into implement/sha…
spalger Jun 15, 2020
af3bbc2
add a chunk to the readme about bundle refs
spalger Jun 15, 2020
cf2d6f2
Merge branch 'implement/share-all-plugin-bundles' of github.com:spalg…
spalger Jun 15, 2020
ce04f66
rename ref.id to ref.bundleId
spalger Jun 15, 2020
a9886f8
stop looking for a matching ref after the first match
spalger Jun 15, 2020
2973469
simplify BundleRefs#filterByExportIds()
spalger Jun 15, 2020
8fb3330
fix bundle_cache tests by defining bundleRefExportIds
spalger Jun 15, 2020
c67020c
add new public dir for embeddable_examples plugin
spalger Jun 15, 2020
7ed3097
Merge branch 'master' into implement/share-all-plugin-bundles
elasticmachine Jun 15, 2020
01abf17
fix comment and rename internal method for clarity
spalger Jun 15, 2020
048111f
Merge branch 'implement/share-all-plugin-bundles' of github.com:spalg…
spalger Jun 15, 2020
d03ec3e
Merge branch 'master' of github.com:elastic/kibana into implement/sha…
spalger Jun 15, 2020
6f16b87
add notice comments to the modules inspired by webpack's externals pl…
spalger Jun 15, 2020
7e9ceaa
improve comment for extraPublicDirs and immediately deprecate, regen …
spalger Jun 15, 2020
b07e700
Merge branch 'master' of github.com:elastic/kibana into implement/sha…
spalger Jun 15, 2020
1cb966b
tweak the readme text since it's not just for this PR
spalger Jun 15, 2020
9ec9881
store __kbnBundles__ source in a separate module for legibility
spalger Jun 15, 2020
38a6597
Merge branch 'master' of github.com:elastic/kibana into implement/sha…
spalger Jun 15, 2020
bc17db5
Merge branch 'master' into implement/share-all-plugin-bundles
elasticmachine Jun 16, 2020
7f4b4e8
Merge branch 'master' into implement/share-all-plugin-bundles
elasticmachine Jun 16, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion examples/demo_search/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"server": true,
"ui": true,
"requiredPlugins": ["data"],
"optionalPlugins": []
"optionalPlugins": [],
"extraPublicDirs": ["common"]
}
3 changes: 2 additions & 1 deletion examples/embeddable_examples/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"server": true,
"ui": true,
"requiredPlugins": ["embeddable"],
"optionalPlugins": []
"optionalPlugins": [],
"extraPublicDirs": ["public/todo"]
}
5 changes: 4 additions & 1 deletion examples/url_generators_examples/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@
"server": false,
"ui": true,
"requiredPlugins": ["share"],
"optionalPlugins": []
"optionalPlugins": [],
"extraPublicDirs": [
"public/url_generator"
]
}
1 change: 1 addition & 0 deletions packages/kbn-optimizer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"terser-webpack-plugin": "^2.1.2",
"tinymath": "1.2.1",
"url-loader": "^2.2.0",
"val-loader": "^1.1.1",
"watchpack": "^1.6.0",
"webpack": "^4.41.5",
"webpack-merge": "^4.2.2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@

import './legacy/styles.scss';
import './index.scss';
import { fooLibFn } from '../../foo/public/index';
import { fooLibFn } from '../../foo/public';
export * from './lib';
export { fooLibFn };
10 changes: 7 additions & 3 deletions packages/kbn-optimizer/src/common/bundle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jest.mock('fs');

const SPEC: BundleSpec = {
contextDir: '/foo/bar',
entry: 'entry',
publicDirNames: ['public'],
id: 'bar',
outputDir: '/foo/bar/target',
sourceRoot: '/foo',
Expand All @@ -49,9 +49,11 @@ it('creates cache keys', () => {
},
"spec": Object {
"contextDir": "/foo/bar",
"entry": "entry",
"id": "bar",
"outputDir": "/foo/bar/target",
"publicDirNames": Array [
"public",
],
"sourceRoot": "/foo",
"type": "plugin",
},
Expand Down Expand Up @@ -82,9 +84,11 @@ it('parses bundles from JSON specs', () => {
"state": undefined,
},
"contextDir": "/foo/bar",
"entry": "entry",
"id": "bar",
"outputDir": "/foo/bar/target",
"publicDirNames": Array [
"public",
],
"sourceRoot": "/foo",
"type": "plugin",
},
Expand Down
22 changes: 10 additions & 12 deletions packages/kbn-optimizer/src/common/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ export interface BundleSpec {
readonly type: typeof VALID_BUNDLE_TYPES[0];
/** Unique id for this bundle */
readonly id: string;
/** Webpack entry request for this plugin, relative to the contextDir */
readonly entry: string;
/** directory names relative to the contextDir that can be imported from */
readonly publicDirNames: string[];
/** Absolute path to the plugin source directory */
readonly contextDir: string;
/** Absolute path to the root of the repository */
Expand All @@ -44,8 +44,8 @@ export class Bundle {
public readonly type: BundleSpec['type'];
/** Unique identifier for this bundle */
public readonly id: BundleSpec['id'];
/** Path, relative to `contextDir`, to the entry file for the Webpack bundle */
public readonly entry: BundleSpec['entry'];
/** directory names relative to the contextDir that can be imported from */
public readonly publicDirNames: BundleSpec['publicDirNames'];
/**
* Absolute path to the root of the bundle context (plugin directory)
* where the entry is resolved relative to and the default output paths
Expand All @@ -62,7 +62,7 @@ export class Bundle {
constructor(spec: BundleSpec) {
this.type = spec.type;
this.id = spec.id;
this.entry = spec.entry;
this.publicDirNames = spec.publicDirNames;
this.contextDir = spec.contextDir;
this.sourceRoot = spec.sourceRoot;
this.outputDir = spec.outputDir;
Expand All @@ -73,8 +73,6 @@ export class Bundle {
/**
* Calculate the cache key for this bundle based from current
* mtime values.
*
* @param mtimes pre-fetched mtimes (ms || undefined) for all referenced files
*/
createCacheKey(files: string[], mtimes: Map<string, number | undefined>): unknown {
return {
Expand All @@ -94,7 +92,7 @@ export class Bundle {
return {
type: this.type,
id: this.id,
entry: this.entry,
publicDirNames: this.publicDirNames,
contextDir: this.contextDir,
sourceRoot: this.sourceRoot,
outputDir: this.outputDir,
Expand Down Expand Up @@ -134,9 +132,9 @@ export function parseBundles(json: string) {
throw new Error('`bundles[]` must have a string `id` property');
}

const { entry } = spec;
if (!(typeof entry === 'string')) {
throw new Error('`bundles[]` must have a string `entry` property');
const { publicDirNames } = spec;
if (!Array.isArray(publicDirNames) || !publicDirNames.every((d) => typeof d === 'string')) {
throw new Error('`bundles[]` must have an array of strings `publicDirNames` property');
}

const { contextDir } = spec;
Expand All @@ -157,7 +155,7 @@ export function parseBundles(json: string) {
return new Bundle({
type,
id,
entry,
publicDirNames,
contextDir,
sourceRoot,
outputDir,
Expand Down
5 changes: 5 additions & 0 deletions packages/kbn-optimizer/src/common/bundle_cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface State {
cacheKey?: unknown;
moduleCount?: number;
files?: string[];
bundleRefExportIds?: string[];
}

const DEFAULT_STATE: State = {};
Expand Down Expand Up @@ -87,6 +88,10 @@ export class BundleCache {
return this.get().files;
}

public getBundleRefExportIds() {
return this.get().bundleRefExportIds;
}

public getCacheKey() {
return this.get().cacheKey;
}
Expand Down
137 changes: 137 additions & 0 deletions packages/kbn-optimizer/src/common/bundle_refs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* 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 Path from 'path';

import { Bundle } from './bundle';
import { UnknownVals } from './ts_helpers';

export interface BundleRef {
id: string;
contextDir: string;
contextPrefix: string;
entry: string;
exportId: string;
}

export class BundleRefs {
static fromBundles(bundles: Bundle[]) {
return new BundleRefs(
bundles.reduce(
(acc: BundleRef[], b) => [
...acc,
...b.publicDirNames.map(
(name): BundleRef => ({
id: b.id,
contextDir: b.contextDir,
// Path.resolve converts separators and strips the final separator
contextPrefix: Path.resolve(b.contextDir) + Path.sep,
entry: name,
exportId: `${b.type}/${b.id}/${name}`,
})
),
],
[]
)
);
}

static parseSpec(json: unknown) {
if (typeof json !== 'string') {
throw new Error('expected `bundleRefs` spec to be a JSON string');
}

let spec;
try {
spec = JSON.parse(json);
} catch (error) {
throw new Error('`bundleRefs` spec must be valid JSON');
}

if (!Array.isArray(spec)) {
throw new Error('`bundleRefs` spec must be an array');
}

return new BundleRefs(
spec.map(
(refSpec: UnknownVals<BundleRef>): BundleRef => {
if (typeof refSpec !== 'object' || !refSpec) {
throw new Error('`bundleRefs[]` must be an object');
}

const { id } = refSpec;
if (typeof id !== 'string') {
throw new Error('`bundleRefs[].id` must be a string');
}

const { contextDir } = refSpec;
if (typeof contextDir !== 'string' || !Path.isAbsolute(contextDir)) {
throw new Error('`bundleRefs[].contextDir` must be an absolute directory');
}

const { contextPrefix } = refSpec;
if (typeof contextPrefix !== 'string' || !Path.isAbsolute(contextPrefix)) {
throw new Error('`bundleRefs[].contextPrefix` must be an absolute directory');
}

const { entry } = refSpec;
if (typeof entry !== 'string') {
throw new Error('`bundleRefs[].entry` must be a string');
}

const { exportId } = refSpec;
if (typeof exportId !== 'string') {
throw new Error('`bundleRefs[].exportId` must be a string');
}

return {
contextDir,
contextPrefix,
entry,
exportId,
id,
};
}
)
);
}

constructor(private readonly refs: BundleRef[]) {}

public filterByExportIds(exportIds: string[]) {
const refs: BundleRef[] = [];
for (const exportId of exportIds) {
const ref = this.refs.find((r) => r.exportId === exportId);
if (ref) {
refs.push(ref);
}
}
return refs;
}

public filterByContextPrefix(bundle: Bundle, absolutePath: string) {
return this.refs.filter(
(ref) => ref.id !== bundle.id && absolutePath.startsWith(ref.contextPrefix)
);
}

public toSpecJson() {
return JSON.stringify(this.refs);
}
}
1 change: 1 addition & 0 deletions packages/kbn-optimizer/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

export * from './bundle';
export * from './bundle_cache';
export * from './bundle_refs';
export * from './worker_config';
export * from './worker_messages';
export * from './compiler_messages';
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,14 @@ it('builds expected bundles, saves bundle counts to metadata', async () => {
const foo = config.bundles.find((b) => b.id === 'foo')!;
expect(foo).toBeTruthy();
foo.cache.refresh();
expect(foo.cache.getModuleCount()).toBe(5);
expect(foo.cache.getModuleCount()).toBe(6);
expect(foo.cache.getReferencedFiles()).toMatchInlineSnapshot(`
Array [
<absolute path>/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/async_import.ts,
<absolute path>/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/ext.ts,
<absolute path>/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/index.ts,
<absolute path>/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/lib.ts,
<absolute path>/packages/kbn-optimizer/target/worker/entry_point_creator.js,
<absolute path>/packages/kbn-ui-shared-deps/public_path_module_creator.js,
]
`);
Expand All @@ -148,7 +149,7 @@ it('builds expected bundles, saves bundle counts to metadata', async () => {
bar.cache.refresh();
expect(bar.cache.getModuleCount()).toBe(
// code + styles + style/css-loader runtimes + public path updater
21
18
);

expect(bar.cache.getReferencedFiles()).toMatchInlineSnapshot(`
Expand All @@ -159,11 +160,8 @@ it('builds expected bundles, saves bundle counts to metadata', async () => {
<absolute path>/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/index.ts,
<absolute path>/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/legacy/styles.scss,
<absolute path>/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/lib.ts,
<absolute path>/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/async_import.ts,
<absolute path>/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/ext.ts,
<absolute path>/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/index.ts,
<absolute path>/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/lib.ts,
<absolute path>/packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/src/legacy/ui/public/icon.svg,
<absolute path>/packages/kbn-optimizer/target/worker/entry_point_creator.js,
<absolute path>/packages/kbn-ui-shared-deps/public_path_module_creator.js,
]
`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ it('emits "bundle cached" event when everything is updated', async () => {
Array [
Object {
"bundle": <Bundle>,
"type": "bundle cached",
"reason": "bundle references missing",
"type": "bundle not cached",
},
]
`);
Expand Down Expand Up @@ -288,12 +289,7 @@ it('emits "bundle not cached" event when cacheKey is outdated', async () => {
Array [
Object {
"bundle": <Bundle>,
"diff": "- Expected
+ Received

- \\"old\\"
+ \\"new\\"",
"reason": "cache key mismatch",
"reason": "bundle references missing",
"type": "bundle not cached",
},
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ jest.mock('fs');
jest.mock('watchpack');

const MockWatchPack: jest.MockedClass<typeof ActualWatchpack> = jest.requireMock('watchpack');
const bundleEntryPath = (bundle: Bundle) => `${bundle.contextDir}/${bundle.entry}`;
const bundleEntryPath = (bundle: Bundle) => `${bundle.contextDir}/public/index.ts`;

const makeTestBundle = (id: string) => {
const bundle = new Bundle({
type: 'plugin',
id,
contextDir: `/repo/plugins/${id}/public`,
entry: 'index.ts',
publicDirNames: ['public'],
outputDir: `/repo/plugins/${id}/target/public`,
sourceRoot: `/repo`,
});
Expand Down
Loading