@varykit/vue 0.1.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 +75 -0
- package/dist/index.d.mts +66 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.mjs +50 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# @varykit/vue
|
|
2
|
+
|
|
3
|
+
**Vue 3 composable and component for VaryKit segment-based multivariate testing.**
|
|
4
|
+
|
|
5
|
+
This package works in any Vue 3 app (Vite, plain Vue Router, etc.) with **no Nuxt present**. It depends on `@varykit/core` for bucketing and declares `vue` as a peer dependency.
|
|
6
|
+
|
|
7
|
+
## The segment model
|
|
8
|
+
|
|
9
|
+
Every visitor is assigned to a **single global segment** (e.g. `control` or `treatment`), persisted in the `vary:segment` cookie. That segment is reused consistently across every element and page — a visitor is never in different segments for different tests.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm add @varykit/vue
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### `useSegment(segments, options?)`
|
|
20
|
+
|
|
21
|
+
Resolves the visitor's global segment, persisting it in the `vary:segment` cookie so the assignment is sticky. Returns a reactive `{ segment }` ref.
|
|
22
|
+
|
|
23
|
+
```vue
|
|
24
|
+
<script setup>
|
|
25
|
+
import { useSegment } from '@varykit/vue'
|
|
26
|
+
|
|
27
|
+
const segments = {
|
|
28
|
+
control: { distribution: 0.5 },
|
|
29
|
+
treatment: { distribution: 0.5 }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const { segment } = useSegment(segments)
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<template>
|
|
36
|
+
<p v-if="segment === 'control'">Control content</p>
|
|
37
|
+
<p v-else>Treatment content</p>
|
|
38
|
+
</template>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### `<VaryShow>`
|
|
42
|
+
|
|
43
|
+
A template-only wrapper around `useSegment()`. Renders its default slot only when the visitor's segment matches the `segment` prop.
|
|
44
|
+
|
|
45
|
+
```vue
|
|
46
|
+
<script setup>
|
|
47
|
+
import { VaryShow } from '@varykit/vue'
|
|
48
|
+
|
|
49
|
+
const segments = {
|
|
50
|
+
control: { distribution: 0.5 },
|
|
51
|
+
treatment: { distribution: 0.5 }
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<template>
|
|
56
|
+
<VaryShow :segments="segments" segment="control">
|
|
57
|
+
<p>Control content</p>
|
|
58
|
+
</VaryShow>
|
|
59
|
+
</template>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Options
|
|
63
|
+
|
|
64
|
+
| Option | Type | Description |
|
|
65
|
+
| ------ | ---- | ----------- |
|
|
66
|
+
| `duration` | `number` | Global default cookie duration in seconds. |
|
|
67
|
+
| `cookieName` | `string` | Override the cookie name (default `vary:segment`). |
|
|
68
|
+
|
|
69
|
+
## Scope
|
|
70
|
+
|
|
71
|
+
This package owns Vue-specific persistence (`document.cookie`) and reactivity. It never imports from `@varykit/nuxt`.
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as vue from 'vue';
|
|
2
|
+
import { Ref, PropType } from 'vue';
|
|
3
|
+
import { VarySegments } from '@varykit/core';
|
|
4
|
+
export { DEFAULT_DURATION, ResolvedSegment, VarySegmentConfig, VarySegments, resolveSegment, validateSegments } from '@varykit/core';
|
|
5
|
+
|
|
6
|
+
interface UseSegmentOptions {
|
|
7
|
+
duration?: number;
|
|
8
|
+
cookieName?: string;
|
|
9
|
+
}
|
|
10
|
+
interface UseSegmentReturn {
|
|
11
|
+
segment: Ref<string>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the visitor's single global segment, persisting it in the
|
|
15
|
+
* `vary:segment` cookie so the assignment is sticky across requests.
|
|
16
|
+
*
|
|
17
|
+
* The same segment is reused across every page and element test.
|
|
18
|
+
*/
|
|
19
|
+
declare function useSegment(segments: VarySegments, options?: UseSegmentOptions): UseSegmentReturn;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Template-only wrapper around `useSegment()`.
|
|
23
|
+
*
|
|
24
|
+
* Renders its default slot only when the visitor's global segment matches
|
|
25
|
+
* the `segment` prop.
|
|
26
|
+
*
|
|
27
|
+
* ```vue
|
|
28
|
+
* <VaryShow :segments="segments" segment="control">
|
|
29
|
+
* <p>Control content</p>
|
|
30
|
+
* </VaryShow>
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
declare const VaryShow: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
34
|
+
segment: {
|
|
35
|
+
type: StringConstructor;
|
|
36
|
+
required: true;
|
|
37
|
+
};
|
|
38
|
+
segments: {
|
|
39
|
+
type: PropType<VarySegments>;
|
|
40
|
+
required: true;
|
|
41
|
+
};
|
|
42
|
+
duration: {
|
|
43
|
+
type: NumberConstructor;
|
|
44
|
+
default: undefined;
|
|
45
|
+
};
|
|
46
|
+
}>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
47
|
+
[key: string]: any;
|
|
48
|
+
}>[] | null | undefined, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
49
|
+
segment: {
|
|
50
|
+
type: StringConstructor;
|
|
51
|
+
required: true;
|
|
52
|
+
};
|
|
53
|
+
segments: {
|
|
54
|
+
type: PropType<VarySegments>;
|
|
55
|
+
required: true;
|
|
56
|
+
};
|
|
57
|
+
duration: {
|
|
58
|
+
type: NumberConstructor;
|
|
59
|
+
default: undefined;
|
|
60
|
+
};
|
|
61
|
+
}>> & Readonly<{}>, {
|
|
62
|
+
duration: number;
|
|
63
|
+
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
64
|
+
|
|
65
|
+
export { VaryShow, useSegment };
|
|
66
|
+
export type { UseSegmentOptions, UseSegmentReturn };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as vue from 'vue';
|
|
2
|
+
import { Ref, PropType } from 'vue';
|
|
3
|
+
import { VarySegments } from '@varykit/core';
|
|
4
|
+
export { DEFAULT_DURATION, ResolvedSegment, VarySegmentConfig, VarySegments, resolveSegment, validateSegments } from '@varykit/core';
|
|
5
|
+
|
|
6
|
+
interface UseSegmentOptions {
|
|
7
|
+
duration?: number;
|
|
8
|
+
cookieName?: string;
|
|
9
|
+
}
|
|
10
|
+
interface UseSegmentReturn {
|
|
11
|
+
segment: Ref<string>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the visitor's single global segment, persisting it in the
|
|
15
|
+
* `vary:segment` cookie so the assignment is sticky across requests.
|
|
16
|
+
*
|
|
17
|
+
* The same segment is reused across every page and element test.
|
|
18
|
+
*/
|
|
19
|
+
declare function useSegment(segments: VarySegments, options?: UseSegmentOptions): UseSegmentReturn;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Template-only wrapper around `useSegment()`.
|
|
23
|
+
*
|
|
24
|
+
* Renders its default slot only when the visitor's global segment matches
|
|
25
|
+
* the `segment` prop.
|
|
26
|
+
*
|
|
27
|
+
* ```vue
|
|
28
|
+
* <VaryShow :segments="segments" segment="control">
|
|
29
|
+
* <p>Control content</p>
|
|
30
|
+
* </VaryShow>
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
declare const VaryShow: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
34
|
+
segment: {
|
|
35
|
+
type: StringConstructor;
|
|
36
|
+
required: true;
|
|
37
|
+
};
|
|
38
|
+
segments: {
|
|
39
|
+
type: PropType<VarySegments>;
|
|
40
|
+
required: true;
|
|
41
|
+
};
|
|
42
|
+
duration: {
|
|
43
|
+
type: NumberConstructor;
|
|
44
|
+
default: undefined;
|
|
45
|
+
};
|
|
46
|
+
}>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
47
|
+
[key: string]: any;
|
|
48
|
+
}>[] | null | undefined, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
49
|
+
segment: {
|
|
50
|
+
type: StringConstructor;
|
|
51
|
+
required: true;
|
|
52
|
+
};
|
|
53
|
+
segments: {
|
|
54
|
+
type: PropType<VarySegments>;
|
|
55
|
+
required: true;
|
|
56
|
+
};
|
|
57
|
+
duration: {
|
|
58
|
+
type: NumberConstructor;
|
|
59
|
+
default: undefined;
|
|
60
|
+
};
|
|
61
|
+
}>> & Readonly<{}>, {
|
|
62
|
+
duration: number;
|
|
63
|
+
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
64
|
+
|
|
65
|
+
export { VaryShow, useSegment };
|
|
66
|
+
export type { UseSegmentOptions, UseSegmentReturn };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ref, defineComponent } from 'vue';
|
|
2
|
+
import { resolveSegment } from '@varykit/core';
|
|
3
|
+
export { DEFAULT_DURATION, resolveSegment, validateSegments } from '@varykit/core';
|
|
4
|
+
|
|
5
|
+
function getCookie(name) {
|
|
6
|
+
if (typeof document === "undefined") return void 0;
|
|
7
|
+
const match = document.cookie.split("; ").find((row) => row.startsWith(`${name}=`));
|
|
8
|
+
return match ? decodeURIComponent(match.slice(name.length + 1)) : void 0;
|
|
9
|
+
}
|
|
10
|
+
function setCookie(name, value, maxAge) {
|
|
11
|
+
if (typeof document === "undefined") return;
|
|
12
|
+
document.cookie = `${name}=${encodeURIComponent(value)}; path=/; max-age=${maxAge}`;
|
|
13
|
+
}
|
|
14
|
+
function useSegment(segments, options = {}) {
|
|
15
|
+
const cookieName = options.cookieName ?? "vary:segment";
|
|
16
|
+
const existingSegment = getCookie(cookieName);
|
|
17
|
+
const resolved = resolveSegment({
|
|
18
|
+
segments,
|
|
19
|
+
existingSegment,
|
|
20
|
+
defaultDuration: options.duration
|
|
21
|
+
});
|
|
22
|
+
setCookie(cookieName, resolved.segment, resolved.duration);
|
|
23
|
+
return { segment: ref(resolved.segment) };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const VaryShow = defineComponent({
|
|
27
|
+
name: "VaryShow",
|
|
28
|
+
props: {
|
|
29
|
+
segment: {
|
|
30
|
+
type: String,
|
|
31
|
+
required: true
|
|
32
|
+
},
|
|
33
|
+
segments: {
|
|
34
|
+
type: Object,
|
|
35
|
+
required: true
|
|
36
|
+
},
|
|
37
|
+
duration: {
|
|
38
|
+
type: Number,
|
|
39
|
+
default: void 0
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
setup(props, { slots }) {
|
|
43
|
+
const { segment } = useSegment(props.segments, {
|
|
44
|
+
duration: props.duration
|
|
45
|
+
});
|
|
46
|
+
return () => segment.value === props.segment ? slots.default?.() : null;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export { VaryShow, useSegment };
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@varykit/vue",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Vue 3 composable and component for VaryKit element-level multivariate testing.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.mts",
|
|
10
|
+
"import": "./dist/index.mjs"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"main": "./dist/index.mjs",
|
|
14
|
+
"types": "./dist/index.d.mts",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "unbuild",
|
|
20
|
+
"typecheck": "tsc --noEmit"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"vue",
|
|
24
|
+
"a/b-testing",
|
|
25
|
+
"multivariate",
|
|
26
|
+
"ab-test",
|
|
27
|
+
"experimentation",
|
|
28
|
+
"bucketing",
|
|
29
|
+
"varykit"
|
|
30
|
+
],
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@varykit/core": "workspace:*"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"vue": "^3.0.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"typescript": "^5.0.0",
|
|
39
|
+
"unbuild": "^3.0.0",
|
|
40
|
+
"vue": "^3.0.0"
|
|
41
|
+
}
|
|
42
|
+
}
|