@redhat-cloud-services/frontend-components-config-utilities 1.5.6 → 1.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -123,3 +123,71 @@ This packages exposes these federated shared dependencies
123
123
  * `@redhat-cloud-services/frontend-components` - version taken from your `package.json`
124
124
  * `@redhat-cloud-services/frontend-components-utilities` - version taken from your `package.json`
125
125
  * `@redhat-cloud-services/frontend-components-notifications` - version taken from your `package.json`
126
+
127
+ ## Extensions plugin
128
+
129
+ In order to share some code into extension points or to add new extension point we can use `ExtensionsPlugin`
130
+
131
+ Simply import it in your webpack config and add it to your plugins
132
+
133
+ ```JS
134
+ const { resolve } = require('path');
135
+ const config = require('@redhat-cloud-services/frontend-components-config');
136
+ const ExtensionsPlugin = require('@redhat-cloud-services/frontend-components-config/extensions-plugin');
137
+
138
+ const { config: webpackConfig, plugins } = config({
139
+ rootFolder: resolve(__dirname, '../'),
140
+ ...(process.env.BETA && { deployment: 'beta/apps' }),
141
+ });
142
+
143
+ plugins.push(
144
+ require('@redhat-cloud-services/frontend-components-config/federated-modules')({
145
+ root: resolve(__dirname, '../'),
146
+ }),
147
+ new ExtensionsPlugin({})
148
+ );
149
+
150
+ module.exports = {
151
+ ...webpackConfig,
152
+ plugins
153
+ }
154
+ ```
155
+
156
+ ### Arguments
157
+
158
+ There are three arguments `ExtensionsPlugin` constructor accepts:
159
+ * `pluginConfig`
160
+ * `fedModuleConfig`
161
+ * `options`
162
+
163
+ ### `pluginConfig`
164
+
165
+ This config contains information about extensions, plugin requirements, its name and description. Most of it (name, description and version) is calculated from your root `package.json`. But you can override these values:
166
+
167
+ * `name` - plugin name (pulled from `package.json`)
168
+ * `version` - version of the plugin
169
+ * `displayName` - display name of the plugin
170
+ * `description` - description of the plugin (pulled from `package.json`)
171
+ * `dependencies` - object of dependencies which will be passed down to module federation (no need to list general react dependencies)
172
+ * `disableStaticPlugins` - list of static plugins this plugin disables on load
173
+ * `extensions` - list of extension objects.
174
+
175
+ #### extension object
176
+
177
+ Each extension object requires a `type` and `properties`. The type can be either custom extension or one of predefined:
178
+
179
+ * `console.navigation/section` - a section in navigation (identifies secondary nav)
180
+ * `properties`
181
+ * `id` - id of the section
182
+ * `name` - name of the section, this will be shown in the UI
183
+ * `console.page/route` - route passed to react-router
184
+ * `properties` - in theory any react-router path prop can be used here
185
+ * `path` - (string, or array) path on which the component will be rendered
186
+ * `component`
187
+ * `$codeRef` - federated module used to render on the route
188
+ * `console.navigation/href` - navigation href, used to render leafs of navigation
189
+ * `properties`
190
+ * `id` - id of the href
191
+ * `section` - (optional) used to group nav items under section (omit for flat nav)
192
+ * `name` - name of the href, thiw will be shown in the UI
193
+ * `href` - used to mutate the URL
@@ -0,0 +1,77 @@
1
+ const webpack = require('webpack');
2
+
3
+ class ExtensionsMapper {
4
+ constructor(plugin, options) {
5
+ if (!plugin) {
6
+ throw new Error('Missing plugin config!');
7
+ }
8
+
9
+ this.plugin = plugin;
10
+ this.options = {
11
+ remoteEntryCallback: 'window.loadPluginEntry',
12
+ remoteEntryFile: 'plugin-entry.js',
13
+ pluginManifestFile: 'plugin-manifest.json',
14
+ ...options
15
+ };
16
+ }
17
+
18
+ apply(compiler) {
19
+ compiler.hooks.thisCompilation.tap(ExtensionsMapper.name, (compilation) => {
20
+ // Generate extensions manifest
21
+ compilation.hooks.processAssets.tap(
22
+ {
23
+ name: ExtensionsMapper.name,
24
+ stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL
25
+ },
26
+ () => {
27
+ compilation.emitAsset(
28
+ this.options.pluginManifestFile,
29
+ new webpack.sources.RawSource(
30
+ Buffer.from(JSON.stringify({
31
+ version: '0.0.0',
32
+ description: '',
33
+ displayName: '',
34
+ dependencies: {},
35
+ disableStaticPlugins: {},
36
+ ...this.plugin
37
+ }, null, 2))
38
+ )
39
+ );
40
+ }
41
+ );
42
+
43
+ // Update plugin-entry.js file
44
+ compilation.hooks.processAssets.tap(
45
+ {
46
+ name: ExtensionsMapper.name,
47
+ stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
48
+ },
49
+ () => {
50
+ compilation.updateAsset(this.options.remoteEntryFile, (source) => {
51
+ const newSource = new webpack.sources.ReplaceSource(source);
52
+
53
+ const fromIndex = source
54
+ .source()
55
+ .toString()
56
+ .indexOf(`${this.options.remoteEntryCallback}(`);
57
+
58
+ if (fromIndex < 0) {
59
+ const error = new webpack.WebpackError(`Missing call to ${this.options.remoteEntryCallback}`);
60
+ error.file = this.options.remoteEntryFile;
61
+ compilation.errors.push(error);
62
+ } else {
63
+ newSource.insert(
64
+ fromIndex + this.options.remoteEntryCallback.length + 1,
65
+ `'${this.plugin.name}@${this.plugin.version}', `
66
+ );
67
+ }
68
+
69
+ return newSource;
70
+ });
71
+ }
72
+ );
73
+ });
74
+ }
75
+ }
76
+
77
+ module.exports = ExtensionsMapper;
@@ -0,0 +1,54 @@
1
+ const { resolve } = require('path');
2
+ const fedModule = require('./federated-modules');
3
+ const ExtensionsMapper = require('./extension-mapper');
4
+
5
+ class ExtensionsPlugin {
6
+ constructor(plugin, fedMod, options) {
7
+ if (!plugin) {
8
+ throw new Error('Missing plugin config!');
9
+ }
10
+
11
+ this.plugin = plugin;
12
+ this.fedMod = {
13
+ moduleName: 'plugin-entry',
14
+ libName: 'window.loadPluginEntry',
15
+ useFileHash: false,
16
+ libType: 'jsonp',
17
+ ...fedMod
18
+ };
19
+ this.options = {
20
+ remoteEntryCallback: 'window.loadPluginEntry',
21
+ remoteEntryFile: `${this.fedMod.moduleName}.js`,
22
+ pluginManifestFile: 'plugin-manifest.json',
23
+ ...options
24
+ };
25
+ }
26
+
27
+ apply(compiler) {
28
+ const root = this.fedMod.root || compiler.context;
29
+ const { insights, version, description } = require(resolve(root, './package.json')) || {};
30
+
31
+ // create federation module
32
+ fedModule({
33
+ ...this.fedMod,
34
+ root
35
+ }).apply(compiler);
36
+
37
+ // generate plugin manifest and update plugin-entry file
38
+ new ExtensionsMapper(
39
+ {
40
+ ...this.plugin,
41
+ name: this.plugin.name || (insights && insights.appname),
42
+ version: this.plugin.version || version || '0.0.0',
43
+ displayName: this.plugin.displayName || '',
44
+ description: this.plugin.description || description || '',
45
+ dependencies: { ...this.plugin.dependencies || {} },
46
+ disableStaticPlugins: [ ...this.plugin.disableStaticPlugins || [] ],
47
+ extensions: [ ...this.plugin.extensions || [] ]
48
+ },
49
+ this.options
50
+ ).apply(compiler);
51
+ }
52
+ }
53
+
54
+ module.exports = ExtensionsPlugin;
@@ -27,6 +27,8 @@ module.exports = ({
27
27
  debug,
28
28
  moduleName,
29
29
  useFileHash = true,
30
+ libType = 'var',
31
+ libName,
30
32
  exclude = []
31
33
  }) => {
32
34
  const { dependencies, insights } = require(resolve(root, './package.json')) || {};
@@ -64,7 +66,7 @@ module.exports = ({
64
66
  return new ModuleFederationPlugin({
65
67
  name: appName,
66
68
  filename: `${appName}${useFileHash ? '.[chunkhash]' : ''}.js`,
67
- library: { type: 'var', name: appName },
69
+ library: { type: libType, name: libName || appName },
68
70
  exposes: {
69
71
  ...exposes || {
70
72
  './RootApp': resolve(root, './src/AppEntry')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redhat-cloud-services/frontend-components-config-utilities",
3
- "version": "1.5.6",
3
+ "version": "1.5.7",
4
4
  "description": "Utilities for shared config used in RedHat Cloud Services project.",
5
5
  "main": "index.js",
6
6
  "publishConfig": {