Skip to content

Commit

Permalink
Merge pull request #10433 from vojtechszocs/plugin-sdk-wp5
Browse files Browse the repository at this point in the history
Bug 2020428: Adapt webpack 5 related code in dynamic plugin SDK
  • Loading branch information
openshift-merge-robot committed Nov 12, 2021
2 parents a38bacb + 5e01196 commit 9ab6ddd
Show file tree
Hide file tree
Showing 16 changed files with 289 additions and 243 deletions.
2 changes: 1 addition & 1 deletion dynamic-demo-plugin/package.json
Expand Up @@ -35,7 +35,7 @@
"ts-loader": "9.x",
"ts-node": "5.0.1",
"typescript": "4.x",
"webpack": "5.x",
"webpack": "^5.62.1",
"webpack-cli": "4.9.x"
},
"consolePlugin": {
Expand Down
10 changes: 5 additions & 5 deletions dynamic-demo-plugin/yarn.lock
Expand Up @@ -76,7 +76,7 @@
lodash "^4.17.21"
read-pkg "5.x"
semver "6.x"
webpack "^5.53.0"
webpack "^5.62.1"

"@openshift-console/dynamic-plugin-sdk@file:../frontend/packages/console-dynamic-plugin-sdk/dist/core":
version "0.0.0-fixed"
Expand Down Expand Up @@ -3407,10 +3407,10 @@ webpack-sources@^3.2.0:
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.1.tgz#251a7d9720d75ada1469ca07dbb62f3641a05b6d"
integrity sha512-t6BMVLQ0AkjBOoRTZgqrWm7xbXMBzD+XDq2EZ96+vMfn3qKgsvdXZhbPZ4ElUOpdv4u+iiGe+w3+J75iy/bYGA==

webpack@5.x, webpack@^5.53.0:
version "5.62.1"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.62.1.tgz#06f09b56a7b1bb13ed5137ad4b118358a90c9505"
integrity sha512-jNLtnWChS2CMZ7vqWtztv0G6fYB5hz11Zsadp5tE7e4/66zVDj7/KUeQZOsOl8Hz5KrLJH1h2eIDl6AnlyE12Q==
webpack@^5.62.1:
version "5.63.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.63.0.tgz#4b074115800e0526d85112985e46c64b95e04aaf"
integrity sha512-HYrw6bkj/MDmphAXvqLEvn2fVoDZsYu6O638WjK6lSNgIpjb5jl/KtOrqJyU9EC/ZV9mLUmZW5h4mASB+CVA4A==
dependencies:
"@types/eslint-scope" "^3.7.0"
"@types/estree" "^0.0.50"
Expand Down
4 changes: 2 additions & 2 deletions frontend/packages/console-dynamic-plugin-sdk/package.json
Expand Up @@ -22,7 +22,7 @@
"fs-extra": "9.x",
"ts-json-schema-generator": "0.91.0",
"tsutils": "3.x",
"typescript": "~4.2.3",
"webpack": "^5.53.0"
"typescript": "4.2.x",
"webpack": "^5.62.1"
}
}
Expand Up @@ -53,7 +53,7 @@ const parseSharedModuleDeps = (
) =>
parseDeps(
pkg,
Object.keys(sharedPluginModules).filter((m) => !m.startsWith('@openshift-console/')),
sharedPluginModules.filter((m) => !m.startsWith('@openshift-console/')),
missingDepCallback,
);

Expand Down
@@ -0,0 +1,31 @@
import { sharedPluginModules } from '../shared-modules';
import { initSharedPluginModules } from '../shared-modules-init';
import { getEntryModuleMocks } from '../utils/test-utils';

describe('initSharedPluginModules', () => {
const expectSameValues = (arr1: string[], arr2: string[]) => {
expect(new Set(arr1)).toEqual(new Set(arr2));
};

it('is consistent with sharedPluginModules definition', () => {
const [, entryModule] = getEntryModuleMocks({});

initSharedPluginModules(entryModule);

expect(entryModule.init).toHaveBeenCalledTimes(1);

expectSameValues(Object.keys(entryModule.init.mock.calls[0][0]), sharedPluginModules);
});

it('supports plugins built with an older version of plugin SDK', () => {
const [, entryModule] = getEntryModuleMocks({});
entryModule.override = jest.fn();

initSharedPluginModules(entryModule);

expect(entryModule.override).toHaveBeenCalledTimes(1);
expect(entryModule.init).not.toHaveBeenCalled();

expectSameValues(Object.keys(entryModule.override.mock.calls[0][0]), sharedPluginModules);
});
});

This file was deleted.

