Skip to content

Commit 436d1af

Browse files
PR8: SharePlugin - Unified API (#3914)
Co-authored-by: Claude <[email protected]>
1 parent 9f16eac commit 436d1af

File tree

28 files changed

+646
-257
lines changed

28 files changed

+646
-257
lines changed

.claude/hooks/prompt-optimizer.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,9 @@ async function main() {
209209
}
210210

211211
// Skip optimization for very short or simple prompts that don't need enhancement
212+
const wordCount = prompt.trim().split(/\s+/).length;
212213
if (
214+
wordCount <= 4 ||
213215
prompt.length < 10 ||
214216
/^(hi|hello|hey|thanks|thank you)$/i.test(prompt.trim())
215217
) {

.claude/settings.json

Lines changed: 0 additions & 15 deletions
This file was deleted.

.github/workflows/build-and-test.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ jobs:
5959
run: nproc
6060

6161
- name: Run Build for All
62-
run: npx nx run-many --targets=build --projects=tag:type:pkg --parallel=4
62+
run: |
63+
npx nx run-many --targets=build --projects=tag:type:pkg --parallel=4 --skip-nx-cache
64+
npx nx run-many --targets=build --projects=tag:type:pkg --parallel=4
6365
6466
- name: Check Package Publishing Compatibility
6567
run: |

apps/website/tmp/apps/website/tsconfig.tsbuildinfo

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
"@pmmmwh/react-refresh-webpack-plugin": "0.5.15",
125125
"@rollup/plugin-alias": "5.1.1",
126126
"@rollup/plugin-replace": "6.0.1",
127+
"@rslib/core": "^0.10.4",
127128
"@rspack/core": "1.3.9",
128129
"@rspack/dev-server": "1.1.1",
129130
"@semantic-release/changelog": "^6.0.3",

packages/enhanced/src/lib/sharing/SharePlugin.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ class SharePlugin {
4040
options.shared,
4141
(item, key) => {
4242
if (typeof item !== 'string')
43-
throw new Error('Unexpected array in shared');
43+
throw new Error(
44+
`Unexpected array in shared configuration for key "${key}"`,
45+
);
4446
const config: SharedConfig =
4547
item === key || !isRequiredVersion(item)
4648
? {
@@ -112,6 +114,7 @@ class SharePlugin {
112114
shareScope: this._shareScope,
113115
consumes: this._consumes,
114116
}).apply(compiler);
117+
115118
new ProvideSharedPlugin({
116119
shareScope: this._shareScope,
117120
provides: this._provides,
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
/*
2+
* @jest-environment node
3+
*/
4+
5+
import { createMockCompiler } from '../utils';
6+
import webpack from 'webpack';
7+
import path from 'path';
8+
import SharePlugin from '../../../src/lib/sharing/SharePlugin';
9+
10+
// Mock the child plugins to prevent deep integration testing
11+
jest.mock('../../../src/lib/sharing/ConsumeSharedPlugin', () => {
12+
return jest.fn().mockImplementation(() => ({
13+
apply: jest.fn(),
14+
}));
15+
});
16+
17+
jest.mock('../../../src/lib/sharing/ProvideSharedPlugin', () => {
18+
return jest.fn().mockImplementation(() => ({
19+
apply: jest.fn(),
20+
}));
21+
});
22+
23+
// Import mocked modules
24+
import ConsumeSharedPlugin from '../../../src/lib/sharing/ConsumeSharedPlugin';
25+
import ProvideSharedPlugin from '../../../src/lib/sharing/ProvideSharedPlugin';
26+
27+
describe('SharePlugin Compiler Integration', () => {
28+
let mockCompiler: webpack.Compiler;
29+
let mockCompilation: webpack.Compilation;
30+
31+
beforeEach(() => {
32+
mockCompiler = createMockCompiler();
33+
mockCompilation = {
34+
hooks: {
35+
afterOptimizeChunks: {
36+
tap: jest.fn(),
37+
},
38+
additionalTreeRuntimeRequirements: {
39+
tap: jest.fn(),
40+
},
41+
runtimeRequirementInTree: {
42+
for: jest.fn().mockReturnValue({ tap: jest.fn() }),
43+
},
44+
},
45+
compiler: mockCompiler,
46+
options: {
47+
context: path.resolve(__dirname, '../../../'),
48+
},
49+
dependencyFactories: new Map(),
50+
dependencyTemplates: new Map(),
51+
addRuntimeModule: jest.fn(),
52+
resolverFactory: {
53+
get: jest.fn().mockReturnValue({
54+
resolve: jest.fn(),
55+
}),
56+
},
57+
} as any;
58+
59+
// Clear mocks before each test
60+
(ConsumeSharedPlugin as jest.Mock).mockClear();
61+
(ProvideSharedPlugin as jest.Mock).mockClear();
62+
});
63+
64+
it('should integrate with webpack compilation lifecycle', () => {
65+
const plugin = new SharePlugin({
66+
shared: {
67+
react: '^17.0.0',
68+
lodash: {
69+
requiredVersion: '^4.17.0',
70+
singleton: true,
71+
},
72+
},
73+
});
74+
75+
// Apply the plugin
76+
plugin.apply(mockCompiler);
77+
78+
// Verify both child plugins are created and applied
79+
expect(ConsumeSharedPlugin).toHaveBeenCalledTimes(1);
80+
expect(ProvideSharedPlugin).toHaveBeenCalledTimes(1);
81+
82+
// Verify the plugins are applied to the compiler
83+
const consumeInstance = (ConsumeSharedPlugin as jest.Mock).mock.results[0]
84+
.value;
85+
const provideInstance = (ProvideSharedPlugin as jest.Mock).mock.results[0]
86+
.value;
87+
88+
expect(consumeInstance.apply).toHaveBeenCalledWith(mockCompiler);
89+
expect(provideInstance.apply).toHaveBeenCalledWith(mockCompiler);
90+
});
91+
92+
it('should handle advanced configuration with filters', () => {
93+
const plugin = new SharePlugin({
94+
shareScope: 'custom-scope',
95+
shared: {
96+
'react/': {
97+
include: {
98+
request: /components/,
99+
version: '^17.0.0',
100+
},
101+
nodeModulesReconstructedLookup: true,
102+
},
103+
lodash: {
104+
version: '4.17.21',
105+
singleton: true,
106+
eager: true,
107+
},
108+
},
109+
});
110+
111+
// Should not throw during plugin application
112+
expect(() => plugin.apply(mockCompiler)).not.toThrow();
113+
});
114+
115+
it('should handle fallback version configuration', () => {
116+
const plugin = new SharePlugin({
117+
shared: {
118+
react: {
119+
include: {
120+
version: '^17.0.0',
121+
fallbackVersion: '17.0.0',
122+
},
123+
},
124+
'utils/': {
125+
exclude: {
126+
version: '^2.0.0',
127+
fallbackVersion: '2.0.0',
128+
},
129+
},
130+
},
131+
});
132+
133+
// Should not throw during plugin application
134+
expect(() => plugin.apply(mockCompiler)).not.toThrow();
135+
});
136+
137+
it('should handle layer configuration', () => {
138+
const plugin = new SharePlugin({
139+
shared: {
140+
react: {
141+
layer: 'framework',
142+
issuerLayer: 'application',
143+
},
144+
utilities: {
145+
layer: 'utilities',
146+
},
147+
},
148+
});
149+
150+
// Should not throw during plugin application
151+
expect(() => plugin.apply(mockCompiler)).not.toThrow();
152+
});
153+
154+
it('should support multiple shareScopes', () => {
155+
const plugin = new SharePlugin({
156+
shareScope: ['primary', 'secondary'],
157+
shared: {
158+
react: '^17.0.0',
159+
lodash: {
160+
shareScope: 'custom',
161+
requiredVersion: '^4.17.0',
162+
},
163+
},
164+
});
165+
166+
// Should not throw during plugin application
167+
expect(() => plugin.apply(mockCompiler)).not.toThrow();
168+
});
169+
170+
it('should handle import false configuration', () => {
171+
const plugin = new SharePlugin({
172+
shared: {
173+
react: {
174+
import: false, // Only consume, don't provide
175+
requiredVersion: '^17.0.0',
176+
},
177+
lodash: {
178+
import: 'lodash-es', // Provide different module
179+
requiredVersion: '^4.17.0',
180+
},
181+
},
182+
});
183+
184+
// Should not throw during plugin application
185+
expect(() => plugin.apply(mockCompiler)).not.toThrow();
186+
});
187+
188+
it('should handle experiments configuration', () => {
189+
const plugin = new SharePlugin({
190+
shared: {
191+
react: '^17.0.0',
192+
},
193+
experiments: {
194+
nodeModulesReconstructedLookup: true,
195+
},
196+
});
197+
198+
// Should not throw during plugin application
199+
expect(() => plugin.apply(mockCompiler)).not.toThrow();
200+
});
201+
202+
it('should pass through all filtering options to child plugins', () => {
203+
const plugin = new SharePlugin({
204+
shareScope: 'test-scope',
205+
shared: {
206+
'components/': {
207+
include: {
208+
request: /Button|Modal/,
209+
version: '^1.0.0',
210+
},
211+
nodeModulesReconstructedLookup: true,
212+
singleton: true,
213+
eager: false,
214+
},
215+
react: {
216+
version: '17.0.0',
217+
strictVersion: true,
218+
packageName: 'react',
219+
layer: 'framework',
220+
issuerLayer: 'application',
221+
},
222+
},
223+
});
224+
225+
// Should create valid plugin instance
226+
expect(plugin).toBeInstanceOf(SharePlugin);
227+
228+
// Should not throw during plugin application
229+
expect(() => plugin.apply(mockCompiler)).not.toThrow();
230+
});
231+
232+
describe('helper methods integration', () => {
233+
it('should provide debugging information about shared modules', () => {
234+
const plugin = new SharePlugin({
235+
shareScope: 'debug-scope',
236+
shared: {
237+
react: '^17.0.0',
238+
lodash: {
239+
import: false,
240+
requiredVersion: '^4.17.0',
241+
},
242+
'utils/': {
243+
version: '1.0.0',
244+
nodeModulesReconstructedLookup: true,
245+
},
246+
},
247+
});
248+
249+
// Test all helper methods
250+
const options = plugin.getOptions();
251+
expect(options.shareScope).toBe('debug-scope');
252+
253+
const shareScope = plugin.getShareScope();
254+
expect(shareScope).toBe('debug-scope');
255+
256+
const consumes = plugin.getConsumes();
257+
expect(consumes).toHaveLength(3);
258+
259+
const provides = plugin.getProvides();
260+
expect(provides).toHaveLength(2); // lodash excluded due to import: false
261+
262+
const sharedInfo = plugin.getSharedInfo();
263+
expect(sharedInfo).toEqual({
264+
totalShared: 3,
265+
consumeOnly: 1,
266+
provideAndConsume: 2,
267+
shareScopes: ['debug-scope'],
268+
});
269+
});
270+
271+
it('should validate configurations during construction', () => {
272+
expect(() => {
273+
new SharePlugin({
274+
shared: {},
275+
});
276+
}).not.toThrow();
277+
278+
expect(() => {
279+
new SharePlugin({
280+
shared: {
281+
react: {
282+
include: { version: '^17.0.0' },
283+
exclude: { version: '^16.0.0' },
284+
},
285+
},
286+
});
287+
}).not.toThrow();
288+
});
289+
});
290+
});

0 commit comments

Comments
 (0)