From 65bbfce3835c1916a4d9fa84b0d0da15e0565af9 Mon Sep 17 00:00:00 2001 From: "Ana Carolina D. C" <76822093+devartes@users.noreply.github.com> Date: Thu, 23 Nov 2023 16:08:31 -0300 Subject: [PATCH 1/7] feat: add docs 'sending only necessary data to client' --- .../en.md | 24 +++++++++++++++++++ .../pt.md | 24 +++++++++++++++++++ docs/toc.ts | 19 ++++++++++----- 3 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 docs/performance/sending-only-necessary-data-to-client/en.md create mode 100644 docs/performance/sending-only-necessary-data-to-client/pt.md diff --git a/docs/performance/sending-only-necessary-data-to-client/en.md b/docs/performance/sending-only-necessary-data-to-client/en.md new file mode 100644 index 00000000..0a466328 --- /dev/null +++ b/docs/performance/sending-only-necessary-data-to-client/en.md @@ -0,0 +1,24 @@ +--- +description: TODO +since: 1.0.0 +--- + +In some situations, when using [loaders](http://localhost:8000/docs/en/concepts/loader) to fetch data, an excessive amount of information may be received, negatively impacting page performance. This is evidenced by the significant size of the JSON transmitted to the client. + +To mitigate this issue, we propose implementing a client-side data preprocessing process, ensuring that only necessary information is transmitted and used in the markup/UI. + +## Data Flow + +1. Data Request: Initiate the normal data flow by requesting the necessary information through props. + +2. Data Loader: Use a loader to fetch the desired data. In some scenarios, the loader may return a substantial amount of data, for instance, when fetching related products from [VTEX](https://www.deco.cx/docs/en/composable-apis/vtex). However, it's essential to note that there are instances where the loader might return more data than necessary for the specific operation. + +3. Inline Preprocessing: Introduce an inline data preprocessing mechanism. This component will receive the same props as the loader and process the data to transmit only essential information, optimizing performance. + +4. Delivery to Component: Transmit only the processed data to the JSX component, thus reducing unnecessary load on the client. + +## Benefits +- Significant reduction in the size of transmitted JSON. +- Noticeable improvement in page performance, especially in terms of loading. + +By implementing this data preprocessing process, it is possible to optimize page performance, ensuring that only crucial information is sent and processed, providing a more streamlined performance for the user. \ No newline at end of file diff --git a/docs/performance/sending-only-necessary-data-to-client/pt.md b/docs/performance/sending-only-necessary-data-to-client/pt.md new file mode 100644 index 00000000..9db958b6 --- /dev/null +++ b/docs/performance/sending-only-necessary-data-to-client/pt.md @@ -0,0 +1,24 @@ +--- +description: TODO +since: 1.0.0 +--- + +Em algumas situações, ao utilizar [loaders](http://localhost:8000/docs/pt/concepts/loader) para obter dados, pode-se receber uma quantidade excessiva de informações, impactando negativamente o desempenho da página. Isso é evidenciado pelo tamanho significativo do JSON transmitido para o cliente. + +Para mitigar esse problema, propomos a implementação de um processo de pré-processamento dos dados no lado do cliente, garantindo que apenas as informações necessárias sejam transmitidas e utilizadas no markup/UI. + +## Fluxo de Dados + +1. Solicitação de Dados: Inicie o fluxo normal de dados, solicitando as informações necessárias por meio de props. + +2. Loader de Dados: Utilize um loader para obter os dados desejados. Em algumas situações, o loader pode retornar uma quantidade substancial de dados, por exemplo, ao solicitar produtos relacionados da [VTEX](https://www.deco.cx/docs/pt/composable-apis/vtex). No entanto, é importante observar que há momentos em que o loader pode retornar uma quantidade de dados maior do que o necessário para a operação em questão. + +3. Pré-Processamento Inline: Introduza um mecanismo de pré-processamento de dados inline. Este componente receberá as mesmas props do loader e processará os dados de forma a transmitir apenas as informações essenciais, otimizando assim o desempenho. + +4. Entrega ao Componente: Transmita apenas os dados processados para o componente JSX, reduzindo assim a carga desnecessária no cliente. + +## Benefícios +- Redução significativa no tamanho do JSON transmitido. +- Melhoria perceptível no desempenho da página, especialmente em termos de carregamento. + +Ao implementar esse processo de pré-processamento de dados, é possível otimizar a performance da página, garantindo que apenas as informações cruciais sejam enviadas e processadas, proporcionando um desempenho mais otimizado para o usuário. \ No newline at end of file diff --git a/docs/toc.ts b/docs/toc.ts index 2cb70820..16f65d48 100644 --- a/docs/toc.ts +++ b/docs/toc.ts @@ -280,17 +280,24 @@ const tableOfContents: TableOfContents = [ }, { title: { - pt: "Como usar a deco para atingir alta performance", - en: "How can you use deco for achieve high performance", + pt: "Dicas para atingir uma alta performance", + en: "Performance tips", }, - slug: "performance/how-deco-performance", + slug: "performance/tips", }, { title: { - pt: "Dicas para atingir uma alta performance", - en: "Performance tips", + pt: "Enviar apenas os dados necessários para o cliente", + en: "Sending only necessary data to client", }, - slug: "performance/tips", + slug: "performance/sending-only-necessary-data-to-client", + }, + { + title: { + pt: "Como usar a deco para atingir alta performance", + en: "How can you use deco for achieve high performance", + }, + slug: "performance/how-deco-performance", }, ], }, From e758e2950da61a8bcff8bc775416d0e60c793c2f Mon Sep 17 00:00:00 2001 From: devartes Date: Mon, 4 Dec 2023 17:49:31 -0300 Subject: [PATCH 2/7] docs: add images and code examples --- .../en.md | 113 ++++++++++++++++- .../pt.md | 114 +++++++++++++++++- 2 files changed, 225 insertions(+), 2 deletions(-) diff --git a/docs/performance/sending-only-necessary-data-to-client/en.md b/docs/performance/sending-only-necessary-data-to-client/en.md index 0a466328..3a46a570 100644 --- a/docs/performance/sending-only-necessary-data-to-client/en.md +++ b/docs/performance/sending-only-necessary-data-to-client/en.md @@ -5,6 +5,8 @@ since: 1.0.0 In some situations, when using [loaders](http://localhost:8000/docs/en/concepts/loader) to fetch data, an excessive amount of information may be received, negatively impacting page performance. This is evidenced by the significant size of the JSON transmitted to the client. +![287814343-44b8fc59-2c25-4a55-bbe3-16810d5501a6](https://github.com/deco-sites/starting/assets/76822093/ab2d2212-1e3e-487d-ad6a-3eb225f9b15b) + To mitigate this issue, we propose implementing a client-side data preprocessing process, ensuring that only necessary information is transmitted and used in the markup/UI. ## Data Flow @@ -17,8 +19,117 @@ To mitigate this issue, we propose implementing a client-side data preprocessing 4. Delivery to Component: Transmit only the processed data to the JSX component, thus reducing unnecessary load on the client. +## Example Code + +This is the implementation of the `storefront/loaders/Layouts/ProductCard.tsx`: + +```tsx +import ProductCard, { Layout } from "$store/components/product/ProductCard.tsx"; +import { usePlatform } from "$store/sdk/usePlatform.tsx"; + +interface Props { + /** @title Product Card layout props */ + layout: Layout; +} + +/** @title Product Card Layout */ +const loader = ({ layout }: Props): Layout => layout; + +export const Preview = (props: Props) => { + const { layout } = props; + + return ( +
+
+ Camisetas Gola Lisa", + "productID": "165", + "url": "", + "name": "Product Test", + "description": "Product Description", + "brand": { + "@type": "Brand", + "@id": "2000000", + "name": "deco.cx", + }, + "inProductGroupWithID": "33", + "sku": "165", + "gtin": "789456123003305", + "additionalProperty": [ + { + "@type": "PropertyValue", + "name": "TAMANHO", + "value": "GG", + "valueReference": "SPECIFICATION", + }, + ], + "isVariantOf": { + "@type": "ProductGroup", + "productGroupID": "33", + "hasVariant": [], + "name": "Camiseta Masculina Gola Lisa Olive", + "additionalProperty": [], + }, + "image": [ + { + "@type": "ImageObject", + "alternateName": "test", + "url": + "https://ozksgdmyrqcxcwhnbepg.supabase.co/storage/v1/object/public/assets/2291/b9e0a819-6a75-47af-84fe-90b44fecda5f", + }, + { + "@type": "ImageObject", + "alternateName": "test", + "url": + "https://ozksgdmyrqcxcwhnbepg.supabase.co/storage/v1/object/public/assets/2291/b9e0a819-6a75-47af-84fe-90b44fecda5f", + }, + ], + "offers": { + "@type": "AggregateOffer", + "priceCurrency": "BRL", + "highPrice": 69.3, + "lowPrice": 69.3, + "offerCount": 1, + "offers": [ + { + "@type": "Offer", + "price": 69.3, + "seller": "1", + "priceValidUntil": "2024-09-04T13:03:31Z", + "inventoryLevel": { "value": 10000 }, + "teasers": [], + "priceSpecification": [ + { + "@type": "UnitPriceSpecification", + "priceType": "https://schema.org/ListPrice", + "price": 179, + }, + { + "@type": "UnitPriceSpecification", + "priceType": "https://schema.org/SalePrice", + "price": 69.3, + }, + ], + "availability": "https://schema.org/InStock", + }, + ], + }, + }} + /> +
+
+ ); +}; + +export default loader; +``` + ## Benefits - Significant reduction in the size of transmitted JSON. - Noticeable improvement in page performance, especially in terms of loading. -By implementing this data preprocessing process, it is possible to optimize page performance, ensuring that only crucial information is sent and processed, providing a more streamlined performance for the user. \ No newline at end of file +By implementing this data preprocessing process, it is possible to optimize page performance, ensuring that only crucial information is sent and processed, providing a more streamlined performance for the user. diff --git a/docs/performance/sending-only-necessary-data-to-client/pt.md b/docs/performance/sending-only-necessary-data-to-client/pt.md index 9db958b6..59482245 100644 --- a/docs/performance/sending-only-necessary-data-to-client/pt.md +++ b/docs/performance/sending-only-necessary-data-to-client/pt.md @@ -5,6 +5,9 @@ since: 1.0.0 Em algumas situações, ao utilizar [loaders](http://localhost:8000/docs/pt/concepts/loader) para obter dados, pode-se receber uma quantidade excessiva de informações, impactando negativamente o desempenho da página. Isso é evidenciado pelo tamanho significativo do JSON transmitido para o cliente. +![287813945-9ccd40a6-f41f-486f-a2b6-3f1efca0bfd1](https://github.com/deco-sites/starting/assets/76822093/bff19a56-bc1d-475b-b25d-f45fd1af713a) + + Para mitigar esse problema, propomos a implementação de um processo de pré-processamento dos dados no lado do cliente, garantindo que apenas as informações necessárias sejam transmitidas e utilizadas no markup/UI. ## Fluxo de Dados @@ -17,8 +20,117 @@ Para mitigar esse problema, propomos a implementação de um processo de pré-pr 4. Entrega ao Componente: Transmita apenas os dados processados para o componente JSX, reduzindo assim a carga desnecessária no cliente. +## Código de exemplo + +Esta é a implementação do Loader `storefront/loaders/Layouts/ProductCard.tsx`: + +```tsx +import ProductCard, { Layout } from "$store/components/product/ProductCard.tsx"; +import { usePlatform } from "$store/sdk/usePlatform.tsx"; + +interface Props { + /** @title Product Card layout props */ + layout: Layout; +} + +/** @title Product Card Layout */ +const loader = ({ layout }: Props): Layout => layout; + +export const Preview = (props: Props) => { + const { layout } = props; + + return ( +
+
+ Camisetas Gola Lisa", + "productID": "165", + "url": "", + "name": "Product Test", + "description": "Product Description", + "brand": { + "@type": "Brand", + "@id": "2000000", + "name": "deco.cx", + }, + "inProductGroupWithID": "33", + "sku": "165", + "gtin": "789456123003305", + "additionalProperty": [ + { + "@type": "PropertyValue", + "name": "TAMANHO", + "value": "GG", + "valueReference": "SPECIFICATION", + }, + ], + "isVariantOf": { + "@type": "ProductGroup", + "productGroupID": "33", + "hasVariant": [], + "name": "Camiseta Masculina Gola Lisa Olive", + "additionalProperty": [], + }, + "image": [ + { + "@type": "ImageObject", + "alternateName": "test", + "url": + "https://ozksgdmyrqcxcwhnbepg.supabase.co/storage/v1/object/public/assets/2291/b9e0a819-6a75-47af-84fe-90b44fecda5f", + }, + { + "@type": "ImageObject", + "alternateName": "test", + "url": + "https://ozksgdmyrqcxcwhnbepg.supabase.co/storage/v1/object/public/assets/2291/b9e0a819-6a75-47af-84fe-90b44fecda5f", + }, + ], + "offers": { + "@type": "AggregateOffer", + "priceCurrency": "BRL", + "highPrice": 69.3, + "lowPrice": 69.3, + "offerCount": 1, + "offers": [ + { + "@type": "Offer", + "price": 69.3, + "seller": "1", + "priceValidUntil": "2024-09-04T13:03:31Z", + "inventoryLevel": { "value": 10000 }, + "teasers": [], + "priceSpecification": [ + { + "@type": "UnitPriceSpecification", + "priceType": "https://schema.org/ListPrice", + "price": 179, + }, + { + "@type": "UnitPriceSpecification", + "priceType": "https://schema.org/SalePrice", + "price": 69.3, + }, + ], + "availability": "https://schema.org/InStock", + }, + ], + }, + }} + /> +
+
+ ); +}; + +export default loader; +``` + ## Benefícios - Redução significativa no tamanho do JSON transmitido. - Melhoria perceptível no desempenho da página, especialmente em termos de carregamento. -Ao implementar esse processo de pré-processamento de dados, é possível otimizar a performance da página, garantindo que apenas as informações cruciais sejam enviadas e processadas, proporcionando um desempenho mais otimizado para o usuário. \ No newline at end of file +Ao implementar esse processo de pré-processamento de dados, é possível otimizar a performance da página, garantindo que apenas as informações cruciais sejam enviadas e processadas, proporcionando um desempenho mais otimizado para o usuário. From 801c8442dfa1dbdca8b6dbee268d1faea7447482 Mon Sep 17 00:00:00 2001 From: devartes Date: Tue, 5 Dec 2023 18:18:36 -0300 Subject: [PATCH 3/7] docs: applying improvement suggestions --- .../en.md | 136 ++++------------- .../pt.md | 141 ++++-------------- 2 files changed, 64 insertions(+), 213 deletions(-) diff --git a/docs/performance/sending-only-necessary-data-to-client/en.md b/docs/performance/sending-only-necessary-data-to-client/en.md index 3a46a570..a4dc9949 100644 --- a/docs/performance/sending-only-necessary-data-to-client/en.md +++ b/docs/performance/sending-only-necessary-data-to-client/en.md @@ -1,131 +1,57 @@ --- -description: TODO +description: Sending only necessary data to client since: 1.0.0 --- -In some situations, when using [loaders](http://localhost:8000/docs/en/concepts/loader) to fetch data, an excessive amount of information may be received, negatively impacting page performance. This is evidenced by the significant size of the JSON transmitted to the client. +When loading data from external APIs using [Loaders](/docs/pt/concepts/loader) and sending them to the [Section](/docs/pt/concepts/section), it is possible that the size of the _payload_ may negatively impact the site's performance. The impact occurs both in the initial loading time and in the [hydration](https://blog.saeloun.com/2021/12/16/hydration/), where the page is "initialized" in the browser to make it interactive (using `useEffect`, `useSignal`, etc.). You can visualize the size of the final JSON in the **Performance** tab in the CMS deco. -![287814343-44b8fc59-2c25-4a55-bbe3-16810d5501a6](https://github.com/deco-sites/starting/assets/76822093/ab2d2212-1e3e-487d-ad6a-3eb225f9b15b) +![288067513-db3a14e1-c0ac-47f8-83b9-afc8db60de71](https://github.com/deco-sites/starting/assets/76822093/ec005f5d-4169-4e89-acd0-8c06baf3c80d) -To mitigate this issue, we propose implementing a client-side data preprocessing process, ensuring that only necessary information is transmitted and used in the markup/UI. +When the JSON size exceeds ~500kb, it's likely that the UI doesn't need the complete data but rather some portion of it, or a computation based on other values. To reduce this size and improve page performance, it's possible to **filter the data** directly in the Loader, passing only what is necessary to the UI. ## Data Flow -1. Data Request: Initiate the normal data flow by requesting the necessary information through props. +- Initiate the request for necessary information using props. -2. Data Loader: Use a loader to fetch the desired data. In some scenarios, the loader may return a substantial amount of data, for instance, when fetching related products from [VTEX](https://www.deco.cx/docs/en/composable-apis/vtex). However, it's essential to note that there are instances where the loader might return more data than necessary for the specific operation. +- Employ a loader to fetch the desired data. In certain situations, it may return a substantial amount of data, for instance, when requesting products from [VTEX](https://www.deco.cx/docs/en/composable-apis/vtex). Be aware that it might return more data than necessary. -3. Inline Preprocessing: Introduce an inline data preprocessing mechanism. This component will receive the same props as the loader and process the data to transmit only essential information, optimizing performance. - -4. Delivery to Component: Transmit only the processed data to the JSX component, thus reducing unnecessary load on the client. +- Transmit only the processed data to the JSX component, thereby reducing unnecessary load on the client. ## Example Code -This is the implementation of the `storefront/loaders/Layouts/ProductCard.tsx`: +Implementation example of a [Loader](docs/en/developing/fetching-data): ```tsx -import ProductCard, { Layout } from "$store/components/product/ProductCard.tsx"; -import { usePlatform } from "$store/sdk/usePlatform.tsx"; +import type { SectionProps } from "deco/mod.ts"; -interface Props { - /** @title Product Card layout props */ - layout: Layout; +// Props type that will be configured in deco.cx's Admin +export interface Props { + title: string; + numberOfFacts?: number; } -/** @title Product Card Layout */ -const loader = ({ layout }: Props): Layout => layout; - -export const Preview = (props: Props) => { - const { layout } = props; +export async function loader( + { numberOfFacts, title }: Props, + _req: Request, +) { + const { facts: dogFacts } = (await fetch( + `https://dogapi.dog/api/facts?number=${numberOfFacts ?? 1}`, + ).then((r) => r.json())) as { facts: string[] }; + return { dogFacts, title }; +} +export default function DogFacts( + { title, dogFacts }: SectionProps, +) { return ( -
-
- Camisetas Gola Lisa", - "productID": "165", - "url": "", - "name": "Product Test", - "description": "Product Description", - "brand": { - "@type": "Brand", - "@id": "2000000", - "name": "deco.cx", - }, - "inProductGroupWithID": "33", - "sku": "165", - "gtin": "789456123003305", - "additionalProperty": [ - { - "@type": "PropertyValue", - "name": "TAMANHO", - "value": "GG", - "valueReference": "SPECIFICATION", - }, - ], - "isVariantOf": { - "@type": "ProductGroup", - "productGroupID": "33", - "hasVariant": [], - "name": "Camiseta Masculina Gola Lisa Olive", - "additionalProperty": [], - }, - "image": [ - { - "@type": "ImageObject", - "alternateName": "test", - "url": - "https://ozksgdmyrqcxcwhnbepg.supabase.co/storage/v1/object/public/assets/2291/b9e0a819-6a75-47af-84fe-90b44fecda5f", - }, - { - "@type": "ImageObject", - "alternateName": "test", - "url": - "https://ozksgdmyrqcxcwhnbepg.supabase.co/storage/v1/object/public/assets/2291/b9e0a819-6a75-47af-84fe-90b44fecda5f", - }, - ], - "offers": { - "@type": "AggregateOffer", - "priceCurrency": "BRL", - "highPrice": 69.3, - "lowPrice": 69.3, - "offerCount": 1, - "offers": [ - { - "@type": "Offer", - "price": 69.3, - "seller": "1", - "priceValidUntil": "2024-09-04T13:03:31Z", - "inventoryLevel": { "value": 10000 }, - "teasers": [], - "priceSpecification": [ - { - "@type": "UnitPriceSpecification", - "priceType": "https://schema.org/ListPrice", - "price": 179, - }, - { - "@type": "UnitPriceSpecification", - "priceType": "https://schema.org/SalePrice", - "price": 69.3, - }, - ], - "availability": "https://schema.org/InStock", - }, - ], - }, - }} - /> -
+
+

{title}

+
    + {dogFacts.map((fact) =>
  • {fact}
  • )} +
); -}; - -export default loader; +} ``` ## Benefits diff --git a/docs/performance/sending-only-necessary-data-to-client/pt.md b/docs/performance/sending-only-necessary-data-to-client/pt.md index 59482245..7d75c7f0 100644 --- a/docs/performance/sending-only-necessary-data-to-client/pt.md +++ b/docs/performance/sending-only-necessary-data-to-client/pt.md @@ -1,132 +1,57 @@ --- -description: TODO +descrição: Enviando apenas dados necessários ao cliente since: 1.0.0 --- -Em algumas situações, ao utilizar [loaders](http://localhost:8000/docs/pt/concepts/loader) para obter dados, pode-se receber uma quantidade excessiva de informações, impactando negativamente o desempenho da página. Isso é evidenciado pelo tamanho significativo do JSON transmitido para o cliente. +Ao carregar dados de APIs externas usando [Loaders](/docs/pt/concepts/loader) e enviá-los para a [Section](/docs/pt/concepts/section), é possível que o tamanho do _payload_ impacte negativamente a performance do site. O impacto ocorre tanto no tempo inicial de carregamento como também no [hidratação](https://blog.saeloun.com/2021/12/16/hydration/), onde a página é "inicializada" no browser para que possa ser interativa (usar `useEffect`, `useSignal`, etc...). É possível visualizar no tamanho do JSON final através da aba **Performance** no CMS deco. -![287813945-9ccd40a6-f41f-486f-a2b6-3f1efca0bfd1](https://github.com/deco-sites/starting/assets/76822093/bff19a56-bc1d-475b-b25d-f45fd1af713a) +![288067513-db3a14e1-c0ac-47f8-83b9-afc8db60de71](https://github.com/deco-sites/starting/assets/76822093/ec005f5d-4169-4e89-acd0-8c06baf3c80d) - -Para mitigar esse problema, propomos a implementação de um processo de pré-processamento dos dados no lado do cliente, garantindo que apenas as informações necessárias sejam transmitidas e utilizadas no markup/UI. +Quando o tamanho do JSON passa de ~500kb, é provável que a UI não precisa do dado completo, mas sim alguma parte dele (ou então uma computação sobre outros valores). Para diminuir esse tamanho e e melhorar a performance da página, é possível **filtrar os dados** ainda no Loader para que apenas o necessário seja passado para a UI. ## Fluxo de Dados -1. Solicitação de Dados: Inicie o fluxo normal de dados, solicitando as informações necessárias por meio de props. - -2. Loader de Dados: Utilize um loader para obter os dados desejados. Em algumas situações, o loader pode retornar uma quantidade substancial de dados, por exemplo, ao solicitar produtos relacionados da [VTEX](https://www.deco.cx/docs/pt/composable-apis/vtex). No entanto, é importante observar que há momentos em que o loader pode retornar uma quantidade de dados maior do que o necessário para a operação em questão. - -3. Pré-Processamento Inline: Introduza um mecanismo de pré-processamento de dados inline. Este componente receberá as mesmas props do loader e processará os dados de forma a transmitir apenas as informações essenciais, otimizando assim o desempenho. - -4. Entrega ao Componente: Transmita apenas os dados processados para o componente JSX, reduzindo assim a carga desnecessária no cliente. +- Inicie solicitando as informações necessárias usando props. + +- Utilize um loader para obter os dados desejados. Em algumas situações, pode retornar muitos dados, como ao solicitar produtos da [VTEX](https://www.deco.cx/docs/pt/composable-apis/vtex). Esteja ciente de que pode retornar mais dados do que o necessário. + +- Transmita apenas os dados processados para o componente JSX, reduzindo assim a carga desnecessária no cliente. ## Código de exemplo -Esta é a implementação do Loader `storefront/loaders/Layouts/ProductCard.tsx`: +Exemplo de implementação de um [Loader](docs/pt/developing/fetching-data): ```tsx -import ProductCard, { Layout } from "$store/components/product/ProductCard.tsx"; -import { usePlatform } from "$store/sdk/usePlatform.tsx"; +import type { SectionProps } from "deco/mod.ts"; -interface Props { - /** @title Product Card layout props */ - layout: Layout; +// Props type that will be configured in deco.cx's Admin +export interface Props { + title: string; + numberOfFacts?: number; } -/** @title Product Card Layout */ -const loader = ({ layout }: Props): Layout => layout; - -export const Preview = (props: Props) => { - const { layout } = props; +export async function loader( + { numberOfFacts, title }: Props, + _req: Request, +) { + const { facts: dogFacts } = (await fetch( + `https://dogapi.dog/api/facts?number=${numberOfFacts ?? 1}`, + ).then((r) => r.json())) as { facts: string[] }; + return { dogFacts, title }; +} +export default function DogFacts( + { title, dogFacts }: SectionProps, +) { return ( -
-
- Camisetas Gola Lisa", - "productID": "165", - "url": "", - "name": "Product Test", - "description": "Product Description", - "brand": { - "@type": "Brand", - "@id": "2000000", - "name": "deco.cx", - }, - "inProductGroupWithID": "33", - "sku": "165", - "gtin": "789456123003305", - "additionalProperty": [ - { - "@type": "PropertyValue", - "name": "TAMANHO", - "value": "GG", - "valueReference": "SPECIFICATION", - }, - ], - "isVariantOf": { - "@type": "ProductGroup", - "productGroupID": "33", - "hasVariant": [], - "name": "Camiseta Masculina Gola Lisa Olive", - "additionalProperty": [], - }, - "image": [ - { - "@type": "ImageObject", - "alternateName": "test", - "url": - "https://ozksgdmyrqcxcwhnbepg.supabase.co/storage/v1/object/public/assets/2291/b9e0a819-6a75-47af-84fe-90b44fecda5f", - }, - { - "@type": "ImageObject", - "alternateName": "test", - "url": - "https://ozksgdmyrqcxcwhnbepg.supabase.co/storage/v1/object/public/assets/2291/b9e0a819-6a75-47af-84fe-90b44fecda5f", - }, - ], - "offers": { - "@type": "AggregateOffer", - "priceCurrency": "BRL", - "highPrice": 69.3, - "lowPrice": 69.3, - "offerCount": 1, - "offers": [ - { - "@type": "Offer", - "price": 69.3, - "seller": "1", - "priceValidUntil": "2024-09-04T13:03:31Z", - "inventoryLevel": { "value": 10000 }, - "teasers": [], - "priceSpecification": [ - { - "@type": "UnitPriceSpecification", - "priceType": "https://schema.org/ListPrice", - "price": 179, - }, - { - "@type": "UnitPriceSpecification", - "priceType": "https://schema.org/SalePrice", - "price": 69.3, - }, - ], - "availability": "https://schema.org/InStock", - }, - ], - }, - }} - /> -
+
+

{title}

+
    + {dogFacts.map((fact) =>
  • {fact}
  • )} +
); -}; - -export default loader; +} ``` ## Benefícios From 51bbe3fdf43be0b61e58684fdd55798aea315bd4 Mon Sep 17 00:00:00 2001 From: devartes Date: Tue, 5 Dec 2023 18:42:38 -0300 Subject: [PATCH 4/7] docs: modify the content of the text --- docs/performance/sending-only-necessary-data-to-client/en.md | 2 +- docs/performance/sending-only-necessary-data-to-client/pt.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/performance/sending-only-necessary-data-to-client/en.md b/docs/performance/sending-only-necessary-data-to-client/en.md index a4dc9949..6c0edfc0 100644 --- a/docs/performance/sending-only-necessary-data-to-client/en.md +++ b/docs/performance/sending-only-necessary-data-to-client/en.md @@ -13,7 +13,7 @@ When the JSON size exceeds ~500kb, it's likely that the UI doesn't need the comp - Initiate the request for necessary information using props. -- Employ a loader to fetch the desired data. In certain situations, it may return a substantial amount of data, for instance, when requesting products from [VTEX](https://www.deco.cx/docs/en/composable-apis/vtex). Be aware that it might return more data than necessary. +- Use a loader to fetch the desired data. In some situations, it might return a large amount of data, for example, when requesting related products from [VTEX](https://www.deco.cx/docs/en/composable-apis/vtex). Be aware that it might return more data than necessary. - Transmit only the processed data to the JSX component, thereby reducing unnecessary load on the client. diff --git a/docs/performance/sending-only-necessary-data-to-client/pt.md b/docs/performance/sending-only-necessary-data-to-client/pt.md index 7d75c7f0..cf41e662 100644 --- a/docs/performance/sending-only-necessary-data-to-client/pt.md +++ b/docs/performance/sending-only-necessary-data-to-client/pt.md @@ -13,7 +13,7 @@ Quando o tamanho do JSON passa de ~500kb, é provável que a UI não precisa do - Inicie solicitando as informações necessárias usando props. -- Utilize um loader para obter os dados desejados. Em algumas situações, pode retornar muitos dados, como ao solicitar produtos da [VTEX](https://www.deco.cx/docs/pt/composable-apis/vtex). Esteja ciente de que pode retornar mais dados do que o necessário. +- Utilize um loader para obter os dados desejados. Em algumas situações, pode retornar muitos dados, por exemplo, ao solicitar produtos relacionados da [VTEX](https://www.deco.cx/docs/pt/composable-apis/vtex). Esteja ciente de que pode retornar mais dados do que o necessário. - Transmita apenas os dados processados para o componente JSX, reduzindo assim a carga desnecessária no cliente. From c53ec6e943c19b26dd00ae8bcf395cec78cb3b6c Mon Sep 17 00:00:00 2001 From: guitavano Date: Fri, 8 Dec 2023 14:47:55 -0300 Subject: [PATCH 5/7] add other examples --- .../pt.md | 164 ++++++++++++++---- 1 file changed, 131 insertions(+), 33 deletions(-) diff --git a/docs/performance/sending-only-necessary-data-to-client/pt.md b/docs/performance/sending-only-necessary-data-to-client/pt.md index cf41e662..e4f019f5 100644 --- a/docs/performance/sending-only-necessary-data-to-client/pt.md +++ b/docs/performance/sending-only-necessary-data-to-client/pt.md @@ -3,57 +3,155 @@ descrição: Enviando apenas dados necessários ao cliente since: 1.0.0 --- -Ao carregar dados de APIs externas usando [Loaders](/docs/pt/concepts/loader) e enviá-los para a [Section](/docs/pt/concepts/section), é possível que o tamanho do _payload_ impacte negativamente a performance do site. O impacto ocorre tanto no tempo inicial de carregamento como também no [hidratação](https://blog.saeloun.com/2021/12/16/hydration/), onde a página é "inicializada" no browser para que possa ser interativa (usar `useEffect`, `useSignal`, etc...). É possível visualizar no tamanho do JSON final através da aba **Performance** no CMS deco. +Ao carregar dados de APIs externas usando [Loaders](/docs/pt/concepts/loader) e enviá-los para a [Section](/docs/pt/concepts/section), é possível que o tamanho do _payload_ impacte negativamente a performance do site. O impacto ocorre tanto no tempo inicial de carregamento como também na [hidratação](https://blog.saeloun.com/2021/12/16/hydration/), onde a página é "inicializada" no browser para que possa ser interativa (usar `useEffect`, `useSignal`, etc...). É possível visualizar no tamanho do JSON final através da aba **Performance** no CMS deco. ![288067513-db3a14e1-c0ac-47f8-83b9-afc8db60de71](https://github.com/deco-sites/starting/assets/76822093/ec005f5d-4169-4e89-acd0-8c06baf3c80d) -Quando o tamanho do JSON passa de ~500kb, é provável que a UI não precisa do dado completo, mas sim alguma parte dele (ou então uma computação sobre outros valores). Para diminuir esse tamanho e e melhorar a performance da página, é possível **filtrar os dados** ainda no Loader para que apenas o necessário seja passado para a UI. +Quando o tamanho do JSON passa de ~500kb, é provável que a UI não precise do dado completo, mas sim alguma parte dele (ou então uma computação sobre outros valores). Para diminuir esse tamanho e melhorar a performance da página, é possível **filtrar os dados** ainda no Loader para que apenas o necessário seja passado para a UI. -## Fluxo de Dados -- Inicie solicitando as informações necessárias usando props. - -- Utilize um loader para obter os dados desejados. Em algumas situações, pode retornar muitos dados, por exemplo, ao solicitar produtos relacionados da [VTEX](https://www.deco.cx/docs/pt/composable-apis/vtex). Esteja ciente de que pode retornar mais dados do que o necessário. +## Código de exemplo - 1 + +Nesse primeiro exemplo, mostraremos como evitar enviar muitos dados para uma Island. + +Digamos que existe um componente chamado ProductCard, que recebe todo o JSON de um produto. + +```tsx + import Image from "apps/website/components/Image.tsx" -- Transmita apenas os dados processados para o componente JSX, reduzindo assim a carga desnecessária no cliente. + export default function ProductCard({product} : Props){ + return( +
+ +
+ ) + } +``` + +Nele, você deseja incluir uma [Island](https://fresh.deno.dev/docs/concepts/islands) para criar o botão de comprar. + +```tsx + import BuyButton from "$store/components/ui" + import Image from "apps/website/components/Image.tsx" + + export default function ProductCard({product} : Props){ + + return( +
+ + +
+ ) + } +``` + +É possível que esse BuyButton, precise de algumas informações do produto para poder adicionar ao carrinho. -## Código de exemplo +Aqui que devemos tomar cuidado a quantidade de dados enviados para a Island. -Exemplo de implementação de um [Loader](docs/pt/developing/fetching-data): +Por exemplo, é bem possível que o botão de comprar não precise receber dados de imagem. + +O ideal é enviar apenas os dados necessários + +* Abordagem errada: + +```tsx + import BuyButton from "$store/components/ui" + import Image from "apps/website/components/Image.tsx" + + export default function ProductCard({product} : Props){ + + return( +
+ + +
+ ) + } +``` + +* Abordagem correta: + +```tsx + import BuyButton from "$store/components/ui" + import Image from "apps/website/components/Image.tsx" + + export default function ProductCard({product} : Props){ + + return( +
+ + +
+ ) + } +``` + +A abordagem correta envia apenas os dados de ID e Seller, que no exemplo, são os únicos necessários na Island. + +Assim, no momento de hidratação, o JSON que a Island irá carregar não será tão grande. + +## Código de exemplo - 2 + +Neste exemplo, vamos mostrar como evitar enviar um dado muito grande para uma section. + +Digamos que temos um loader inline para buscar as cores do produto e retornar em uma section. ```tsx -import type { SectionProps } from "deco/mod.ts"; +export default function Colors({colors}){ -// Props type that will be configured in deco.cx's Admin -export interface Props { - title: string; - numberOfFacts?: number; + return colors.map(color => {color}) } -export async function loader( - { numberOfFacts, title }: Props, - _req: Request, -) { - const { facts: dogFacts } = (await fetch( - `https://dogapi.dog/api/facts?number=${numberOfFacts ?? 1}`, - ).then((r) => r.json())) as { facts: string[] }; - return { dogFacts, title }; +export const loader = async () => { + const colors = await fetch("/product/colors").then(r => r.json()) + + return colors; +} +``` + +Esse componente parece correto, certo? + +Porém, após uma investigação, verificamos que o dado retornado trazia também as imagens do produto. + +Exemplo do retorno da API: + +```tsx +colors = [ + { + "color": "red" + "images": [...] + }, + { + "color": "green" + "images": [...] + }, + { + "color": "orange" + "images": [...] + }, +}] +``` + +Os dados de imagem nesse retorno, não serão utilizados na section, então não precisamos enviá-los. + +Podemos filtrar dessa forma: + +```tsx +export default function Colors({colors}){ + + return colors.map(color => {color}) } -export default function DogFacts( - { title, dogFacts }: SectionProps, -) { - return ( -
-

{title}

-
    - {dogFacts.map((fact) =>
  • {fact}
  • )} -
-
- ); +export const loader = async () => { + const result = await fetch("/product/colors").then(r => r.json()) + const colors = result.map(item => item.color) + return colors; } ``` +Dessa forma, apenas os dados utilizados serão enviados, evitando uma sobrecarga desnecessária. + ## Benefícios - Redução significativa no tamanho do JSON transmitido. - Melhoria perceptível no desempenho da página, especialmente em termos de carregamento. From be934d7be5cadbc4ff143e2d80bfdd3f8bbd647d Mon Sep 17 00:00:00 2001 From: devartes Date: Fri, 8 Dec 2023 16:19:34 -0300 Subject: [PATCH 6/7] docs: sending documentation translated into English 'Sending only necessary data to the client' --- .../en.md | 163 ++++++++++++++---- 1 file changed, 131 insertions(+), 32 deletions(-) diff --git a/docs/performance/sending-only-necessary-data-to-client/en.md b/docs/performance/sending-only-necessary-data-to-client/en.md index 6c0edfc0..4c7fac04 100644 --- a/docs/performance/sending-only-necessary-data-to-client/en.md +++ b/docs/performance/sending-only-necessary-data-to-client/en.md @@ -3,57 +3,156 @@ description: Sending only necessary data to client since: 1.0.0 --- -When loading data from external APIs using [Loaders](/docs/pt/concepts/loader) and sending them to the [Section](/docs/pt/concepts/section), it is possible that the size of the _payload_ may negatively impact the site's performance. The impact occurs both in the initial loading time and in the [hydration](https://blog.saeloun.com/2021/12/16/hydration/), where the page is "initialized" in the browser to make it interactive (using `useEffect`, `useSignal`, etc.). You can visualize the size of the final JSON in the **Performance** tab in the CMS deco. +When loading data from external APIs using [Loaders](/docs/en/concepts/loader) and sending them to the [Section](/docs/en/concepts/section), it's possible that the size of the payload may negatively impact the site's performance. The impact occurs both in the initial loading time and in the [hydration](https://blog.saeloun.com/2021/12/16/hydration/), where the page is "initialized" in the browser to make it interactive (using `useEffect`, `useSignal`, etc.). It's possible to visualize the size of the final JSON through the **Performance** tab in the CMS deco. ![288067513-db3a14e1-c0ac-47f8-83b9-afc8db60de71](https://github.com/deco-sites/starting/assets/76822093/ec005f5d-4169-4e89-acd0-8c06baf3c80d) -When the JSON size exceeds ~500kb, it's likely that the UI doesn't need the complete data but rather some portion of it, or a computation based on other values. To reduce this size and improve page performance, it's possible to **filter the data** directly in the Loader, passing only what is necessary to the UI. +When the JSON size exceeds ~500kb, it's likely that the UI doesn't need the complete data but rather some part of it (or a computation based on other values). To reduce this size and improve page performance, it's possible to **filter the data** still on the loader to ensure that only the necessary data is passed to the UI. -## Data Flow -- Initiate the request for necessary information using props. +## Example Code - 1 -- Use a loader to fetch the desired data. In some situations, it might return a large amount of data, for example, when requesting related products from [VTEX](https://www.deco.cx/docs/en/composable-apis/vtex). Be aware that it might return more data than necessary. +In this first example, we will show how to avoid sending too much data to an Island. -- Transmit only the processed data to the JSX component, thereby reducing unnecessary load on the client. +Let's say there's a component called ProductCard, which receives the entire JSON of a product. -## Example Code +```tsx + import Image from "apps/website/components/Image.tsx" + + export default function ProductCard({product} : Props){ + return( +
+ +
+ ) + } +``` + +In it, you want to include an [Island](https://fresh.deno.dev/docs/concepts/islands) to create the buy button. + +```tsx + import BuyButton from "$store/components/ui" + import Image from "apps/website/components/Image.tsx" + + export default function ProductCard({product} : Props){ + + return( +
+ + +
+ ) + } +``` + +It's possible that this BuyButton may need some product information to be able to add it to the cart. + +Here is where we should be careful about the amount of data sent to the Island. + +For example, it's quite possible that the buy button doesn't need to receive image data. + +The ideal approach is to send only the necessary data. + +* Wrong Approach: + +```tsx + import BuyButton from "$store/components/ui" + import Image from "apps/website/components/Image.tsx" + + export default function ProductCard({product} : Props){ + + return( +
+ + +
+ ) + } +``` + +* Correct Approach: + +```tsx + import BuyButton from "$store/components/ui" + import Image from "apps/website/components/Image.tsx" + + export default function ProductCard({product} : Props){ + + return( +
+ + +
+ ) + } +``` -Implementation example of a [Loader](docs/en/developing/fetching-data): +The correct approach sends only the ID and Seller data, which in this example are the only ones needed in the Island. + +Thus, during hydration, the JSON that the Island will load won't be as large. + +## Example Code - 2 + +In this example, we will show how to avoid sending a very large piece of data to a section. + +Let's say we have an inline loader to fetch product colors and return them in a section. ```tsx -import type { SectionProps } from "deco/mod.ts"; +export default function Colors({colors}){ -// Props type that will be configured in deco.cx's Admin -export interface Props { - title: string; - numberOfFacts?: number; + return colors.map(color => {color}) } -export async function loader( - { numberOfFacts, title }: Props, - _req: Request, -) { - const { facts: dogFacts } = (await fetch( - `https://dogapi.dog/api/facts?number=${numberOfFacts ?? 1}`, - ).then((r) => r.json())) as { facts: string[] }; - return { dogFacts, title }; +export const loader = async () => { + const colors = await fetch("/product/colors").then(r => r.json()) + + return colors; } +``` + +This component seems correct, right? + +However, after an investigation, we found that the returned data also included product images. -export default function DogFacts( - { title, dogFacts }: SectionProps, -) { - return ( -
-

{title}

-
    - {dogFacts.map((fact) =>
  • {fact}
  • )} -
-
- ); +Example of the API response: + +```tsx +colors = [ + { + "color": "red" + "images": [...] + }, + { + "color": "green" + "images": [...] + }, + { + "color": "orange" + "images": [...] + }, +}] +``` + +The image data in this response will not be used in the section, so we don't need to send it. + +We can filter it like this: + + +```tsx +export default function Colors({colors}){ + + return colors.map(color => {color}) +} + +export const loader = async () => { + const result = await fetch("/product/colors").then(r => r.json()) + const colors = result.map(item => item.color) + return colors; } ``` +This way, only the data that is used will be sent, avoiding unnecessary overload. + ## Benefits - Significant reduction in the size of transmitted JSON. - Noticeable improvement in page performance, especially in terms of loading. From 5155f55a022fcba8deaa3ea64852c4c8f5a4cfce Mon Sep 17 00:00:00 2001 From: devartes Date: Wed, 13 Dec 2023 12:22:19 -0300 Subject: [PATCH 7/7] docs: update documentation --- docs/performance/sending-only-necessary-data-to-client/en.md | 4 ++-- docs/performance/sending-only-necessary-data-to-client/pt.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/performance/sending-only-necessary-data-to-client/en.md b/docs/performance/sending-only-necessary-data-to-client/en.md index 4c7fac04..157dde2b 100644 --- a/docs/performance/sending-only-necessary-data-to-client/en.md +++ b/docs/performance/sending-only-necessary-data-to-client/en.md @@ -53,7 +53,7 @@ For example, it's quite possible that the buy button doesn't need to receive ima The ideal approach is to send only the necessary data. -* Wrong Approach: +❌ Wrong Approach: ```tsx import BuyButton from "$store/components/ui" @@ -70,7 +70,7 @@ The ideal approach is to send only the necessary data. } ``` -* Correct Approach: +✅ Correct Approach: ```tsx import BuyButton from "$store/components/ui" diff --git a/docs/performance/sending-only-necessary-data-to-client/pt.md b/docs/performance/sending-only-necessary-data-to-client/pt.md index e4f019f5..761f5ffd 100644 --- a/docs/performance/sending-only-necessary-data-to-client/pt.md +++ b/docs/performance/sending-only-necessary-data-to-client/pt.md @@ -53,7 +53,7 @@ Por exemplo, é bem possível que o botão de comprar não precise receber dados O ideal é enviar apenas os dados necessários -* Abordagem errada: +❌ Abordagem errada: ```tsx import BuyButton from "$store/components/ui" @@ -70,7 +70,7 @@ O ideal é enviar apenas os dados necessários } ``` -* Abordagem correta: +✅ Abordagem correta: ```tsx import BuyButton from "$store/components/ui"