Skip to content

Commit 8d5274f

Browse files
authored
feat[vue+svelte]: support of variant containers (#3957)
## Description Adds support of Variant Containers in Gen2 Vue and Svelte SDK updating the approach to be synonymous with how we handle A/B tests in Gen2 SDKs (general support) so that we can expand this approach and support VCs in other gen2 SDKs in the future. Jira https://builder-io.atlassian.net/browse/ENG-7677 Demo https://www.loom.com/share/678e5b23a666445d87e3758f32a81b3a
1 parent a3986bd commit 8d5274f

26 files changed

+570
-216
lines changed

.changeset/angry-hounds-fix.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
'@builder.io/sdk-vue': patch
3+
---
4+
5+
Feat: Add support for passing `BlocksWrapperProps` to `<Blocks />` component. This allows overriding global props set via `<Content />` with specific props for individual Blocks instances. Note that local props completely replace global props unless manually merged.
6+
7+
Example usage:
8+
9+
```vue
10+
<!-- Set global props, applies to all <Blocks /> -->
11+
<Content :blocksWrapperProps="{ style: { padding: '10px' } }" />
12+
13+
<!-- Override global props -->
14+
<Blocks :BlocksWrapperProps="{ style: { backgroundColor: 'red' } }" />
15+
16+
<!-- Merge global and local props -->
17+
<Blocks
18+
:BlocksWrapperProps="{
19+
...builderContext.BlocksWrapperProps,
20+
style: { backgroundColor: 'red' }, // applies both bg color and padding
21+
}"
22+
/>
23+
```

.changeset/brown-buses-swim.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
'@builder.io/sdk-react-nextjs': patch
3+
'@builder.io/sdk-qwik': patch
4+
'@builder.io/sdk-react': patch
5+
'@builder.io/sdk-react-native': patch
6+
'@builder.io/sdk-solid': patch
7+
'@builder.io/sdk-svelte': patch
8+
---
9+
10+
Feat: Add support for passing `BlocksWrapperProps` to `<Blocks />` component. This allows overriding global props set via `<Content />` with specific props for individual Blocks instances. Note that local props completely replace global props unless manually merged.
11+
12+
Example usage:
13+
14+
```tsx
15+
// Set global props, applies to all <Blocks />
16+
<Content blocksWrapperProps={{ style: { padding: 10 } }} />
17+
18+
// Override global props
19+
<Blocks BlocksWrapperProps={{ style: { backgroundColor: 'red' } }} />
20+
21+
// Merge global and local props
22+
<Blocks
23+
BlocksWrapperProps={{
24+
...builderContext.BlocksWrapperProps,
25+
style: { backgroundColor: 'red' } // applies both bg color and padding
26+
}}
27+
/>
28+
```

.changeset/flat-needles-do.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@builder.io/sdk-react": patch
3+
---
4+
5+
Refactor: variant containers approach, now uses global level scripts and avoids re-initialization

.changeset/healthy-cups-impress.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
'@builder.io/sdk-angular': patch
3+
---
4+
5+
Feat: Add support for passing `BlocksWrapperProps` to `<blocks>` component. This allows overriding global props set via `<builder-content>` with specific props for individual blocks instances. Note that local props completely replace global props unless manually merged.
6+
7+
Example usage:
8+
9+
```html
10+
<!-- Set global props, applies to all blocks -->
11+
<builder-content [blocksWrapperProps]="{ style: { padding: '10px' } }"></builder-content>
12+
13+
<!-- Override global props -->
14+
<blocks [BlocksWrapperProps]="{ style: { backgroundColor: 'red' } }"></blocks>
15+
16+
<!-- Merge global and local props -->
17+
<blocks
18+
[BlocksWrapperProps]="{
19+
...builderContext.BlocksWrapperProps,
20+
style: { backgroundColor: 'red' } // applies both bg color and padding
21+
}"
22+
></blocks>
23+
```

.changeset/witty-lemons-report.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@builder.io/sdk-svelte": patch
3+
"@builder.io/sdk-vue": patch
4+
---
5+
6+
Feat: support of Variant Containers and block level personalization

packages/sdks-tests/src/e2e-tests/personalization-container.spec.ts

Lines changed: 18 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import type { Browser } from '@playwright/test';
22
import { expect } from '@playwright/test';
3-
import { excludeGen2, isSSRFramework, test } from '../helpers/index.js';
3+
import { isSSRFramework, test } from '../helpers/index.js';
44
import { launchEmbedderAndWaitForSdk } from '../helpers/visual-editor.js';
5+
import type { Sdk } from '../helpers/sdk.js';
6+
57
const SELECTOR = 'div[builder-content-id]';
8+
const SDKS_SUPPORTING_PERSONALIZATION = ['react', 'vue', 'svelte'] as Sdk[];
69

710
const createContextWithCookies = async ({
811
cookies,
@@ -36,18 +39,9 @@ const initializeUserAttributes = async (
3639
page: _page,
3740
baseURL,
3841
browser,
39-
packageName,
40-
sdk,
41-
}: Pick<
42-
Parameters<Parameters<typeof test>[2]>[0],
43-
'page' | 'baseURL' | 'browser' | 'packageName' | 'sdk'
44-
>,
42+
}: Pick<Parameters<Parameters<typeof test>[2]>[0], 'page' | 'baseURL' | 'browser'>,
4543
{ userAttributes }: { userAttributes: Record<string, string> }
4644
) => {
47-
// gen1-remix started failing on this test for an unknown reason.
48-
test.skip(packageName === 'gen1-remix');
49-
test.skip(excludeGen2(sdk) && sdk !== 'react');
50-
5145
if (!baseURL) throw new Error('Missing baseURL');
5246

5347
const context = await createContextWithCookies({
@@ -62,6 +56,11 @@ const initializeUserAttributes = async (
6256
};
6357

6458
test.describe('Personalization Container', () => {
59+
test.beforeEach(({ sdk, packageName }) => {
60+
test.skip(!SDKS_SUPPORTING_PERSONALIZATION.includes(sdk));
61+
test.skip(packageName === 'gen1-remix');
62+
});
63+
6564
test.describe('entire page', () => {
6665
const TEXTS = {
6766
DEFAULT_CONTENT: 'Default',
@@ -73,20 +72,12 @@ test.describe('Personalization Container', () => {
7372

7473
// Manually run tests 10 times to ensure we don't have any flakiness.
7574
for (let i = 1; i <= TRIES; i++) {
76-
test(`#${i}/${TRIES}: Render default w/ SSR`, async ({
77-
page: _page,
78-
baseURL,
79-
browser,
80-
packageName,
81-
sdk,
82-
}) => {
75+
test(`#${i}/${TRIES}: Render default w/ SSR`, async ({ page: _page, baseURL, browser }) => {
8376
const { page } = await initializeUserAttributes(
8477
{
8578
page: _page,
8679
baseURL,
8780
browser,
88-
sdk,
89-
packageName,
9081
},
9182
// empty should render default, non-personalized content
9283
{
@@ -102,20 +93,12 @@ test.describe('Personalization Container', () => {
10293
await expect(page.locator(SELECTOR, { hasText: TEXTS.EXPERIMENT_B })).toBeHidden();
10394
});
10495

105-
test(`#${i}/${TRIES}: Render variant A w/ SSR`, async ({
106-
page: _page,
107-
baseURL,
108-
browser,
109-
sdk,
110-
packageName,
111-
}) => {
96+
test(`#${i}/${TRIES}: Render variant A w/ SSR`, async ({ page: _page, baseURL, browser }) => {
11297
const { page } = await initializeUserAttributes(
11398
{
11499
page: _page,
115100
baseURL,
116101
browser,
117-
sdk,
118-
packageName,
119102
},
120103
// empty should render default, non-personalized content
121104
{
@@ -131,20 +114,12 @@ test.describe('Personalization Container', () => {
131114
await expect(page.locator(SELECTOR, { hasText: TEXTS.DEFAULT_CONTENT })).toBeHidden();
132115
});
133116

134-
test(`#${i}/${TRIES}: Render variant B w/ SSR`, async ({
135-
page: _page,
136-
baseURL,
137-
browser,
138-
sdk,
139-
packageName,
140-
}) => {
117+
test(`#${i}/${TRIES}: Render variant B w/ SSR`, async ({ page: _page, baseURL, browser }) => {
141118
const { page } = await initializeUserAttributes(
142119
{
143120
page: _page,
144121
baseURL,
145122
browser,
146-
sdk,
147-
packageName,
148123
},
149124
// empty should render default, non-personalized content
150125
{
@@ -167,7 +142,9 @@ test.describe('Personalization Container', () => {
167142
packageName,
168143
}) => {
169144
// here we are checking specifically for winning variant content by setting the user attributes
170-
test.skip(!['react-sdk-next-15-app', 'gen1-next15-app'].includes(packageName));
145+
test.skip(
146+
!['react-sdk-next-15-app', 'gen1-next15-app', 'nuxt', 'sveltekit'].includes(packageName)
147+
);
171148
await page.goto('/variant-containers');
172149

173150
// content 1
@@ -179,12 +156,8 @@ test.describe('Personalization Container', () => {
179156
await expect(page.getByText('Tablet content 2')).toBeVisible();
180157
});
181158

182-
test('only default variants are ssred on the server', async ({ browser, packageName, sdk }) => {
159+
test('only default variants are ssred on the server', async ({ browser, packageName }) => {
183160
test.skip(!isSSRFramework(packageName));
184-
test.skip(!['react', 'oldReact'].includes(sdk));
185-
// Cannot read properties of null (reading 'useContext')
186-
test.skip(packageName === 'gen1-remix');
187-
188161
const context = await browser.newContext({
189162
javaScriptEnabled: false,
190163
});
@@ -197,11 +170,7 @@ test.describe('Personalization Container', () => {
197170
await expect(page.getByText('Default content 2')).toBeVisible();
198171
});
199172

200-
test('root style attribute is correctly set', async ({ page, sdk, packageName }) => {
201-
test.skip(!['react', 'oldReact'].includes(sdk));
202-
// Cannot read properties of null (reading 'useContext')
203-
test.skip(packageName === 'gen1-remix');
204-
173+
test('root style attribute is correctly set', async ({ page }) => {
205174
await page.goto('/variant-containers');
206175

207176
const secondPersonalizationContainer = page
@@ -215,12 +184,7 @@ test.describe('Personalization Container', () => {
215184
page,
216185
sdk,
217186
basePort,
218-
packageName,
219187
}) => {
220-
test.skip(!['react', 'oldReact'].includes(sdk));
221-
// Cannot read properties of null (reading 'useContext')
222-
test.skip(packageName === 'gen1-remix');
223-
224188
const paths = [
225189
'/variant-containers-with-previewing-index-0',
226190
'/variant-containers-with-previewing-index-1',

packages/sdks-tests/src/specs/index.ts

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -250,39 +250,15 @@ export const PAGES: Record<string, Page> = {
250250
'/video-lazy-load': { content: VIDEO_LAZY_LOAD },
251251
'/variant-containers': {
252252
content: VARIANT_CONTAINERS,
253-
target: [
254-
'react-sdk-next-15-app',
255-
'gen1-next15-app',
256-
'react-sdk-next-pages',
257-
'gen1-next14-pages',
258-
],
259253
},
260254
'/variant-containers-with-previewing-index-0': {
261255
content: VARIANT_CONTAINERS,
262-
target: [
263-
'react-sdk-next-15-app',
264-
'gen1-next15-app',
265-
'react-sdk-next-pages',
266-
'gen1-next14-pages',
267-
],
268256
},
269257
'/variant-containers-with-previewing-index-1': {
270258
content: VARIANT_CONTAINERS_WITH_PREVIEWING_INDEX_1,
271-
target: [
272-
'react-sdk-next-15-app',
273-
'gen1-next15-app',
274-
'react-sdk-next-pages',
275-
'gen1-next14-pages',
276-
],
277259
},
278260
'/variant-containers-with-previewing-index-undefined': {
279261
content: VARIANT_CONTAINERS_WITH_PREVIEWING_INDEX_UNDEFINED,
280-
target: [
281-
'react-sdk-next-15-app',
282-
'gen1-next15-app',
283-
'react-sdk-next-pages',
284-
'gen1-next14-pages',
285-
],
286262
},
287263
'/columns-vertical-center-flex': { content: COLUMNS_VERTICAL_CENTER_FLEX },
288264
'/can-track-false-pre-init': { content: HOMEPAGE, target: 'gen1' },

packages/sdks-tests/src/specs/variant-containers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export const VARIANT_CONTAINERS = {
143143
{
144144
'@type': '@builder.io/sdk:Element',
145145
'@version': 2,
146-
id: 'builder-f90383ccd64745ada9399da4f492b466',
146+
id: 'builder-a1fa7007203347ce817e860661bbea79',
147147
component: {
148148
name: 'PersonalizationContainer',
149149
options: {

packages/sdks/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,4 @@ Legend:
9393
| Global Content Styles ||||| ❌ (Does not apply) |||| |
9494
| CSS Nesting (`&` operator) ||||| ❌ (Does not apply) |||| |
9595
| Locale Support ||||||||| |
96+
| Variant Containers | 🏗 || 🏗 || 🏗 || 🏗 | 🏗 | |

0 commit comments

Comments
 (0)