@faststore/core 3.0.129 → 3.0.131

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.
Files changed (54) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +16 -16
  3. package/.next/cache/.tsbuildinfo +1 -1
  4. package/.next/cache/config.json +3 -3
  5. package/.next/cache/eslint/.cache_1gneedd +1 -1
  6. package/.next/cache/webpack/client-production/0.pack +0 -0
  7. package/.next/cache/webpack/client-production/index.pack +0 -0
  8. package/.next/cache/webpack/server-production/0.pack +0 -0
  9. package/.next/cache/webpack/server-production/index.pack +0 -0
  10. package/.next/next-server.js.nft.json +1 -1
  11. package/.next/prerender-manifest.js +1 -1
  12. package/.next/prerender-manifest.json +1 -1
  13. package/.next/react-loadable-manifest.json +2 -2
  14. package/.next/routes-manifest.json +1 -1
  15. package/.next/server/chunks/350.js +1 -1
  16. package/.next/server/chunks/371.js +1 -1
  17. package/.next/server/chunks/430.js +1 -1
  18. package/.next/server/chunks/671.js +1 -1
  19. package/.next/server/chunks/96.js +1 -1
  20. package/.next/server/middleware-build-manifest.js +1 -1
  21. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  22. package/.next/server/pages/api/graphql.js +1 -1
  23. package/.next/server/pages/en-US/404.html +1 -1
  24. package/.next/server/pages/en-US/404.json +1 -1
  25. package/.next/server/pages/en-US/500.html +1 -1
  26. package/.next/server/pages/en-US/500.json +1 -1
  27. package/.next/server/pages/en-US/account.html +1 -1
  28. package/.next/server/pages/en-US/account.json +1 -1
  29. package/.next/server/pages/en-US/checkout.html +1 -1
  30. package/.next/server/pages/en-US/checkout.json +1 -1
  31. package/.next/server/pages/en-US/login.html +1 -1
  32. package/.next/server/pages/en-US/login.json +1 -1
  33. package/.next/server/pages/en-US/s.html +1 -1
  34. package/.next/server/pages/en-US/s.json +1 -1
  35. package/.next/server/pages/en-US.html +2 -2
  36. package/.next/server/pages/en-US.json +1 -1
  37. package/.next/server/pages-manifest.json +1 -1
  38. package/.next/static/chunks/798.f16a775f53df6766.js +1 -0
  39. package/.next/static/chunks/{87-5709356a398fea13.js → 87-84bd07d1b983e0d6.js} +1 -1
  40. package/.next/static/chunks/pages/{_app-ed807a0c1aebeb38.js → _app-cb1c3a94f987c5c8.js} +1 -1
  41. package/.next/static/chunks/{webpack-904b033805de64d4.js → webpack-ca5fe5a8d57b1bda.js} +1 -1
  42. package/.next/static/{Ywtu8htMrJApXXIOtVA2F → o69X4-v2dIUnsnwvKME49}/_buildManifest.js +1 -1
  43. package/.next/trace +94 -94
  44. package/.turbo/turbo-build.log +3 -3
  45. package/.turbo/turbo-test.log +4 -4
  46. package/discovery.config.default.js +1 -0
  47. package/next.config.js +10 -0
  48. package/package.json +13 -13
  49. package/src/components/cms/ViewportObserver.tsx +88 -0
  50. package/src/components/product/ProductGrid/ProductGrid.tsx +82 -21
  51. package/src/components/ui/ProductGallery/ProductGallery.tsx +4 -3
  52. package/src/components/ui/ProductGallery/ProductGalleryPage.tsx +10 -2
  53. package/.next/static/chunks/758.829db9862d9c4add.js +0 -1
  54. /package/.next/static/{Ywtu8htMrJApXXIOtVA2F → o69X4-v2dIUnsnwvKME49}/_ssgManifest.js +0 -0
@@ -37,8 +37,8 @@ https://nextjs.org/telemetry
37
37
  Collecting page data ...
38
38
  Generating static pages (0/7) ...
39
39
 
40
40
  Generating static pages (1/7)
