@dotcms/experiments 1.6.0 → 1.7.0
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 +138 -56
- package/index.esm.js +813 -887
- package/package.json +5 -5
- package/src/index.d.ts +1 -0
- package/src/lib/components/DotExperimentHandlingComponent.d.ts +20 -0
- package/src/lib/components/DotExperimentsProvider.d.ts +17 -0
- package/src/lib/components/withExperiments.d.ts +20 -0
- package/src/lib/contexts/DotExperimentsContext.d.ts +12 -0
- package/src/lib/dot-experiments.d.ts +289 -0
- package/src/lib/hooks/useExperimentVariant.d.ts +17 -0
- package/src/lib/hooks/useExperiments.d.ts +14 -0
- package/src/lib/shared/constants.d.ts +95 -0
- package/src/lib/shared/mocks/mock.d.ts +43 -0
- package/src/lib/shared/models.d.ts +209 -0
- package/src/lib/shared/parser/parser.d.ts +54 -0
- package/src/lib/shared/persistence/index-db-database-handler.d.ts +87 -0
- package/src/lib/shared/utils/DotLogger.d.ts +15 -0
- package/src/lib/shared/utils/memoize.d.ts +7 -0
- package/src/lib/shared/utils/utils.d.ts +73 -0
- package/src/lib/standalone.d.ts +7 -0
package/README.md
CHANGED
|
@@ -22,12 +22,16 @@ The `@dotcms/experiments` SDK is the official dotCMS JavaScript library that hel
|
|
|
22
22
|
- [Overview](#overview)
|
|
23
23
|
- [Installation](#installation)
|
|
24
24
|
- [Getting Started](#getting-started)
|
|
25
|
+
- [Public API](#public-api)
|
|
25
26
|
- [withExperiments HOC](#withexperiments-higher-order-component)
|
|
26
27
|
- [Configuration Object](#configuration-object)
|
|
27
28
|
- [Usage](#usage)
|
|
28
|
-
- [With @dotcms/react](#with-dotcmsreact-recommended)
|
|
29
|
+
- [With @dotcms/react (Recommended)](#with-dotcmsreact-recommended)
|
|
30
|
+
- [Next.js App Router](#nextjs-app-router)
|
|
29
31
|
- [Configuration Best Practices](#configuration-best-practices)
|
|
32
|
+
- [Anti-patterns](#anti-patterns)
|
|
30
33
|
- [How It Works](#how-it-works)
|
|
34
|
+
- [Troubleshooting](#troubleshooting)
|
|
31
35
|
- [Support](#support)
|
|
32
36
|
- [Contributing](#contributing)
|
|
33
37
|
- [Licensing](#licensing)
|
|
@@ -46,11 +50,23 @@ Or using Yarn:
|
|
|
46
50
|
yarn add @dotcms/experiments
|
|
47
51
|
```
|
|
48
52
|
|
|
53
|
+
Align `@dotcms/experiments` with the same version line as your other `@dotcms/*` packages (for example `^1.5.6`).
|
|
54
|
+
|
|
49
55
|
## Getting Started
|
|
50
56
|
|
|
57
|
+
### Public API
|
|
58
|
+
|
|
59
|
+
The package exports **one** public symbol:
|
|
60
|
+
|
|
61
|
+
| Export | Description |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| `withExperiments` | HOC that wraps a layout component (typically `DotCMSLayoutBody`) with experiment handling |
|
|
64
|
+
|
|
65
|
+
`DotExperimentsProvider` and other internals are **not** part of the public API. Do not import them — `withExperiments` wires the provider internally.
|
|
66
|
+
|
|
51
67
|
### `withExperiments` Higher-Order Component
|
|
52
68
|
|
|
53
|
-
|
|
69
|
+
`withExperiments` wraps your page component with experiment functionality:
|
|
54
70
|
|
|
55
71
|
- User assignment to experiment variants
|
|
56
72
|
- Automatic redirection to the correct variant
|
|
@@ -58,67 +74,133 @@ The SDK exports a single HOC (Higher-Order Component) called `withExperiments` t
|
|
|
58
74
|
- Automatic page view tracking to dotCMS Analytics
|
|
59
75
|
- Click event handling to maintain variant consistency across navigation
|
|
60
76
|
|
|
77
|
+
> **Important:** `withExperiments` uses React hooks internally. It must be called **unconditionally** on every render of the component that uses it. See [Anti-patterns](#anti-patterns).
|
|
78
|
+
|
|
61
79
|
### Configuration Object
|
|
62
80
|
|
|
63
81
|
The `config` object passed to `withExperiments` accepts the following properties:
|
|
64
82
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
83
|
+
| Property | Required | Default | Description |
|
|
84
|
+
| --- | --- | --- | --- |
|
|
85
|
+
| `apiKey` | Yes | — | jsKey from the dotCMS Analytics / Experiments app (frontend key, not m2m) |
|
|
86
|
+
| `server` | Yes | — | dotCMS **origin** URL (e.g. `https://your-dotcms-instance.com`) — not a CDN |
|
|
87
|
+
| `redirectFn` | No | `window.location.replace` | SPA redirect function (e.g. `router.replace` in Next.js) |
|
|
88
|
+
| `trackPageView` | No | `true` | Enable/disable automatic page view tracking |
|
|
89
|
+
| `debug` | No | `false` | Verbose logging in the browser console |
|
|
70
90
|
|
|
71
91
|
## Usage
|
|
72
92
|
|
|
73
93
|
### With @dotcms/react (Recommended)
|
|
74
94
|
|
|
75
|
-
|
|
95
|
+
Use **separate views or routes** for pages with and without experiments. This avoids calling `withExperiments` conditionally in the same component.
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
// views/StandardPage.tsx — no experiments
|
|
99
|
+
"use client";
|
|
100
|
+
|
|
101
|
+
import { DotCMSLayoutBody, useEditableDotCMSPage } from "@dotcms/react";
|
|
102
|
+
|
|
103
|
+
import { pageComponents } from "@/components/content-types";
|
|
76
104
|
|
|
77
|
-
|
|
105
|
+
export function StandardPage({ pageContent }) {
|
|
106
|
+
const { pageAsset } = useEditableDotCMSPage(pageContent);
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<main>
|
|
110
|
+
<DotCMSLayoutBody page={pageAsset} components={pageComponents} />
|
|
111
|
+
</main>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
// views/ExperimentsPage.tsx — experiments always enabled on this view
|
|
78
118
|
"use client";
|
|
79
119
|
|
|
80
120
|
import { withExperiments } from "@dotcms/experiments";
|
|
81
121
|
import { DotCMSLayoutBody, useEditableDotCMSPage } from "@dotcms/react";
|
|
82
|
-
import { useRouter } from
|
|
122
|
+
import { useRouter } from "next/navigation";
|
|
83
123
|
|
|
84
|
-
|
|
85
|
-
const experimentConfig = {
|
|
86
|
-
apiKey: process.env.NEXT_PUBLIC_EXPERIMENTS_API_KEY,
|
|
87
|
-
server: process.env.NEXT_PUBLIC_DOTCMS_HOST,
|
|
88
|
-
debug: true
|
|
89
|
-
};
|
|
124
|
+
import { pageComponents } from "@/components/content-types";
|
|
90
125
|
|
|
91
|
-
export function
|
|
126
|
+
export function ExperimentsPage({ pageContent }) {
|
|
92
127
|
const { pageAsset } = useEditableDotCMSPage(pageContent);
|
|
93
128
|
const { replace } = useRouter();
|
|
94
129
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
: DotCMSLayoutBody;
|
|
130
|
+
const LayoutBody = withExperiments(DotCMSLayoutBody, {
|
|
131
|
+
apiKey: process.env.NEXT_PUBLIC_DOTCMS_ANALYTICS_KEY!,
|
|
132
|
+
server: process.env.NEXT_PUBLIC_DOTCMS_HOST!,
|
|
133
|
+
redirectFn: replace,
|
|
134
|
+
debug: process.env.NEXT_PUBLIC_DOTCMS_DEBUG === "true",
|
|
135
|
+
});
|
|
102
136
|
|
|
103
137
|
return (
|
|
104
138
|
<main>
|
|
105
|
-
<
|
|
106
|
-
page={pageAsset}
|
|
107
|
-
components={pageComponents}
|
|
108
|
-
/>
|
|
139
|
+
<LayoutBody page={pageAsset} components={pageComponents} />
|
|
109
140
|
</main>
|
|
110
141
|
);
|
|
111
142
|
}
|
|
112
143
|
```
|
|
113
144
|
|
|
114
|
-
|
|
145
|
+
Wire each view to its own route in the App Router (for example `/blog` for experiments, catch-all for standard pages).
|
|
146
|
+
|
|
147
|
+
> **Learn more about `DotCMSLayoutBody`**: See the [@dotcms/react SDK documentation](https://github.com/dotCMS/core/blob/main/core-web/libs/sdk/react/README.md#dotcmslayoutbody).
|
|
148
|
+
|
|
149
|
+
### Next.js App Router
|
|
150
|
+
|
|
151
|
+
Canonical working example: [`examples/nextjs-analytics-experiments`](../../../../examples/nextjs-analytics-experiments)
|
|
152
|
+
|
|
153
|
+
That project demonstrates:
|
|
154
|
+
|
|
155
|
+
- Analytics on all routes via `@dotcms/analytics` in `layout.tsx`
|
|
156
|
+
- Experiments isolated to `/blog` via `withExperiments` in a dedicated view
|
|
157
|
+
- Safe separation that avoids rules-of-hooks violations in UVE
|
|
158
|
+
|
|
159
|
+
**Environment variables** (see the example's `.env.local.example`):
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
NEXT_PUBLIC_DOTCMS_HOST=http://localhost:8080 # dotCMS origin — NOT a CDN
|
|
163
|
+
NEXT_PUBLIC_DOTCMS_ANALYTICS_KEY= # jsKey (frontend key)
|
|
164
|
+
NEXT_PUBLIC_DOTCMS_DEBUG=true
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Verification** (DevTools → Network):
|
|
168
|
+
|
|
169
|
+
1. On experiment routes: `POST {HOST}/api/v1/experiments/isUserIncluded`
|
|
170
|
+
2. With `debug: true`: `[dotCMS ...]` logs in the console
|
|
171
|
+
3. Open the page in UVE — no "client-side exception" overlay
|
|
115
172
|
|
|
116
173
|
### Configuration Best Practices
|
|
117
174
|
|
|
118
|
-
- **Use
|
|
119
|
-
- **
|
|
120
|
-
- **Framework
|
|
121
|
-
- **
|
|
175
|
+
- **Use environment variables** for `apiKey` and `server`
|
|
176
|
+
- **Dedicated routes/views** for experiment pages — do not toggle `withExperiments` with a ternary on `apiKey` in the same component
|
|
177
|
+
- **Framework router**: pass `router.replace` (Next.js) or equivalent to `redirectFn` for SPA navigation
|
|
178
|
+
- **Origin URL**: `server` must point to the dotCMS instance origin. Do not use Azure Front Door, CloudFront, or other CDNs — experiment API responses are session-specific and must not be cached at the edge
|
|
179
|
+
- **Aligned SDK versions**: keep `@dotcms/client`, `@dotcms/react`, `@dotcms/uve`, `@dotcms/types`, and `@dotcms/experiments` on the same version line
|
|
180
|
+
- **Debug mode**: enable during development to troubleshoot assignment issues
|
|
181
|
+
|
|
182
|
+
### Anti-patterns
|
|
183
|
+
|
|
184
|
+
Do **not** use these patterns — they can crash Next.js App Router pages and the UVE editor:
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
// ❌ Conditional withExperiments — violates rules of hooks
|
|
188
|
+
const Layout = experimentConfig.apiKey
|
|
189
|
+
? withExperiments(DotCMSLayoutBody, config)
|
|
190
|
+
: DotCMSLayoutBody;
|
|
191
|
+
|
|
192
|
+
// ❌ Early return before withExperiments in the same component
|
|
193
|
+
if (!apiKey) return <DotCMSLayoutBody {...props} />;
|
|
194
|
+
const Layout = withExperiments(DotCMSLayoutBody, config);
|
|
195
|
+
|
|
196
|
+
// ❌ Importing internal provider
|
|
197
|
+
import { DotExperimentsProvider } from "@dotcms/experiments";
|
|
198
|
+
|
|
199
|
+
// ❌ CDN as server
|
|
200
|
+
server: "https://cdn.example.com"
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Use separate components/routes instead (see [With @dotcms/react](#with-dotcmsreact-recommended)).
|
|
122
204
|
|
|
123
205
|
### How It Works
|
|
124
206
|
|
|
@@ -130,35 +212,33 @@ Once you wrap your component with `withExperiments`, the SDK automatically handl
|
|
|
130
212
|
4. **Navigation Handling**: Maintains variant consistency when users click links
|
|
131
213
|
5. **Analytics Tracking**: Sends pageview events to DotCMS Analytics automatically
|
|
132
214
|
|
|
133
|
-
|
|
215
|
+
**Learn More**: [DotCMS A/B Testing Experiments](https://www.dotcms.com/product/ab-testing-experiments)
|
|
134
216
|
|
|
135
|
-
|
|
217
|
+
## Troubleshooting
|
|
136
218
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
219
|
+
| Symptom | Likely cause | What to do |
|
|
220
|
+
| --- | --- | --- |
|
|
221
|
+
| UVE crash: "A client-side exception has occurred" | `withExperiments` called conditionally, or experiments initializing before UVE state is ready | Use a dedicated experiments view; never use `apiKey ? withExperiments(...) : DotCMSLayoutBody` |
|
|
222
|
+
| `GET /api/v1/experiments/DEFAULT` 404 | Known backoffice issue — variant name `"DEFAULT"` passed as experiment ID | Harmless in headless apps; backoffice fix tracked separately |
|
|
223
|
+
| "No experiments assigned to the client" | Experiment not in `Running` status, or no analytics session yet | Confirm experiment status in dotCMS; verify `apiKey` and `server` |
|
|
224
|
+
| No `isUserIncluded` request | Missing `apiKey`, wrong route, or experiments view not mounted | Check env vars; confirm the page uses the experiments view |
|
|
225
|
+
| Events go to wrong host | `server` points to CDN instead of dotCMS origin | Set `server` to the dotCMS instance URL |
|
|
140
226
|
|
|
141
|
-
|
|
142
|
-
- **Community Forum**: Join our [community discussions](https://community.dotcms.com/) to ask questions and share solutions
|
|
143
|
-
- **Stack Overflow**: Use the tag `dotcms-experiments` when posting questions
|
|
144
|
-
- **Enterprise Support**: Enterprise customers can access premium support through the [dotCMS Support Portal](https://helpdesk.dotcms.com/support/)
|
|
227
|
+
## Support
|
|
145
228
|
|
|
146
|
-
|
|
229
|
+
- **GitHub Issues**: [open an issue](https://github.com/dotCMS/core/issues/new/choose)
|
|
230
|
+
- **Community Forum**: [community.dotcms.com](https://community.dotcms.com/)
|
|
231
|
+
- **Stack Overflow**: tag `dotcms-experiments`
|
|
232
|
+
- **Enterprise Support**: [dotCMS Support](https://www.dotcms.com/support)
|
|
147
233
|
|
|
148
|
-
|
|
149
|
-
- Framework/library version (if applicable)
|
|
150
|
-
- Minimal reproduction steps
|
|
151
|
-
- Expected vs. actual behavior
|
|
234
|
+
When reporting issues, include SDK version, framework version, minimal reproduction steps, and expected vs. actual behavior.
|
|
152
235
|
|
|
153
236
|
## Contributing
|
|
154
237
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
160
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
161
|
-
5. Open a Pull Request
|
|
238
|
+
1. Fork [dotCMS/core](https://github.com/dotCMS/core)
|
|
239
|
+
2. Create a feature branch
|
|
240
|
+
3. Commit your changes
|
|
241
|
+
4. Open a Pull Request
|
|
162
242
|
|
|
163
243
|
Please ensure your code follows the existing style and includes appropriate tests.
|
|
164
244
|
|
|
@@ -166,6 +246,8 @@ Before any pull requests can be accepted, an automated tool will ask you to agre
|
|
|
166
246
|
|
|
167
247
|
## Licensing
|
|
168
248
|
|
|
169
|
-
dotCMS
|
|
249
|
+
dotCMS is available under either the [Business Source License 1.1 (BSL)](https://www.dotcms.com/bsl) or a commercial license.
|
|
250
|
+
|
|
251
|
+
Under the BSL, dotCMS can be used at no cost by individual developers, small businesses or agencies under $5M in total finances, and by larger organizations in non-production environments. Every BSL release automatically converts to GPL v3 four years after its release date. For full terms and FAQs, visit [dotcms.com/bsl](https://www.dotcms.com/bsl) and [dotcms.com/bsl-faq](https://www.dotcms.com/bsl-faq).
|
|
170
252
|
|
|
171
|
-
|
|
253
|
+
Production use in larger organizations, along with access to managed cloud, SLAs, support, and enterprise capabilities, is available under a commercial license from dotCMS. For details on commercial plans, features, and support options, see [dotcms.com/pricing](https://www.dotcms.com/pricing).
|