Expand Up @@ -171,19 +171,19 @@ describe('window.loadPluginEntry', () => {
const [, entryModule] = getEntryModuleMocks({});
const { pluginMap } = getStateForTestPurposes();

const overrideSharedModules = jest.fn();
const initSharedPluginModules = jest.fn();
const resolveEncodedCodeRefs = jest.fn(() => resolvedExtensions);

pluginMap.set(getPluginID(manifest), { manifest, entryCallbackFired: false });

getPluginEntryCallback(
pluginStore,
overrideSharedModules,
initSharedPluginModules,
resolveEncodedCodeRefs,
)('Test@1.2.3', entryModule);

expect(pluginMap.get('Test@1.2.3').entryCallbackFired).toBe(true);
expect(overrideSharedModules).toHaveBeenCalledWith(entryModule);
expect(initSharedPluginModules).toHaveBeenCalledWith(entryModule);

expect(resolveEncodedCodeRefs).toHaveBeenCalledWith(
manifest.extensions,
Expand All @@ -202,17 +202,17 @@ describe('window.loadPluginEntry', () => {
const [, entryModule] = getEntryModuleMocks({});
const { pluginMap } = getStateForTestPurposes();

const overrideSharedModules = jest.fn();
const initSharedPluginModules = jest.fn();
const resolveEncodedCodeRefs = jest.fn(() => []);

getPluginEntryCallback(
pluginStore,
overrideSharedModules,
initSharedPluginModules,
resolveEncodedCodeRefs,
)('Test@1.2.3', entryModule);

expect(pluginMap.size).toBe(0);
expect(overrideSharedModules).not.toHaveBeenCalled();
expect(initSharedPluginModules).not.toHaveBeenCalled();
expect(resolveEncodedCodeRefs).not.toHaveBeenCalled();
expect(addDynamicPlugin).not.toHaveBeenCalled();
});
Expand All @@ -225,25 +225,25 @@ describe('window.loadPluginEntry', () => {
const [, entryModule] = getEntryModuleMocks({});
const { pluginMap } = getStateForTestPurposes();

const overrideSharedModules = jest.fn();
const initSharedPluginModules = jest.fn();
const resolveEncodedCodeRefs = jest.fn(() => []);

pluginMap.set(getPluginID(manifest), { manifest, entryCallbackFired: false });

getPluginEntryCallback(
pluginStore,
overrideSharedModules,
initSharedPluginModules,
resolveEncodedCodeRefs,
)('Test@1.2.3', entryModule);

getPluginEntryCallback(
pluginStore,
overrideSharedModules,
initSharedPluginModules,
resolveEncodedCodeRefs,
)('Test@1.2.3', entryModule);

expect(pluginMap.size).toBe(1);
expect(overrideSharedModules).toHaveBeenCalledTimes(1);
expect(initSharedPluginModules).toHaveBeenCalledTimes(1);
expect(resolveEncodedCodeRefs).toHaveBeenCalledTimes(1);
expect(addDynamicPlugin).toHaveBeenCalledTimes(1);
});
Expand All @@ -256,7 +256,7 @@ describe('window.loadPluginEntry', () => {
const [, entryModule] = getEntryModuleMocks({});
const { pluginMap } = getStateForTestPurposes();

const overrideSharedModules = jest.fn(() => {
const initSharedPluginModules = jest.fn(() => {
throw new Error('boom');
});
const resolveEncodedCodeRefs = jest.fn(() => []);
Expand All @@ -265,12 +265,12 @@ describe('window.loadPluginEntry', () => {

getPluginEntryCallback(
pluginStore,
overrideSharedModules,
initSharedPluginModules,
resolveEncodedCodeRefs,
)('Test@1.2.3', entryModule);

expect(pluginMap.size).toBe(1);
expect(overrideSharedModules).toHaveBeenCalledWith(entryModule);
expect(initSharedPluginModules).toHaveBeenCalledWith(entryModule);
expect(resolveEncodedCodeRefs).not.toHaveBeenCalled();
expect(addDynamicPlugin).not.toHaveBeenCalled();
});
Expand Down
Expand Up @@ -5,7 +5,7 @@ import { PluginStore } from '@console/plugin-sdk/src/store';
import { resolveEncodedCodeRefs } from '../coderefs/coderef-resolver';
import { remoteEntryFile } from '../constants';
import { ConsolePluginManifestJSON } from '../schema/plugin-manifest';
import { overrideSharedModules } from '../shared-modules-override';
import { initSharedPluginModules } from '../shared-modules-init';
import { RemoteEntryModule } from '../types';
import { resolveURL } from '../utils/url';
import { fetchPluginManifest } from './plugin-manifest';
Expand Down Expand Up @@ -65,7 +65,7 @@ export const loadDynamicPlugin = (baseURL: string, manifest: ConsolePluginManife

export const getPluginEntryCallback = (
pluginStore: PluginStore,
overrideSharedModulesCallback: typeof overrideSharedModules,
initSharedPluginModulesCallback: typeof initSharedPluginModules,
resolveEncodedCodeRefsCallback: typeof resolveEncodedCodeRefs,
) => (pluginID: string, entryModule: RemoteEntryModule) => {
if (!pluginMap.has(pluginID)) {
Expand All @@ -83,9 +83,9 @@ export const getPluginEntryCallback = (
pluginData.entryCallbackFired = true;

try {
overrideSharedModulesCallback(entryModule);
initSharedPluginModulesCallback(entryModule);
} catch (error) {
console.error(`Failed to override shared modules for plugin ${pluginID}`, error);
console.error(`Failed to initialize shared modules for plugin ${pluginID}`, error);
return;
}

Expand All @@ -105,7 +105,7 @@ export const getPluginEntryCallback = (
export const registerPluginEntryCallback = (pluginStore: PluginStore) => {
window.loadPluginEntry = getPluginEntryCallback(
pluginStore,
overrideSharedModules,
initSharedPluginModules,
resolveEncodedCodeRefs,
);
};
Expand Down
@@ -0,0 +1,58 @@
/* eslint-disable global-require */
/* eslint-disable @typescript-eslint/no-require-imports */

import { SharedModuleResolution, RemoteEntryModule } from './types';

const modules: SharedModuleResolution = {
'@openshift-console/dynamic-plugin-sdk': async () => () =>
require('@console/dynamic-plugin-sdk/src/lib-core'),
'@openshift-console/dynamic-plugin-sdk-internal': async () => () =>
require('@console/dynamic-plugin-sdk/src/lib-internal'),
'@openshift-console/dynamic-plugin-sdk-internal-kubevirt': async () => () =>
require('@console/dynamic-plugin-sdk/src/lib-internal-kubevirt'),
'@patternfly/react-core': async () => () => require('@patternfly/react-core'),
'@patternfly/react-table': async () => () => require('@patternfly/react-table'),
react: async () => () => require('react'),
'react-helmet': async () => () => require('react-helmet'),
'react-i18next': async () => () => require('react-i18next'),
'react-router': async () => () => require('react-router'),
'react-router-dom': async () => () => require('react-router-dom'),
};

const sharedScope = Object.keys(modules).reduce(
(acc, moduleRequest) => ({
...acc,
[moduleRequest]: {
// The '*' semver range means "this shared module matches all requested versions",
// i.e. make sure the plugin always uses the Console-provided shared module version
'*': {
get: modules[moduleRequest],
// Indicates that Console has already loaded the shared module
loaded: true,
},
},
}),
{},
);

/**
* At runtime, the Console application will initialize shared modules for each
* dynamic plugin before loading any of the modules exposed by the given plugin.
*
* Currently, module sharing is strictly unidirectional (Console -> plugins).
*
* Note: `__webpack_init_sharing__` global function is available in webpack 5+ builds.
* Once Console gets built with webpack 5, evaluate if we need this global in order to
* allow plugins to attempt to provide shared modules into the application shared scope.
*
* @see https://webpack.js.org/concepts/module-federation/#dynamic-remote-containers
*/
export const initSharedPluginModules = (entryModule: RemoteEntryModule) => {
if (typeof entryModule.override === 'function') {
// Support plugins built with webpack 5.0.0-beta.16
entryModule.override(modules);
return;
}

entryModule.init(sharedScope);
};

This file was deleted.

44 changes: 12 additions & 32 deletions frontend/packages/console-dynamic-plugin-sdk/src/shared-modules.ts
@@ -1,35 +1,15 @@
/**
* Modules shared between the Console application and its dynamic plugins.
*/
export const sharedPluginModules = {
'@openshift-console/dynamic-plugin-sdk': {
singleton: true,
},
'@openshift-console/dynamic-plugin-sdk-internal': {
singleton: true,
},
'@openshift-console/dynamic-plugin-sdk-internal-kubevirt': {
singleton: true,
},
'@patternfly/react-core': {
singleton: true,
},
'@patternfly/react-table': {
singleton: true,
},
react: {
singleton: true,
},
'react-helmet': {
singleton: true,
},
'react-i18next': {
singleton: true,
},
'react-router': {
singleton: true,
},
'react-router-dom': {
singleton: true,
},
};
export const sharedPluginModules = [
'@openshift-console/dynamic-plugin-sdk',
'@openshift-console/dynamic-plugin-sdk-internal',
'@openshift-console/dynamic-plugin-sdk-internal-kubevirt',
'@patternfly/react-core',
'@patternfly/react-table',
'react',
'react-helmet',
'react-i18next',
'react-router',
'react-router-dom',
];

0 comments on commit 9ab6ddd

Please sign in to comment.