@mvtlab/nextjs-orchestrator 0.1.3 → 0.2.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 +140 -97
- package/dist/MVTOrchestrator.d.ts +6 -2
- package/dist/MVTOrchestrator.js +34 -20
- package/dist/MVTScripts.d.ts +46 -0
- package/dist/MVTScripts.js +34 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/@mvtlab/nextjs-orchestrator)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
React
|
|
7
|
+
React SDK for integrating the MVTLab.io CDN engine into Next.js applications with anti-flicker support.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -22,35 +22,34 @@ yarn add @mvtlab/nextjs-orchestrator
|
|
|
22
22
|
|
|
23
23
|
## Quick Start
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
### Recommended — App Router (SSR-safe, no flicker)
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
Use `MVTScripts` in your root `layout.tsx`. It is a **Server Component** — no `'use client'`
|
|
28
|
+
needed — so the anti-flicker style and engine script are injected into the server-rendered
|
|
29
|
+
HTML and execute before React hydration, preventing any content flash.
|
|
28
30
|
|
|
29
31
|
```tsx
|
|
30
32
|
// app/layout.tsx
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
import { MVTOrchestrator } from '@mvtlab/nextjs-orchestrator';
|
|
33
|
+
import { MVTScripts } from '@mvtlab/nextjs-orchestrator';
|
|
34
34
|
|
|
35
35
|
export default function RootLayout({ children }) {
|
|
36
36
|
return (
|
|
37
37
|
<html lang="en">
|
|
38
38
|
<body>
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
</MVTOrchestrator>
|
|
39
|
+
<MVTScripts orchestratorKey="YOUR_PROJECT_KEY" />
|
|
40
|
+
{children}
|
|
42
41
|
</body>
|
|
43
42
|
</html>
|
|
44
43
|
);
|
|
45
44
|
}
|
|
46
45
|
```
|
|
47
46
|
|
|
47
|
+
That's it. No `'use client'` required.
|
|
48
|
+
|
|
48
49
|
### Pages Router
|
|
49
50
|
|
|
50
51
|
```tsx
|
|
51
52
|
// pages/_app.tsx
|
|
52
|
-
'use client';
|
|
53
|
-
|
|
54
53
|
import { MVTOrchestrator } from '@mvtlab/nextjs-orchestrator';
|
|
55
54
|
|
|
56
55
|
export default function MyApp({ Component, pageProps }) {
|
|
@@ -62,150 +61,192 @@ export default function MyApp({ Component, pageProps }) {
|
|
|
62
61
|
}
|
|
63
62
|
```
|
|
64
63
|
|
|
65
|
-
> **Why `'use client'`?** The component injects scripts and styles, accesses `window`/`document`, and defines `window.rmfk`—all browser-only operations that can't run in server components.
|
|
66
|
-
|
|
67
64
|
---
|
|
68
65
|
|
|
69
|
-
##
|
|
66
|
+
## Components
|
|
70
67
|
|
|
71
|
-
###
|
|
68
|
+
### `MVTScripts` — Server Component ✅ Recommended
|
|
72
69
|
|
|
73
|
-
|
|
74
|
-
|------|------|----------|---------|-------------|
|
|
75
|
-
| `orchestratorKey` | `string` | ✅ | - | MVTLab.io project key (passed as `data-project-key`) |
|
|
76
|
-
| `children` | `ReactNode` | ✅ | - | App content to wrap |
|
|
77
|
-
| `antiFlickerEnabled` | `boolean` | ❌ | `true` | Inject temporary `body{opacity:0}` style until engine ready |
|
|
78
|
-
| `antiFlickerTimeoutMs` | `number` | ❌ | `3000` | Fallback timeout to remove anti-flicker style |
|
|
70
|
+
Place once at the top of `<body>` in your root `layout.tsx`.
|
|
79
71
|
|
|
80
|
-
|
|
72
|
+
Renders two script tags directly into the server HTML:
|
|
73
|
+
|
|
74
|
+
1. An **inline anti-flicker script** that sets `body { opacity: 0 }` and exposes
|
|
75
|
+
`window.rmfk()` — runs synchronously before any page content is visible.
|
|
76
|
+
2. The **MVT engine `<script async>`** that loads the CDN, applies variant changes,
|
|
77
|
+
then calls `window.rmfk()` to reveal the page.
|
|
81
78
|
|
|
82
79
|
```tsx
|
|
83
|
-
import
|
|
80
|
+
import { MVTScripts } from '@mvtlab/nextjs-orchestrator';
|
|
81
|
+
|
|
82
|
+
<MVTScripts
|
|
83
|
+
orchestratorKey="YOUR_PROJECT_KEY"
|
|
84
|
+
antiFlickerEnabled={true} // default
|
|
85
|
+
antiFlickerTimeoutMs={3000} // default
|
|
86
|
+
/>
|
|
84
87
|
```
|
|
85
88
|
|
|
86
|
-
|
|
89
|
+
| Prop | Type | Default | Description |
|
|
90
|
+
| --- | --- | --- | --- |
|
|
91
|
+
| `orchestratorKey` | `string` | — | MVTLab project key |
|
|
92
|
+
| `antiFlickerEnabled` | `boolean` | `true` | Inject `body{opacity:0}` before hydration |
|
|
93
|
+
| `antiFlickerTimeoutMs` | `number` | `3000` | Fallback timeout to reveal page if engine stalls |
|
|
94
|
+
| `engineUrl` | `string` | staging CDN URL | Override engine script URL |
|
|
87
95
|
|
|
88
|
-
|
|
96
|
+
### `MVTOrchestrator` — Client Component
|
|
97
|
+
|
|
98
|
+
A `'use client'` component that handles script injection client-side and enforces a single
|
|
99
|
+
project key per page. Use this for **Pages Router** apps or when you cannot modify `layout.tsx`.
|
|
89
100
|
|
|
90
|
-
|
|
101
|
+
> **Note:** When used without `MVTScripts` in layout, the anti-flicker fires after React
|
|
102
|
+
> hydration and will not prevent the initial SSR content flash. For full flicker prevention
|
|
103
|
+
> use `MVTScripts` in `layout.tsx`.
|
|
104
|
+
>
|
|
105
|
+
> When used **together with `MVTScripts`**, `MVTOrchestrator` automatically detects the
|
|
106
|
+
> server-injected script and skips re-injection — no duplicate scripts.
|
|
91
107
|
|
|
92
108
|
```tsx
|
|
93
|
-
|
|
94
|
-
|
|
109
|
+
import { MVTOrchestrator } from '@mvtlab/nextjs-orchestrator';
|
|
110
|
+
|
|
111
|
+
<MVTOrchestrator
|
|
112
|
+
orchestratorKey="YOUR_PROJECT_KEY"
|
|
113
|
+
antiFlickerEnabled={true} // default
|
|
114
|
+
antiFlickerTimeoutMs={3000} // default
|
|
115
|
+
>
|
|
116
|
+
{children}
|
|
95
117
|
</MVTOrchestrator>
|
|
96
118
|
```
|
|
97
119
|
|
|
98
|
-
|
|
120
|
+
| Prop | Type | Default | Description |
|
|
121
|
+
| --- | --- | --- | --- |
|
|
122
|
+
| `orchestratorKey` | `string` | — | MVTLab project key |
|
|
123
|
+
| `children` | `ReactNode` | — | App content to wrap |
|
|
124
|
+
| `antiFlickerEnabled` | `boolean` | `true` | Enable anti-flicker |
|
|
125
|
+
| `antiFlickerTimeoutMs` | `number` | `3000` | Fallback timeout |
|
|
126
|
+
| `engineUrl` | `string` | staging CDN URL | Override engine script URL |
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Usage Examples
|
|
131
|
+
|
|
132
|
+
### With environment variable
|
|
99
133
|
|
|
100
134
|
```tsx
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
135
|
+
// .env.local
|
|
136
|
+
NEXT_PUBLIC_MVT_PROJECT_KEY=your_key_here
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
<MVTScripts orchestratorKey={process.env.NEXT_PUBLIC_MVT_PROJECT_KEY!} />
|
|
107
141
|
```
|
|
108
142
|
|
|
109
|
-
###
|
|
143
|
+
### Disable anti-flicker
|
|
110
144
|
|
|
111
145
|
```tsx
|
|
112
|
-
<
|
|
113
|
-
orchestratorKey="abc123xyz"
|
|
114
|
-
antiFlickerTimeoutMs={5000}
|
|
115
|
-
>
|
|
116
|
-
<YourApp />
|
|
117
|
-
</MVTOrchestrator>
|
|
146
|
+
<MVTScripts orchestratorKey="abc123xyz" antiFlickerEnabled={false} />
|
|
118
147
|
```
|
|
119
148
|
|
|
120
|
-
###
|
|
149
|
+
### Custom timeout
|
|
121
150
|
|
|
122
151
|
```tsx
|
|
123
|
-
|
|
124
|
-
NEXT_PUBLIC_MVT_PROJECT_KEY=your_key_here
|
|
152
|
+
<MVTScripts orchestratorKey="abc123xyz" antiFlickerTimeoutMs={5000} />
|
|
125
153
|
```
|
|
126
154
|
|
|
155
|
+
### TypeScript
|
|
156
|
+
|
|
127
157
|
```tsx
|
|
128
|
-
|
|
129
|
-
orchestratorKey={process.env.NEXT_PUBLIC_MVT_PROJECT_KEY!}
|
|
130
|
-
>
|
|
131
|
-
{children}
|
|
132
|
-
</MVTOrchestrator>
|
|
158
|
+
import type { MVTScriptsProps, MVTOrchestratorProps } from '@mvtlab/nextjs-orchestrator';
|
|
133
159
|
```
|
|
134
160
|
|
|
135
161
|
---
|
|
136
162
|
|
|
137
163
|
## How It Works
|
|
138
164
|
|
|
139
|
-
###
|
|
165
|
+
### `MVTScripts` (Server Component)
|
|
166
|
+
|
|
167
|
+
Server-renders two `<script>` tags into the HTML response:
|
|
168
|
+
|
|
169
|
+
```html
|
|
170
|
+
<!-- Anti-flicker: runs synchronously before any content is shown -->
|
|
171
|
+
<script id="mvt-anti-flicker">
|
|
172
|
+
var timeout=3000;!(function(h,i,d,e){ ... body{opacity:0} ... window.rmfk ... })(...)
|
|
173
|
+
</script>
|
|
174
|
+
|
|
175
|
+
<!-- Engine: async, loads CDN, applies variants, calls window.rmfk() -->
|
|
176
|
+
<script
|
|
177
|
+
id="mvt-engine-script"
|
|
178
|
+
src="https://staging-svc.mvtlab.io/scripts/engine.js"
|
|
179
|
+
data-project-key="YOUR_KEY"
|
|
180
|
+
data-mvt="engine"
|
|
181
|
+
data-mvt-engine="true"
|
|
182
|
+
data-flicker-class="abtest-hidden"
|
|
183
|
+
crossorigin="anonymous"
|
|
184
|
+
async
|
|
185
|
+
></script>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Sequence: **body hidden → engine loads → variants applied → body revealed**
|
|
140
189
|
|
|
141
|
-
|
|
190
|
+
### `MVTOrchestrator` (Client Component)
|
|
142
191
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
- `src="https://staging-svc.mvtlab.io/scripts/engine.js"`
|
|
146
|
-
- `data-project-key={orchestratorKey}`
|
|
147
|
-
- `data-mvt="engine"`
|
|
148
|
-
- `async={true}`
|
|
149
|
-
3. Appends to `<head>`
|
|
192
|
+
Injects the same scripts via `useEffect` (after hydration). Detects if `MVTScripts` already
|
|
193
|
+
ran (`id="mvt-engine-script"` present) and skips re-injection.
|
|
150
194
|
|
|
151
|
-
|
|
195
|
+
Sequence when standalone: **SSR renders → hydration → useEffect → scripts injected**
|
|
152
196
|
|
|
153
|
-
### Anti-Flicker
|
|
197
|
+
### Anti-Flicker Detail
|
|
154
198
|
|
|
155
|
-
|
|
199
|
+
- `<style id="abhide">body{opacity:0}</style>` is injected into `<head>`
|
|
200
|
+
- `window.rmfk()` is defined to remove that style element
|
|
201
|
+
- The engine calls `window.rmfk()` once variants are applied
|
|
202
|
+
- A safety timeout removes the style if the engine never responds
|
|
156
203
|
|
|
157
|
-
|
|
158
|
-
2. Defines `window.rmfk()` to remove the style element
|
|
159
|
-
3. Engine calls `window.rmfk()` when ready
|
|
160
|
-
4. Safety timeout (default 3000ms) calls `window.rmfk()` as fallback
|
|
204
|
+
---
|
|
161
205
|
|
|
162
|
-
|
|
206
|
+
## Troubleshooting
|
|
163
207
|
|
|
164
|
-
|
|
208
|
+
**Engine not loading?**
|
|
165
209
|
|
|
166
|
-
-
|
|
167
|
-
-
|
|
168
|
-
-
|
|
210
|
+
- Verify `orchestratorKey` is the correct project key from your MVTLab dashboard
|
|
211
|
+
- Check the Network tab for the `engine.js` request and any errors
|
|
212
|
+
- Ensure the project's domain matches the `websiteUrl` configured in MVTLab
|
|
169
213
|
|
|
170
|
-
|
|
214
|
+
**Anti-flicker not working (page flashes)?**
|
|
171
215
|
|
|
172
|
-
|
|
216
|
+
- Switch from `MVTOrchestrator` to `MVTScripts` in `layout.tsx` — the client-side approach cannot prevent the initial SSR flash
|
|
217
|
+
- Confirm `antiFlickerEnabled={true}` (default)
|
|
173
218
|
|
|
174
|
-
**
|
|
175
|
-
- Ensure `'use client';` is present
|
|
176
|
-
- Verify `orchestratorKey` is correct
|
|
177
|
-
- Check browser console for errors
|
|
219
|
+
**Duplicate scripts in DOM?**
|
|
178
220
|
|
|
179
|
-
|
|
180
|
-
-
|
|
181
|
-
- Check if `window.rmfk()` is called (inspect console)
|
|
182
|
-
- Increase `antiFlickerTimeoutMs` if engine loads slowly
|
|
221
|
+
- Use `MVTScripts` or `MVTOrchestrator` once at root, not both independently
|
|
222
|
+
- If using both together, `MVTOrchestrator` auto-detects `MVTScripts` and skips injection
|
|
183
223
|
|
|
184
|
-
**
|
|
185
|
-
- Use `MVTOrchestrator` only once at root
|
|
186
|
-
- Don't use different keys on the same page
|
|
224
|
+
**Pages Router / no layout.tsx?**
|
|
187
225
|
|
|
188
|
-
|
|
189
|
-
- All DOM access is in `useEffect` (browser-only)
|
|
190
|
-
- Ensure `'use client';` is at the top of the file
|
|
226
|
+
- Use `MVTOrchestrator` in `pages/_app.tsx`
|
|
191
227
|
|
|
192
228
|
---
|
|
193
229
|
|
|
194
230
|
## FAQ
|
|
195
231
|
|
|
196
|
-
**
|
|
197
|
-
|
|
232
|
+
**Do I need `'use client'` with `MVTScripts`?**
|
|
233
|
+
No. `MVTScripts` is a Server Component. Add it directly to your `layout.tsx` without any directive.
|
|
234
|
+
|
|
235
|
+
**Can I use `MVTScripts` and `MVTOrchestrator` together?**
|
|
236
|
+
Yes. Put `MVTScripts` in `layout.tsx` for correct timing and use `MVTOrchestrator` elsewhere for
|
|
237
|
+
client-side key enforcement. The orchestrator detects the server-injected script and won't duplicate it.
|
|
198
238
|
|
|
199
|
-
**Can I use multiple project keys?**
|
|
200
|
-
No. Use one `orchestratorKey`
|
|
239
|
+
**Can I use multiple project keys?**
|
|
240
|
+
No. Use one `orchestratorKey` for the entire site. Different keys on the same page will log an error.
|
|
201
241
|
|
|
202
|
-
**What if the engine fails to load?**
|
|
203
|
-
The timeout (default 3000ms) removes the anti-flicker style
|
|
242
|
+
**What if the engine fails to load?**
|
|
243
|
+
The timeout (default 3000ms) removes the anti-flicker style so the page becomes visible.
|
|
244
|
+
Experiment variants won't be applied.
|
|
204
245
|
|
|
205
|
-
**TypeScript support?**
|
|
206
|
-
Full type definitions included.
|
|
246
|
+
**TypeScript support?**
|
|
247
|
+
Full type definitions included. Both `MVTScriptsProps` and `MVTOrchestratorProps` are exported.
|
|
207
248
|
|
|
208
|
-
**Browser support?**
|
|
249
|
+
**Browser support?**
|
|
209
250
|
Modern browsers with ES2019+, React 18+, and standard DOM APIs.
|
|
210
251
|
|
|
211
252
|
---
|
|
@@ -225,4 +266,6 @@ See [LICENSE](LICENSE) for details.
|
|
|
225
266
|
|
|
226
267
|
---
|
|
227
268
|
|
|
228
|
-
|
|
269
|
+
*`MVTScripts` renders the standard MVTLab.io HTML snippet server-side so it runs before
|
|
270
|
+
hydration. `MVTOrchestrator` translates the same snippet into React hooks for client-side
|
|
271
|
+
or Pages Router use.*
|
|
@@ -7,8 +7,12 @@ export type MVTOrchestratorProps = {
|
|
|
7
7
|
orchestratorKey: string;
|
|
8
8
|
/**
|
|
9
9
|
* Enable or disable the anti-flicker style injection.
|
|
10
|
-
* When enabled
|
|
11
|
-
*
|
|
10
|
+
* When enabled and MVTScripts is NOT present in layout.tsx, a temporary
|
|
11
|
+
* style is applied client-side to hide the body until the engine removes it.
|
|
12
|
+
* Note: when used standalone (without MVTScripts), anti-flicker fires after
|
|
13
|
+
* React hydration and will not prevent the initial SSR content flash.
|
|
14
|
+
* For full flicker prevention use MVTScripts in your root layout.tsx instead.
|
|
15
|
+
* Defaults to true.
|
|
12
16
|
*/
|
|
13
17
|
antiFlickerEnabled?: boolean;
|
|
14
18
|
/**
|
package/dist/MVTOrchestrator.js
CHANGED
|
@@ -8,48 +8,62 @@ export const MVTOrchestrator = ({ orchestratorKey, antiFlickerEnabled = true, an
|
|
|
8
8
|
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
9
9
|
return;
|
|
10
10
|
}
|
|
11
|
-
//
|
|
11
|
+
// Detect whether MVTScripts server component already injected the engine.
|
|
12
|
+
// If the <script id="mvt-engine-script"> is present, the server-side path
|
|
13
|
+
// ran (correct timing). We skip script injection but still ensure window.rmfk
|
|
14
|
+
// is available for the engine to call and set the timeout fallback.
|
|
15
|
+
const engineAlreadyInjected = !!document.getElementById('mvt-engine-script');
|
|
16
|
+
// Anti-flicker: only inject client-side when MVTScripts was NOT used.
|
|
17
|
+
// When MVTScripts is in layout.tsx the anti-flicker script is server-rendered
|
|
18
|
+
// and window.rmfk is already defined — we just need to set the timeout fallback.
|
|
12
19
|
if (antiFlickerEnabled) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
if (!engineAlreadyInjected) {
|
|
21
|
+
// Standalone mode: inject anti-flicker client-side (fires after hydration —
|
|
22
|
+
// does not prevent the initial SSR flash, but still protects against variant
|
|
23
|
+
// flicker on client-side navigations).
|
|
24
|
+
const existing = document.getElementById(ANTI_FLICKER_STYLE_ID);
|
|
25
|
+
if (!existing) {
|
|
26
|
+
const style = document.createElement('style');
|
|
27
|
+
style.id = ANTI_FLICKER_STYLE_ID;
|
|
28
|
+
style.innerHTML = 'body{opacity:0}';
|
|
29
|
+
document.head.appendChild(style);
|
|
30
|
+
}
|
|
19
31
|
}
|
|
20
|
-
// Expose rmfk
|
|
32
|
+
// Expose window.rmfk so the engine can remove the anti-flicker style.
|
|
33
|
+
// MVTScripts also defines this via the inline script; redefining here is safe.
|
|
21
34
|
window.rmfk = function rmfk() {
|
|
22
35
|
const el = document.getElementById(ANTI_FLICKER_STYLE_ID);
|
|
23
36
|
if (el && el.parentNode) {
|
|
24
37
|
el.parentNode.removeChild(el);
|
|
25
38
|
}
|
|
26
39
|
};
|
|
27
|
-
// Safety timeout
|
|
40
|
+
// Safety timeout: remove anti-flicker if the engine never calls rmfk.
|
|
28
41
|
window.setTimeout(() => {
|
|
29
|
-
|
|
30
|
-
|
|
42
|
+
const rmfk = window.rmfk;
|
|
43
|
+
if (typeof rmfk === 'function') {
|
|
44
|
+
rmfk();
|
|
31
45
|
}
|
|
32
46
|
}, antiFlickerTimeoutMs);
|
|
33
47
|
}
|
|
34
|
-
// Enforce a single project key per page
|
|
35
|
-
const globalKeyProp = '__mvtOrchestratorKey';
|
|
36
48
|
const w = window;
|
|
37
|
-
if (w
|
|
49
|
+
if (w.__mvtOrchestratorKey && w.__mvtOrchestratorKey !== orchestratorKey) {
|
|
38
50
|
// eslint-disable-next-line no-console
|
|
39
51
|
console.error('[MVTOrchestrator] Multiple different project keys on the same page are not supported. ' +
|
|
40
|
-
`Existing key: "${w
|
|
52
|
+
`Existing key: "${w.__mvtOrchestratorKey}", new key: "${orchestratorKey}".`);
|
|
41
53
|
return;
|
|
42
54
|
}
|
|
43
|
-
w
|
|
44
|
-
// Inject the engine script only
|
|
45
|
-
|
|
46
|
-
if (!document.getElementById(scriptId)) {
|
|
55
|
+
w.__mvtOrchestratorKey = orchestratorKey;
|
|
56
|
+
// Inject the engine script only when MVTScripts did not already do so.
|
|
57
|
+
if (!engineAlreadyInjected) {
|
|
47
58
|
const script = document.createElement('script');
|
|
48
|
-
script.id =
|
|
59
|
+
script.id = 'mvt-engine-script';
|
|
49
60
|
script.src = engineUrl;
|
|
50
61
|
script.async = true;
|
|
62
|
+
script.crossOrigin = 'anonymous';
|
|
51
63
|
script.setAttribute('data-project-key', orchestratorKey);
|
|
52
64
|
script.setAttribute('data-mvt', 'engine');
|
|
65
|
+
script.setAttribute('data-mvt-engine', 'true');
|
|
66
|
+
script.setAttribute('data-flicker-class', 'abtest-hidden');
|
|
53
67
|
document.head.appendChild(script);
|
|
54
68
|
}
|
|
55
69
|
}, [orchestratorKey, antiFlickerEnabled, antiFlickerTimeoutMs, engineUrl]);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type MVTScriptsProps = {
|
|
3
|
+
/**
|
|
4
|
+
* Project key used by the MVT engine.
|
|
5
|
+
*/
|
|
6
|
+
orchestratorKey: string;
|
|
7
|
+
/**
|
|
8
|
+
* Enable or disable the anti-flicker style injection.
|
|
9
|
+
* Defaults to true.
|
|
10
|
+
*/
|
|
11
|
+
antiFlickerEnabled?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Timeout in milliseconds to automatically remove the anti-flicker style
|
|
14
|
+
* if the engine never calls window.rmfk(). Defaults to 3000ms.
|
|
15
|
+
*/
|
|
16
|
+
antiFlickerTimeoutMs?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Custom engine script URL.
|
|
19
|
+
* Defaults to the staging endpoint.
|
|
20
|
+
*/
|
|
21
|
+
engineUrl?: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Server Component — place at the top of your root layout.tsx <body>.
|
|
25
|
+
*
|
|
26
|
+
* Renders the anti-flicker inline script and the MVT engine <script> tag
|
|
27
|
+
* directly into the server-generated HTML so they execute before React
|
|
28
|
+
* hydration, eliminating the content flash that useEffect-based injection
|
|
29
|
+
* cannot prevent.
|
|
30
|
+
*
|
|
31
|
+
* Usage in app/layout.tsx:
|
|
32
|
+
*
|
|
33
|
+
* import { MVTScripts } from '@mvtlab/nextjs-orchestrator';
|
|
34
|
+
*
|
|
35
|
+
* export default function RootLayout({ children }) {
|
|
36
|
+
* return (
|
|
37
|
+
* <html>
|
|
38
|
+
* <body>
|
|
39
|
+
* <MVTScripts orchestratorKey="YOUR_PROJECT_KEY" />
|
|
40
|
+
* {children}
|
|
41
|
+
* </body>
|
|
42
|
+
* </html>
|
|
43
|
+
* );
|
|
44
|
+
* }
|
|
45
|
+
*/
|
|
46
|
+
export declare const MVTScripts: React.FC<MVTScriptsProps>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
const DEFAULT_ENGINE_URL = 'https://staging-svc.mvtlab.io/scripts/engine.js';
|
|
3
|
+
/**
|
|
4
|
+
* Server Component — place at the top of your root layout.tsx <body>.
|
|
5
|
+
*
|
|
6
|
+
* Renders the anti-flicker inline script and the MVT engine <script> tag
|
|
7
|
+
* directly into the server-generated HTML so they execute before React
|
|
8
|
+
* hydration, eliminating the content flash that useEffect-based injection
|
|
9
|
+
* cannot prevent.
|
|
10
|
+
*
|
|
11
|
+
* Usage in app/layout.tsx:
|
|
12
|
+
*
|
|
13
|
+
* import { MVTScripts } from '@mvtlab/nextjs-orchestrator';
|
|
14
|
+
*
|
|
15
|
+
* export default function RootLayout({ children }) {
|
|
16
|
+
* return (
|
|
17
|
+
* <html>
|
|
18
|
+
* <body>
|
|
19
|
+
* <MVTScripts orchestratorKey="YOUR_PROJECT_KEY" />
|
|
20
|
+
* {children}
|
|
21
|
+
* </body>
|
|
22
|
+
* </html>
|
|
23
|
+
* );
|
|
24
|
+
* }
|
|
25
|
+
*/
|
|
26
|
+
export const MVTScripts = ({ orchestratorKey, antiFlickerEnabled = true, antiFlickerTimeoutMs = 3000, engineUrl = DEFAULT_ENGINE_URL, }) => {
|
|
27
|
+
// Matches the exact anti-flicker snippet used in the plain HTML pages:
|
|
28
|
+
// hides body{opacity:0}, exposes window.rmfk() for the engine to call,
|
|
29
|
+
// and falls back to auto-removal after the timeout.
|
|
30
|
+
const antiFlickerHtml = `var timeout=${antiFlickerTimeoutMs};!(function(h,i,d,e){var t,n=h.createElement("style");(n.id=e),(n.innerHTML="body{opacity:0}"),h.head.appendChild(n),(t=d),(i.rmfk=function(){var t=h.getElementById(e);t&&t.parentNode.removeChild(t)}),setTimeout(i.rmfk,t)})(document,window,timeout,"abhide");`;
|
|
31
|
+
return (_jsxs(_Fragment, { children: [antiFlickerEnabled && (
|
|
32
|
+
// eslint-disable-next-line react/no-danger
|
|
33
|
+
_jsx("script", { id: "mvt-anti-flicker", dangerouslySetInnerHTML: { __html: antiFlickerHtml } })), _jsx("script", { id: "mvt-engine-script", src: engineUrl, "data-project-key": orchestratorKey, "data-mvt": "engine", "data-mvt-engine": "true", "data-flicker-class": "abtest-hidden", crossOrigin: "anonymous", async: true })] }));
|
|
34
|
+
};
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mvtlab/nextjs-orchestrator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Next.js SDK to integrate the MVT Lab CDN engine with optional anti-flicker support.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -36,5 +36,6 @@
|
|
|
36
36
|
"cdn-engine"
|
|
37
37
|
],
|
|
38
38
|
"author": "MVT Lab",
|
|
39
|
-
"license": "MVTLab.io"
|
|
39
|
+
"license": "MVTLab.io",
|
|
40
|
+
"packageManager": "yarn@4.12.0"
|
|
40
41
|
}
|