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

[Breaking change] Upgrade to JS SDK v11. Remove trafficType parameter, which is now mandatory in track calls. #208

Merged
merged 24 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f23f0a4
Upgrade JS SDK to v11, which has clients without bound traffic type
EmilianoSanchez Oct 22, 2024
4688ff0
Update changelog entry
EmilianoSanchez Oct 22, 2024
628b185
Make factory and client context properties available in first render …
EmilianoSanchez Oct 23, 2024
833d6c9
Added test to validate bugfix
EmilianoSanchez Oct 24, 2024
6bfb15b
Polishing
EmilianoSanchez Oct 24, 2024
e1bad0a
Added test to validate useTrack does not re-render
EmilianoSanchez Oct 24, 2024
e262600
Polishing
EmilianoSanchez Oct 24, 2024
fec84b3
Polishing
EmilianoSanchez Oct 24, 2024
5009c20
Merge pull request #203 from splitio/remove_deprecated_modules
EmilianoSanchez Oct 24, 2024
e633ad2
Merge pull request #204 from splitio/rename_SplitSdk_to_SplitFactory
EmilianoSanchez Oct 24, 2024
7691dd9
Merge pull request #205 from splitio/react_v2_functional_components
EmilianoSanchez Oct 24, 2024
c33577f
Merge pull request #206 from splitio/error_handling_updates
EmilianoSanchez Oct 24, 2024
2cbc1d0
Merge branch 'breaking_changes_baseline' into issue_198_factory_avail…
EmilianoSanchez Oct 24, 2024
bafcfd9
Update JS SDK to use updated Type declaration files
EmilianoSanchez Oct 25, 2024
465af41
Fix import
EmilianoSanchez Oct 25, 2024
2d1a0d0
test namespace implicit import
EmilianoSanchez Oct 26, 2024
dff8b1f
Update changelog entry
EmilianoSanchez Oct 26, 2024
2c311b9
Add TSDoc linter rules
EmilianoSanchez Oct 29, 2024
d26572e
Update changelog entry
EmilianoSanchez Oct 30, 2024
eb475cd
Upgrade JS SDK
EmilianoSanchez Oct 31, 2024
54b13ca
Polishing
EmilianoSanchez Oct 31, 2024
41d960b
rollback ci-cd
EmilianoSanchez Oct 31, 2024
6a723c7
Merge pull request #213 from splitio/refactor_type_definitions
EmilianoSanchez Oct 31, 2024
3b3eabc
Merge pull request #211 from splitio/issue_198_factory_available_in_i…
EmilianoSanchez Oct 31, 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
3 changes: 2 additions & 1 deletion CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
2.0.0 (October XX, 2024)
- Added support for targeting rules based on large segments for browsers.
- Updated @splitsoftware/splitio package to version 10.29.0 that includes minor updates, and updated some transitive dependencies for vulnerability fixes.
- Updated @splitsoftware/splitio package to version 11.0.0 that includes major updates, and updated some transitive dependencies for vulnerability fixes.
- Renamed distribution folders from `/lib` to `/cjs` for CommonJS build, and `/es` to `/esm` for EcmaScript Modules build.
- BREAKING CHANGES:
- Updated error handling: using the library modules without wrapping them in a `SplitFactoryProvider` component will now throw an error instead of logging it, as the modules requires the `SplitContext` to work properly.
- Removed the `core.trafficType` configuration option and the `trafficType` parameter from the SDK `client()` method, `useSplitClient`, `useTrack`, and `SplitClient` component. This is because traffic types can no longer be bound to SDK clients in JavaScript SDK v11.0.0, and so the traffic type must be provided as first argument in the `track` method calls.
- Removed deprecated modules: `SplitFactory` component, `useClient`, `useTreatments` and `useManager` hooks, and `withSplitFactory`, `withSplitClient` and `withSplitTreatments` high-order components. Refer to ./MIGRATION-GUIDE.md for instructions on how to migrate to the new alternatives.
- Renamed TypeScript interfaces `ISplitFactoryProps` to `ISplitFactoryProviderProps`, and `ISplitFactoryChildProps` to `ISplitFactoryProviderChildProps`.
- Renamed `SplitSdk` to `SplitFactory` function, which is the underlying Split SDK factory, i.e., `import { SplitFactory } from '@splitsoftware/splitio'`.
Expand Down
47 changes: 17 additions & 30 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
},
"homepage": "https://github.com/splitio/react-client#readme",
"dependencies": {
"@splitsoftware/splitio": "10.28.1-rc.2",
"@splitsoftware/splitio": "11.0.0-rc.1",
"memoize-one": "^5.1.1",
"shallowequal": "^1.1.0",
"tslib": "^2.3.1"
Expand Down
2 changes: 1 addition & 1 deletion src/SplitClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useSplitClient } from './useSplitClient';
* Children components will have access to the new client when accessing Split Context.
*
* The underlying SDK client can be changed during the component lifecycle
* if the component is updated with a different splitKey or trafficType prop.
* if the component is updated with a different splitKey prop.
*
* @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#advanced-instantiate-multiple-sdk-clients}
*/
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/SplitClient.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ describe('SplitClient', () => {
function Component({ attributesFactory, attributesClient, splitKey, testSwitch, factory }: TestComponentProps) {
return (
<SplitFactoryProvider factory={factory} attributes={attributesFactory} >
<SplitClient splitKey={splitKey} attributes={attributesClient} trafficType='user' >
<SplitClient splitKey={splitKey} attributes={attributesClient} >
{() => {
testSwitch(done, splitKey);
return null;
Expand Down
11 changes: 5 additions & 6 deletions src/__tests__/testUtils/mockSplitFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ function parseKey(key: SplitIO.SplitKey): SplitIO.SplitKey {
};
}
}
function buildInstanceId(key: any, trafficType: string | undefined) {
function buildInstanceId(key: any, trafficType?: string) {
return `${key.matchingKey ? key.matchingKey : key}-${key.bucketingKey ? key.bucketingKey : key}-${trafficType !== undefined ? trafficType : ''}`;
}

export function mockSdk() {

return jest.fn((config: SplitIO.IBrowserSettings, __updateModules) => {

function mockClient(_key: SplitIO.SplitKey, _trafficType?: string) {
function mockClient(_key: SplitIO.SplitKey) {
// Readiness
let isReady = false;
let isReadyFromCache = false;
Expand Down Expand Up @@ -135,11 +135,10 @@ export function mockSdk() {

// Cache of clients
const __clients__: { [instanceId: string]: any } = {};
const client = jest.fn((key?: string, trafficType?: string) => {
const client = jest.fn((key?: string) => {
const clientKey = key || parseKey(config.core.key);
const clientTT = trafficType || config.core.trafficType;
const instanceId = buildInstanceId(clientKey, clientTT);
return __clients__[instanceId] || (__clients__[instanceId] = mockClient(clientKey, clientTT));
const instanceId = buildInstanceId(clientKey);
return __clients__[instanceId] || (__clients__[instanceId] = mockClient(clientKey));
});

// Factory destroy
Expand Down
16 changes: 8 additions & 8 deletions src/__tests__/useSplitClient.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ describe('useSplitClient', () => {
<SplitFactoryProvider factory={outerFactory} >
{React.createElement(() => {
(outerFactory.client as jest.Mock).mockClear();
client = useSplitClient({ splitKey: 'user2', trafficType: 'user' }).client;
client = useSplitClient({ splitKey: 'user2' }).client;
return null;
})}
</SplitFactoryProvider>
);
expect(outerFactory.client as jest.Mock).toBeCalledWith('user2', 'user');
expect(outerFactory.client as jest.Mock).toBeCalledWith('user2');
expect(outerFactory.client as jest.Mock).toHaveReturnedWith(client);
});

Expand All @@ -70,7 +70,7 @@ describe('useSplitClient', () => {
render(
React.createElement(() => {
useSplitClient();
useSplitClient({ splitKey: 'user2', trafficType: 'user' });
useSplitClient({ splitKey: 'user2' });
return null;
})
);
Expand All @@ -81,7 +81,7 @@ describe('useSplitClient', () => {

// eslint-disable-next-line react/prop-types
const InnerComponent = ({ splitKey, attributesClient, testSwitch }) => {
useSplitClient({ splitKey, trafficType: 'user', attributes: attributesClient });
useSplitClient({ splitKey, attributes: attributesClient });
testSwitch(done, splitKey);
return null;
};
Expand Down Expand Up @@ -112,16 +112,16 @@ describe('useSplitClient', () => {
<SplitContext.Consumer>
{() => countSplitContext++}
</SplitContext.Consumer>
<SplitClient splitKey={sdkBrowser.core.key} trafficType={sdkBrowser.core.trafficType}
<SplitClient splitKey={sdkBrowser.core.key}
/* Disabling update props is ineffective because the wrapping SplitFactoryProvider has them enabled: */
updateOnSdkReady={false} updateOnSdkReadyFromCache={false}
>
{() => { countSplitClient++; return null }}
</SplitClient>
{React.createElement(() => {
// Equivalent to
// - Using config key and traffic type: `const { client } = useSplitClient(sdkBrowser.core.key, sdkBrowser.core.trafficType, { att1: 'att1' });`
// - Disabling update props, since the wrapping SplitFactoryProvider has them enabled: `const { client } = useSplitClient(undefined, undefined, { att1: 'att1' }, { updateOnSdkReady: false, updateOnSdkReadyFromCache: false });`
// - Using config key: `const { client } = useSplitClient({ splitKey: sdkBrowser.core.key, attributes: { att1: 'att1' } });`
// - Disabling update props, since the wrapping SplitFactoryProvider has them enabled: `const { client } = useSplitClient({ attributes: { att1: 'att1' }, updateOnSdkReady: false, updateOnSdkReadyFromCache: false });`
const { client } = useSplitClient({ attributes: { att1: 'att1' } });
expect(client).toBe(mainClient); // Assert that the main client was retrieved.
expect(client!.getAttributes()).toEqual({ att1: 'att1' }); // Assert that the client was retrieved with the provided attributes.
Expand All @@ -141,7 +141,7 @@ describe('useSplitClient', () => {
{() => { countSplitClientWithUpdate++; return null }}
</SplitClient>
{React.createElement(() => {
useSplitClient({ splitKey: sdkBrowser.core.key, trafficType: sdkBrowser.core.trafficType, updateOnSdkUpdate: true }).client;
useSplitClient({ splitKey: sdkBrowser.core.key, updateOnSdkUpdate: true }).client;
countUseSplitClientWithUpdate++;
return null;
})}
Expand Down
15 changes: 7 additions & 8 deletions src/__tests__/useTrack.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,31 +62,30 @@ describe('useTrack', () => {
expect(track).toHaveReturnedWith(trackResult);
});

test('returns the track method bound to a new client given a splitKey and optional trafficType.', () => {
test('returns the track method bound to a new client given a splitKey.', () => {
const outerFactory = SplitFactory(sdkBrowser);
let boundTrack;
let trackResult;

render(
<SplitFactoryProvider factory={outerFactory} >
{React.createElement(() => {
boundTrack = useTrack('user2', tt);
trackResult = boundTrack(eventType, value, properties);
const boundTrack = useTrack('user2');
trackResult = boundTrack(tt, eventType, value, properties);
return null;
})}
</SplitFactoryProvider>,
);
const track = outerFactory.client('user2', tt).track as jest.Mock;
expect(track).toBeCalledWith(eventType, value, properties);
const track = outerFactory.client('user2').track as jest.Mock;
expect(track).toBeCalledWith(tt, eventType, value, properties);
expect(track).toHaveReturnedWith(trackResult);
});

test('throws error if invoked outside of SplitFactoryProvider.', () => {
expect(() => {
render(
React.createElement(() => {
const track = useTrack('user2', tt);
track(eventType, value, properties);
const track = useTrack('user2');
track(tt, eventType, value, properties);
return null;
}),
);
Expand Down
6 changes: 0 additions & 6 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,6 @@ export interface IUseSplitClientOptions extends IUpdateProps {
*/
splitKey?: SplitIO.SplitKey;

/**
* Traffic type associated with the customer identifier.
* If no provided here or at the config object, it will be required on the client.track() calls.
*/
trafficType?: string;

/**
* An object of type Attributes used to evaluate the feature flags.
*/
Expand Down
6 changes: 3 additions & 3 deletions src/useSplitClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const DEFAULT_UPDATE_OPTIONS = {
};

/**
* 'useSplitClient' is a hook that returns an Split Context object with the client and its status corresponding to the provided key and trafficType.
* 'useSplitClient' is a hook that returns an Split Context object with the client and its status corresponding to the provided key.
* It uses the 'useContext' hook to access the context, which is updated by SplitFactoryProvider and SplitClient components in the hierarchy of components.
*
* @returns A Split Context object
Expand All @@ -25,7 +25,7 @@ export const DEFAULT_UPDATE_OPTIONS = {
*/
export function useSplitClient(options?: IUseSplitClientOptions): ISplitContextValues {
const {
updateOnSdkReady, updateOnSdkReadyFromCache, updateOnSdkTimedout, updateOnSdkUpdate, splitKey, trafficType, attributes
updateOnSdkReady, updateOnSdkReadyFromCache, updateOnSdkTimedout, updateOnSdkUpdate, splitKey, attributes
} = { ...DEFAULT_UPDATE_OPTIONS, ...options };

const context = useSplitContext();
Expand All @@ -34,7 +34,7 @@ export function useSplitClient(options?: IUseSplitClientOptions): ISplitContextV
let client = contextClient as IClientWithContext;
if (splitKey && factory) {
// @TODO `getSplitClient` starts client sync. Move side effects to useEffect
client = getSplitClient(factory, splitKey, trafficType);
client = getSplitClient(factory, splitKey);
}
initAttributes(client, attributes);

Expand Down
4 changes: 2 additions & 2 deletions src/useTrack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ const noOpFalse = () => false;
*
* @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#track}
*/
export function useTrack(splitKey?: SplitIO.SplitKey, trafficType?: string): SplitIO.IBrowserClient['track'] {
export function useTrack(splitKey?: SplitIO.SplitKey): SplitIO.IBrowserClient['track'] {
// All update options are false to avoid re-renders. The track method doesn't need the client to be operational.
const { client } = useSplitClient({ splitKey, trafficType, updateOnSdkReady: false, updateOnSdkReadyFromCache: false });
const { client } = useSplitClient({ splitKey, updateOnSdkReady: false, updateOnSdkReadyFromCache: false });
return client ? client.track.bind(client) : noOpFalse;
}
6 changes: 3 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ export function getSplitFactory(config: SplitIO.IBrowserSettings) {
}

// idempotent operation
export function getSplitClient(factory: SplitIO.IBrowserSDK, key?: SplitIO.SplitKey, trafficType?: string): IClientWithContext {
export function getSplitClient(factory: SplitIO.IBrowserSDK, key?: SplitIO.SplitKey): IClientWithContext {
// factory.client is an idempotent operation
const client = (key !== undefined ? factory.client(key, trafficType) : factory.client()) as IClientWithContext;
const client = (key !== undefined ? factory.client(key) : factory.client()) as IClientWithContext;

// Remove EventEmitter warning emitted when using multiple SDK hooks or components.
// Unlike JS SDK, users don't need to access the client directly, making the warning irrelevant.
client.setMaxListeners(0);
client.setMaxListeners && client.setMaxListeners(0);

return client;
}
Expand Down
Loading