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

feat(enhanced): support layers in consume share plugin #3276

Open
wants to merge 44 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
5b107fa
feat(enhanced): support layers
ScriptedAlchemy Nov 17, 2024
062706f
feat(enhanced): support layers
ScriptedAlchemy Nov 17, 2024
cfd9d01
feat(enhanced): layers for consume shared module
ScriptedAlchemy Nov 21, 2024
3e59c55
Merge branch 'main' into layers-support
ScriptedAlchemy Nov 21, 2024
536b110
Merge branch 'main' into layers-support
ScriptedAlchemy Nov 21, 2024
aed08e9
feat(enhanced): add issuerLayer support to consume shared
ScriptedAlchemy Nov 22, 2024
9fb164b
chore(enhanced): update test
ScriptedAlchemy Nov 25, 2024
a9d899c
chore(enhanced): update test
ScriptedAlchemy Nov 25, 2024
33a36d1
feat(enhanced): ConsumeSharedPlugin issuerLayer support
ScriptedAlchemy Nov 25, 2024
f0c5c50
chore: update tests for layer combos
ScriptedAlchemy Nov 25, 2024
578adbb
chore: update tests for layer combos
ScriptedAlchemy Nov 25, 2024
31f08d0
chore: update tests for layer combos
ScriptedAlchemy Nov 25, 2024
066ffa6
feat(enhanced): support direct layer
ScriptedAlchemy Nov 25, 2024
b70eb8d
Merge branch 'main' into layers-support
ScriptedAlchemy Nov 25, 2024
358ba00
fix(enhanced): update share options of share plugin
ScriptedAlchemy Nov 25, 2024
94d72ed
fix(enhanced): update share options of share plugin
ScriptedAlchemy Nov 25, 2024
91dbb12
chore(enhanced): refactor layers tests
ScriptedAlchemy Nov 25, 2024
514cf03
chore(enhanced): remove layer options from provider
ScriptedAlchemy Nov 25, 2024
359b0ca
Merge branch 'main' into consume-share-layers
ScriptedAlchemy Nov 25, 2024
24ef6d0
Delete .cursorrules
ScriptedAlchemy Nov 25, 2024
9d9bff2
feat(enhanced): support layers in consume share
ScriptedAlchemy Nov 26, 2024
40ae817
Merge branch 'main' into consume-share-layers
ScriptedAlchemy Nov 26, 2024
d1c68b3
fix(enhanced): rename requiredLayer to layer
ScriptedAlchemy Dec 2, 2024
22964f8
Merge remote-tracking branch 'origin/consume-share-layers' into consu…
ScriptedAlchemy Dec 2, 2024
9884030
Merge branch 'main' into consume-share-layers
ScriptedAlchemy Dec 2, 2024
3d8fa21
refactor(enhanced): pr review of consume share layering
ScriptedAlchemy Dec 3, 2024
69a2a52
Merge branch 'main' into consume-share-layers
ScriptedAlchemy Dec 3, 2024
04b8ffd
chore: locks
ScriptedAlchemy Dec 3, 2024
7852878
feat(enhanced): add request to consume share (#3307)
ScriptedAlchemy Dec 5, 2024
f35b1b1
Merge branch 'main' into consume-share-layers
ScriptedAlchemy Dec 5, 2024
b8df73e
chore: remove tt
ScriptedAlchemy Dec 9, 2024
b4b5a7b
chore: remove unused share
ScriptedAlchemy Dec 9, 2024
6f8f45e
refactor(enhanced): refactor type locations
ScriptedAlchemy Dec 10, 2024
875f516
feat(enhanced): ProvideSharedPlugin loader layer support (#3334)
ScriptedAlchemy Dec 12, 2024
673f6ca
Merge branch 'main' into consume-share-layers
ScriptedAlchemy Dec 12, 2024
20bae5b
chore: locks
ScriptedAlchemy Dec 12, 2024
a5774c8
chore(enhanced): add share plugin test
ScriptedAlchemy Dec 13, 2024
d44acbd
chore(enhanced): add share plugin test
ScriptedAlchemy Dec 13, 2024
1a33ac7
chore(enhanced): add share plugin test
ScriptedAlchemy Dec 13, 2024
1fc2b05
thing
ScriptedAlchemy Dec 13, 2024
29f6d73
thing
ScriptedAlchemy Dec 13, 2024
22127ee
chore(node): lint
ScriptedAlchemy Dec 13, 2024
8f9fb99
chore(node): lint
ScriptedAlchemy Dec 13, 2024
243f1bc
Merge branch 'main' into consume-share-layers
ScriptedAlchemy Dec 13, 2024
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
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"commit": "cz",
"docs": "typedoc",
"f": "nx format:write",
"enhanced:jest": "pnpm build && cd packages/enhanced && NODE_OPTIONS=--experimental-vm-modules npx jest test/ConfigTestCases.basictest.js",
"lint": "nx run-many --target=lint",
"test": "nx run-many --target=test",
"build": "nx run-many --target=build --parallel=5 --projects=tag:type:pkg",
Expand Down Expand Up @@ -228,6 +229,7 @@
"vue-tsc": "^2.0.26",
"wait-on": "^7.2.0",
"webpack": "5.93.0",
"webpack-cli": "^5.1.4",
"webpack-virtual-modules": "0.6.2",
"whatwg-fetch": "^3.6.20",
"yargs": "^17.7.2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,12 @@ export interface ConsumesConfig {
* Do not accept shared module if version is not valid (defaults to yes, if local fallback module is available and shared module is not a singleton, otherwise no, has no effect if there is no required version specified).
*/
strictVersion?: boolean;
/**
* Issuer layer in which the module should be resolved.
*/
issuerLayer?: string;
/**
* Layer for the shared module.
*/
layer?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,12 @@ export interface SharedConfig {
* Version of the provided module. Will replace lower matching versions, but not higher.
*/
version?: false | string;
/**
* Issuer layer in which the module should be resolved.
*/
issuerLayer?: string;
/**
* Layer for the shared module.
*/
layer?: string;
}
22 changes: 19 additions & 3 deletions packages/enhanced/src/lib/sharing/ConsumeSharedModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ export type ConsumeOptions = {
* include the fallback module in a sync way
*/
eager: boolean;
/**
* Share a specific layer of the module, if the module supports layers
*/
layer?: string | null;
/**
* Issuer layer in which the module should be resolved
*/
issuerLayer?: string | null;
};

/**
Expand All @@ -91,6 +99,8 @@ export type ConsumeOptions = {
* @property {boolean} strictVersion don't use shared version even if version isn't valid
* @property {boolean} singleton use single global version
* @property {boolean} eager include the fallback module in a sync way
* @property {string | null=} layer Share a specific layer of the module, if the module supports layers
* @property {string | null=} issuerLayer Issuer layer in which the module should be resolved
*/

const TYPES = new Set(['consume-shared']);
Expand All @@ -103,7 +113,11 @@ class ConsumeSharedModule extends Module {
* @param {ConsumeOptions} options consume options
*/
constructor(context: string, options: ConsumeOptions) {
super(WEBPACK_MODULE_TYPE_CONSUME_SHARED_MODULE, context);
super(
WEBPACK_MODULE_TYPE_CONSUME_SHARED_MODULE,
context,
options.layer ?? undefined,
);
this.options = options;
}

Expand All @@ -119,10 +133,11 @@ class ConsumeSharedModule extends Module {
strictVersion,
singleton,
eager,
layer,
} = this.options;
return `${WEBPACK_MODULE_TYPE_CONSUME_SHARED_MODULE}|${shareScope}|${shareKey}|${
requiredVersion && rangeToString(requiredVersion)
}|${strictVersion}|${importResolved}|${singleton}|${eager}`;
}|${strictVersion}|${importResolved}|${singleton}|${eager}|${layer}`;
}

/**
Expand All @@ -138,14 +153,15 @@ class ConsumeSharedModule extends Module {
strictVersion,
singleton,
eager,
layer,
} = this.options;
return `consume shared module (${shareScope}) ${shareKey}@${
requiredVersion ? rangeToString(requiredVersion) : '*'
}${strictVersion ? ' (strict)' : ''}${singleton ? ' (singleton)' : ''}${
importResolved
? ` (fallback: ${requestShortener.shorten(importResolved)})`
: ''
}${eager ? ' (eager)' : ''}`;
}${eager ? ' (eager)' : ''}${layer ? ` (${layer})` : ''}`;
}

/**
Expand Down
82 changes: 58 additions & 24 deletions packages/enhanced/src/lib/sharing/ConsumeSharedPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
normalizeWebpackPath,
} from '@module-federation/sdk/normalize-webpack-path';
import { isRequiredVersion } from '@module-federation/sdk';
import type { Compiler, Compilation } from 'webpack';
import type { Compiler, Compilation, Module } from 'webpack';
import { parseOptions } from '../container/options';
import { ConsumeOptions } from './ConsumeSharedModule';
import { ConsumeSharedPluginOptions } from '../../declarations/plugins/sharing/ConsumeSharedPlugin';
Expand All @@ -29,6 +29,7 @@ import ProvideForSharedDependency from './ProvideForSharedDependency';
import FederationRuntimePlugin from '../container/runtime/FederationRuntimePlugin';
import ShareRuntimeModule from './ShareRuntimeModule';
import type { SemVerRange } from 'webpack/lib/util/semver';
import type { ResolveData } from 'webpack/lib/NormalModuleFactory';

const ModuleNotFoundError = require(
normalizeWebpackPath('webpack/lib/ModuleNotFoundError'),
Expand All @@ -48,17 +49,8 @@ const createSchemaValidation = require(

const validate = createSchemaValidation(
//eslint-disable-next-line
require(
normalizeWebpackPath(
'webpack/schemas/plugins/sharing/ConsumeSharedPlugin.check.js',
),
),
() =>
require(
normalizeWebpackPath(
'webpack/schemas/plugins/sharing/ConsumeSharedPlugin.json',
),
),
require('../../schemas/sharing/ConsumeSharedPlugin.check.js'),
() => require('../../schemas/sharing/ConsumeSharedPlugin'),
{
name: 'Consume Shared Plugin',
baseDataPath: 'options',
Expand Down Expand Up @@ -94,6 +86,8 @@ class ConsumeSharedPlugin {
strictVersion: false,
singleton: false,
eager: false,
issuerLayer: undefined,
layer: undefined,
}
: // key is a request/key
// item is a version
Expand All @@ -107,6 +101,8 @@ class ConsumeSharedPlugin {
packageName: undefined,
singleton: false,
eager: false,
issuerLayer: undefined,
layer: undefined,
};
return result;
},
Expand All @@ -124,6 +120,8 @@ class ConsumeSharedPlugin {
packageName: item.packageName,
singleton: !!item.singleton,
eager: !!item.eager,
issuerLayer: item.issuerLayer ? item.issuerLayer : undefined,
layer: item.layer ? item.layer : undefined,
}),
);
}
Expand Down Expand Up @@ -296,33 +294,69 @@ class ConsumeSharedPlugin {

normalModuleFactory.hooks.factorize.tapPromise(
PLUGIN_NAME,
({ context, request, dependencies }) =>
async (resolveData: ResolveData): Promise<Module | undefined> => {
const { context, request, dependencies, contextInfo } = resolveData;
// wait for resolving to be complete
//@ts-ignore
promise.then(() => {
return promise.then(() => {
if (
dependencies[0] instanceof ConsumeSharedFallbackDependency ||
dependencies[0] instanceof ProvideForSharedDependency
) {
return;
}

// First try to match with layer-specific request
if (contextInfo.issuerLayer) {
// Try to find a layer-specific match
for (const [key, options] of unresolvedConsumes) {
Copy link

Choose a reason for hiding this comment

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

This should be handled in the unresolvedConsumes.get case below

Copy link
Member Author

Choose a reason for hiding this comment

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

Ive opened up a new PR with additional adjustments for this, it becomes hard to control due to how request is used.
I propose adding another option explicitly for controlling the request matching.

if (
options.issuerLayer === contextInfo.issuerLayer &&
(key === request ||
(options.import && options.import === request))
ScriptedAlchemy marked this conversation as resolved.
Show resolved Hide resolved
) {
return createConsumeSharedModule(context, request, {
...options,
layer: options.layer || contextInfo.issuerLayer,
});
}
}
}

// If no layer-specific match found, try regular matching
const match = unresolvedConsumes.get(request);
if (match !== undefined) {
return createConsumeSharedModule(context, request, match);
// Only use non-layer-specific match if it doesn't have issuerLayer
if (!match.issuerLayer) {
return createConsumeSharedModule(context, request, {
...match,
layer: match.layer || contextInfo.issuerLayer,
});
}
}

// Check prefixed consumes
for (const [prefix, options] of prefixedConsumes) {
if (request.startsWith(prefix)) {
const remainder = request.slice(prefix.length);
return createConsumeSharedModule(context, request, {
...options,
import: options.import
? options.import + remainder
: undefined,
shareKey: options.shareKey + remainder,
});
// Only use prefixed consume if layer matches or no layer specified
if (
!options.issuerLayer ||
options.issuerLayer === contextInfo.issuerLayer
) {
const remainder = request.slice(prefix.length);
return createConsumeSharedModule(context, request, {
...options,
import: options.import
? options.import + remainder
: undefined,
shareKey: options.shareKey + remainder,
layer: options.layer || contextInfo.issuerLayer,
});
}
}
}
}),
});
},
);
normalModuleFactory.hooks.createModule.tapPromise(
PLUGIN_NAME,
Expand Down
2 changes: 2 additions & 0 deletions packages/enhanced/src/lib/sharing/SharePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class SharePlugin {
singleton: options.singleton,
packageName: options.packageName,
eager: options.eager,
issuerLayer: options.issuerLayer,
layer: options.layer,
},
}),
);
Expand Down
Loading
Loading