41
-
42
41
  Generating static pages (3/7)
43
42
  Warning: Dynamic Content not found for the page: home. Refer to the Dynamic Content documentation at https://developers.vtex.com/docs/guides/faststore/dynamic-content-overview for mapping the page and the corresponding data-fetching function.
43
+
44
44
  Generating static pages (3/7)
45
45
 
46
46
  Generating static pages (5/7)
47
47
 
48
48
  ✓ Generating static pages (7/7)
49
49
  Finalizing page optimization ...
@@ -65,8 +65,8 @@ Route (pages) Size First Load JS
65
65
  + First Load JS shared by all 93.8 kB
66
66
  ├ chunks/framework-8e279965036b6169.js 45.4 kB
67
67
  ├ chunks/main-029f1328cfee9686.js 33.1 kB
68
- ├ chunks/pages/_app-ed807a0c1aebeb38.js 9.87 kB
69
- ├ chunks/webpack-904b033805de64d4.js 2.45 kB
68
+ ├ chunks/pages/_app-cb1c3a94f987c5c8.js 9.87 kB
69
+ ├ chunks/webpack-ca5fe5a8d57b1bda.js 2.45 kB
70
70
  └ css/ee0556daedda6306.css 3.07 kB
71
71
 
72
72
  λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps)
@@ -1,10 +1,10 @@
1
1
  $ jest
2
- PASS test/utils/multipleTemplates.test.ts (34.431 s)
3
- PASS test/server/cms/index.test.ts (34.65 s)
4
- PASS test/server/index.test.ts (37.634 s)
2
+ PASS test/utils/multipleTemplates.test.ts (33.901 s)
3
+ PASS test/server/cms/index.test.ts (34.829 s)
4
+ PASS test/server/index.test.ts (38.864 s)
5
5
 
6
6
  Test Suites: 3 passed, 3 total
7
7
  Tests: 19 passed, 19 total
8
8
  Snapshots: 0 total
9
- Time: 38.771 s
9
+ Time: 40.098 s
10
10
  Ran all test suites.
@@ -100,5 +100,6 @@ module.exports = {
100
100
  cypressVersion: 12,
101
101
  enableCypressExtension: false,
102
102
  noRobots: false,
103
+ preact: false,
103
104
  },
104
105
  }
package/next.config.js CHANGED
@@ -46,6 +46,16 @@ const nextConfig = {
46
46
  config.optimization.splitChunks.maxInitialRequests = 1
47
47
  }
48
48
 
49
+ if (storeConfig.experimental.preact && !isServer && !dev) {
50
+ Object.assign(config.resolve.alias, {
51
+ react: 'preact/compat',
52
+
53
+ 'react-dom/test-utils': 'preact/test-utils',
54
+
55
+ 'react-dom': 'preact/compat',
56
+ })
57
+ }
58
+
49
59
  return config
50
60
  },
51
61
  redirects: storeConfig.redirects,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/core",
3
- "version": "3.0.129",
3
+ "version": "3.0.131",
4
4
  "license": "MIT",
5
5
  "repository": "vtex/faststore",
6
6
  "browserslist": "supports es6-module and not dead",
@@ -39,16 +39,16 @@
39
39
  "dependencies": {
40
40
  "@antfu/ni": "^0.21.12",
41
41
  "@builder.io/partytown": "^0.6.1",
42
- "@envelop/core": "^4.0.0",
43
- "@envelop/graphql-jit": "^4.0.0",
44
- "@envelop/parser-cache": "^4.0.0",
45
- "@envelop/validation-cache": "^4.0.0",
46
- "@faststore/api": "^3.0.129",
47
- "@faststore/components": "^3.0.116",
48
- "@faststore/graphql-utils": "^3.0.116",
49
- "@faststore/lighthouse": "^3.0.116",
50
- "@faststore/sdk": "^3.0.120",
51
- "@faststore/ui": "^3.0.116",
42
+ "@envelop/core": "^5.0.2",
43
+ "@envelop/graphql-jit": "^8.0.3",
44
+ "@envelop/parser-cache": "^6.0.2",
45
+ "@envelop/validation-cache": "^6.0.2",
46
+ "@faststore/api": "^3.0.131",
47
+ "@faststore/components": "^3.0.131",
48
+ "@faststore/graphql-utils": "^3.0.131",
49
+ "@faststore/lighthouse": "^3.0.131",
50
+ "@faststore/sdk": "^3.0.131",
51
+ "@faststore/ui": "^3.0.131",
52
52
  "@graphql-codegen/cli": "5.0.2",
53
53
  "@graphql-codegen/client-preset": "4.2.6",
54
54
  "@graphql-codegen/typescript": "4.0.7",
@@ -87,7 +87,7 @@
87
87
  "devDependencies": {
88
88
  "@cypress/code-coverage": "^3.12.1",
89
89
  "@envelop/testing": "^6.0.0",
90
- "@faststore/eslint-config": "^3.0.116",
90
+ "@faststore/eslint-config": "^3.0.131",
91
91
  "@lhci/cli": "^0.9.0",
92
92
  "@testing-library/cypress": "^10.0.1",
93
93
  "@types/cypress": "^1.1.3",
@@ -128,5 +128,5 @@
128
128
  "node": "18.19.0",
129
129
  "yarn": "1.19.1"
130
130
  },
131
- "gitHead": "8de84b10ff99f3c137e73c2bb27970f03dc28d62"
131
+ "gitHead": "79ad36cd135fc1f9bacd3224b33b4e5f7c4323da"
132
132
  }
@@ -0,0 +1,88 @@
1
+ import type { PropsWithChildren } from 'react'
2
+ import { useCallback, useEffect, useRef, useState } from 'react'
3
+
4
+ // Mobile height to prevent sections outside the viewport from being rendered initially.
5
+ // We are using the Moto G Power device measurement as a reference, as used by PageSpeed Insights.
6
+ const VIEWPORT_SIZE = 823
7
+
8
+ type ViewportObserverProps = {
9
+ /**
10
+ * Identify the store section
11
+ */
12
+ sectionName?: string
13
+ /**
14
+ * Debug/test purposes: enables visual debugging to identify the visibility of the section.
15
+ */
16
+ debug?: boolean
17
+ } & IntersectionObserverInit
18
+
19
+ function ViewportObserver({
20
+ sectionName = '',
21
+ threshold = 0,
22
+ root = null,
23
+ rootMargin,
24
+ children,
25
+ debug = false,
26
+ }: PropsWithChildren<ViewportObserverProps>) {
27
+ const [isVisible, setVisible] = useState(false)
28
+ const ref = useRef<HTMLDivElement | null>(null)
29
+
30
+ const observerCallback = useCallback(
31
+ ([entry]: IntersectionObserverEntry[], obs: IntersectionObserver) => {
32
+ if (entry.isIntersecting) {
33
+ if (debug) {
34
+ console.log(`section '${sectionName}' VISIBLE`)
35
+ document.body.style.border = '2px solid green'
36
+ }
37
+ setVisible(true)
38
+ if (ref.current) {
39
+ obs.unobserve(ref.current)
40
+ }
41
+ } else {
42
+ setVisible(false)
43
+ if (debug) {
44
+ console.log(`section '${sectionName}' NOT VISIBLE`)
45
+ document.body.style.border = '2px solid red'
46
+ document.body.style.height = `${VIEWPORT_SIZE}px`
47
+ document.body.style.boxSizing = 'border-box'
48
+ }
49
+ }
50
+ },
51
+ [debug, sectionName]
52
+ )
53
+
54
+ useEffect(() => {
55
+ const observer = new IntersectionObserver(observerCallback, {
56
+ root,
57
+ rootMargin,
58
+ threshold,
59
+ })
60
+
61
+ if (ref.current) {
62
+ observer.observe(ref.current)
63
+ }
64
+
65
+ return () => observer.disconnect()
66
+ }, [observerCallback, root, rootMargin, threshold])
67
+
68
+ return (
69
+ <>
70
+ {!isVisible && (
71
+ <div
72
+ data-store-section-name={sectionName}
73
+ ref={ref}
74
+ style={{
75
+ border: debug ? '2px solid red' : undefined,
76
+ backgroundColor: debug ? 'red' : undefined,
77
+ height: VIEWPORT_SIZE, // required to make sections out of the viewport to be rendered on demand
78
+ width: '100%',
79
+ }}
80
+ ></div>
81
+ )}
82
+
83
+ {isVisible && children}
84
+ </>
85
+ )
86
+ }
87
+
88
+ export default ViewportObserver
@@ -7,6 +7,7 @@ import ProductGridSkeleton from 'src/components/skeletons/ProductGridSkeleton'
7
7
  import { ProductCardProps } from '../ProductCard'
8
8
 
9
9
  import { memo } from 'react'
10
+ import ViewportObserver from 'src/components/cms/ViewportObserver'
10
11
  import { useOverrideComponents } from 'src/sdk/overrides/OverrideContext'
11
12
 
12
13
  interface Props {
@@ -26,6 +27,10 @@ interface Props {
26
27
  ProductCardProps,
27
28
  'showDiscountBadge' | 'bordered' | 'taxesConfiguration'
28
29
  >
30
+ /**
31
+ * Identify the number of firstPage
32
+ */
33
+ firstPage?: number
29
34
  }
30
35
 
31
36
  function ProductGrid({
@@ -33,38 +38,94 @@ function ProductGrid({
33
38
  page,
34
39
  pageSize,
35
40
  productCard: { showDiscountBadge, bordered, taxesConfiguration } = {},
41
+ firstPage,
36
42
  }: Props) {
37
43
  const { __experimentalProductCard: ProductCard } =
38
44
  useOverrideComponents<'ProductGallery'>()
39
45
  const aspectRatio = 1
40
46
 
47
+ // TODO: Check if is also isMobile
48
+ const isFirstPage = firstPage === page
49
+
41
50
  return (
42
51
  <ProductGridSkeleton
43
52
  aspectRatio={aspectRatio}
44
53
  loading={products.length === 0}
45
54
  >
46
55
  <UIProductGrid>
47
- {products.map(({ node: product }, idx) => (
48
- <UIProductGridItem key={`${product.id}`}>
49
- <ProductCard.Component
50
- aspectRatio={aspectRatio}
51
- imgProps={{
52
- width: 150,
53
- height: 150,
54
- sizes: '30vw',
55
- loading: idx === 0 ? 'eager' : 'lazy',
56
- }}
57
- {...ProductCard.props}
58
- bordered={bordered ?? ProductCard.props.bordered}
59
- showDiscountBadge={
60
- showDiscountBadge ?? ProductCard.props.showDiscountBadge
61
- }
62
- product={product}
63
- index={pageSize * page + idx + 1}
64
- taxesConfiguration={taxesConfiguration}
65
- />
66
- </UIProductGridItem>
67
- ))}
56
+ {isFirstPage ? (
57
+ <>
58
+ {products.slice(0, 2).map(({ node: product }, idx) => (
59
+ <UIProductGridItem key={`${product.id}`}>
60
+ <ProductCard.Component
61
+ aspectRatio={aspectRatio}
62
+ imgProps={{
63
+ width: 150,
64
+ height: 150,
65
+ sizes: '30vw',
66
+ loading: 'eager',
67
+ }}
68
+ {...ProductCard.props}
69
+ bordered={bordered ?? ProductCard.props.bordered}
70
+ showDiscountBadge={
71
+ showDiscountBadge ?? ProductCard.props.showDiscountBadge
72
+ }
73
+ product={product}
74
+ index={pageSize * page + idx + 1}
75
+ taxesConfiguration={taxesConfiguration}
76
+ />
77
+ </UIProductGridItem>
78
+ ))}
79
+ <></>
80
+ <ViewportObserver sectionName="UIProductGrid-out-viewport">
81
+ {products.slice(2).map(({ node: product }, idx) => (
82
+ <UIProductGridItem key={`${product.id}`}>
83
+ <ProductCard.Component
84
+ aspectRatio={aspectRatio}
85
+ imgProps={{
86
+ width: 150,
87
+ height: 150,
88
+ sizes: '30vw',
89
+ loading: 'lazy',
90
+ }}
91
+ {...ProductCard.props}
92
+ bordered={bordered ?? ProductCard.props.bordered}
93
+ showDiscountBadge={
94
+ showDiscountBadge ?? ProductCard.props.showDiscountBadge
95
+ }
96
+ product={product}
97
+ index={pageSize * page + idx + 1}
98
+ taxesConfiguration={taxesConfiguration}
99
+ />
100
+ </UIProductGridItem>
101
+ ))}
102
+ </ViewportObserver>
103
+ </>
104
+ ) : (
105
+ <>
106
+ {products.map(({ node: product }, idx) => (
107
+ <UIProductGridItem key={`${product.id}`}>
108
+ <ProductCard.Component
109
+ aspectRatio={aspectRatio}
110
+ imgProps={{
111
+ width: 150,
112
+ height: 150,
113
+ sizes: '30vw',
114
+ loading: idx === 0 ? 'eager' : 'lazy',
115
+ }}
116
+ {...ProductCard.props}
117
+ bordered={bordered ?? ProductCard.props.bordered}
118
+ showDiscountBadge={
119
+ showDiscountBadge ?? ProductCard.props.showDiscountBadge
120
+ }
121
+ product={product}
122
+ index={pageSize * page + idx + 1}
123
+ taxesConfiguration={taxesConfiguration}
124
+ />
125
+ </UIProductGridItem>
126
+ ))}
127
+ </>
128
+ )}
68
129
  </UIProductGrid>
69
130
  </ProductGridSkeleton>
70
131
  )
@@ -12,15 +12,15 @@ import ProductGridSkeleton from 'src/components/skeletons/ProductGridSkeleton'
12
12
  import { ProductCardProps } from 'src/components/product/ProductCard'
13
13
  import { FilterSliderProps } from 'src/components/search/Filter/FilterSlider'
14
14
  import { SortProps } from 'src/components/search/Sort/Sort'
15
- import { useDelayedFacets } from 'src/sdk/search/useDelayedFacets'
16
- import { useDelayedPagination } from 'src/sdk/search/useDelayedPagination'
15
+ import { useOverrideComponents } from 'src/sdk/overrides/OverrideContext'
17
16
  import {
18
17
  PLPContext,
19
18
  SearchPageContext,
20
19
  usePage,
21
20
  } from 'src/sdk/overrides/PageProvider'
22
21
  import { useProductsPrefetch } from 'src/sdk/product/useProductsPrefetch'
23
- import { useOverrideComponents } from 'src/sdk/overrides/OverrideContext'
22
+ import { useDelayedFacets } from 'src/sdk/search/useDelayedFacets'
23
+ import { useDelayedPagination } from 'src/sdk/search/useDelayedPagination'
24
24
 
25
25
  const ProductGalleryPage = lazy(() => import('./ProductGalleryPage'))
26
26
  const GalleryPageSkeleton = <ProductGridSkeleton loading />
@@ -237,6 +237,7 @@ function ProductGallery({
237
237
  title={title}
238
238
  productCard={productCard}
239
239
  itemsPerPage={itemsPerPage}
240
+ firstPage={pages[0]}
240
241
  />
241
242
  ))}
242
243
  </Suspense>
@@ -1,8 +1,8 @@
1
1
  import ProductGrid from 'src/components/product/ProductGrid'
2
2
  import Sentinel from 'src/sdk/search/Sentinel'
3
3
 
4
- import { ProductCardProps } from 'src/components/product/ProductCard'
5
4
  import { memo } from 'react'
5
+ import { ProductCardProps } from 'src/components/product/ProductCard'
6
6
  import { useGalleryPage } from 'src/sdk/product/usePageProductsQuery'
7
7
 
8
8
  interface Props {
@@ -13,9 +13,16 @@ interface Props {
13
13
  'showDiscountBadge' | 'bordered' | 'taxesConfiguration'
14
14
  >
15
15
  itemsPerPage: number
16
+ firstPage: number
16
17
  }
17
18
 
18
- function ProductGalleryPage({ page, title, productCard, itemsPerPage }: Props) {
19
+ function ProductGalleryPage({
20
+ page,
21
+ title,
22
+ productCard,
23
+ itemsPerPage,
24
+ firstPage,
25
+ }: Props) {
19
26
  const { data } = useGalleryPage(page)
20
27
 
21
28
  const products = data?.search?.products?.edges ?? []
@@ -33,6 +40,7 @@ function ProductGalleryPage({ page, title, productCard, itemsPerPage }: Props) {
33
40
  page={page}
34
41
  pageSize={itemsPerPage}
35
42
  productCard={productCard}
43
+ firstPage={firstPage}
36
44
  />
37
45
  </>
38
46
  )
@@ -1 +0,0 @@
1
- "use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[758],{5758:function(e,r,t){t.r(r),t.d(r,{default:function(){return j}});var n=t(9499),o=t(2784);let a=(0,o.forwardRef)(function({testId:e="fs-product-grid",children:r,...t},n){return o.createElement("ul",{ref:n,"data-fs-product-grid":!0,...t},r)}),c=(0,o.forwardRef)(function({testId:e="fs-product-grid-item",children:r,...t},n){return o.createElement("li",{ref:n,"data-fs-product-grid-item":!0,...t},r)});var i=t(4548),s=t(4329),u=t(2322);function ownKeys(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter(function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable})),t.push.apply(t,n)}return t}function _objectSpread(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?ownKeys(Object(t),!0).forEach(function(r){(0,n.Z)(e,r,t[r])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):ownKeys(Object(t)).forEach(function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))})}return e}var d=(0,o.memo)(function(e){var{products:r,page:t,pageSize:n,productCard:{showDiscountBadge:o,bordered:d,taxesConfiguration:l}={}}=e,{__experimentalProductCard:p}=(0,s.r3)();return(0,u.jsx)(i.Z,{aspectRatio:1,loading:0===r.length,children:(0,u.jsx)(a,{children:r.map((e,r)=>{var{node:a}=e;return(0,u.jsx)(c,{children:(0,u.jsx)(p.Component,_objectSpread(_objectSpread({aspectRatio:1,imgProps:{width:150,height:150,sizes:"30vw",loading:0===r?"eager":"lazy"}},p.props),{},{bordered:null!=d?d:p.props.bordered,showDiscountBadge:null!=o?o:p.props.showDiscountBadge,product:a,index:n*t+r+1,taxesConfiguration:l}))},"".concat(a.id))})})})}),l=t(9029),p=t(7704),f=t(1163),g=t(6414),replacePagination=(e,r)=>{var t=new URL(window.location.href);t.searchParams.get("page")!==e&&(t.searchParams.set("page",e),r.replace(t,void 0,{shallow:!0,scroll:!1}))},search_Sentinel=function(e){var{page:r,pageSize:t,products:n,title:a}=e,c=(0,o.useRef)(!1),{ref:i,inView:s}=(0,p.YD)(),{pages:d}=(0,l.R)(),h=(0,f.useRouter)(),{sendViewItemListEvent:j}=(0,g.m)({products:n,title:a,page:r,pageSize:t});return(0,o.useEffect)(()=>{s&&d.length>1&&replacePagination(r.toString(),h),s&&!c.current&&n.length&&(j(),c.current=!0)},[d.length,s,r,h,j,n.length]),(0,u.jsx)("div",{ref:i})},h=t(7171),j=(0,o.memo)(function(e){var r,t,n,{page:o,title:a,productCard:c,itemsPerPage:i}=e,{data:s}=(0,h.__)(o),l=null!==(r=null==s?void 0:null===(t=s.search)||void 0===t?void 0:null===(n=t.products)||void 0===n?void 0:n.edges)&&void 0!==r?r:[];return(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(search_Sentinel,{products:l,page:o,pageSize:i,title:a}),(0,u.jsx)(d,{products:l,page:o,pageSize:i,productCard:c})]})})}}]);