From fb5cf2a22deb5476e7baaeb17fb403a358ce81b7 Mon Sep 17 00:00:00 2001 From: PASQUET Fabien Date: Wed, 29 Mar 2023 10:27:08 +0200 Subject: [PATCH] fixup! feat: improvement of the web perf --- .../{manifest.json => web-app-manifest.json} | 0 src/config/website/socialNetworks.ts | 6 ++ .../useFooterContainer.tsx | 1 + ...iner.tsx => useLayoutTemplateContainer.ts} | 28 +++++- src/entry-server.tsx | 27 +++++- src/templates/HtmlTemplate/HtmlTemplate.tsx | 92 +++++++++---------- .../LayoutTemplate/Header/Header.tsx | 2 +- 7 files changed, 103 insertions(+), 53 deletions(-) rename public/{manifest.json => web-app-manifest.json} (100%) rename src/containers/LayoutTemplateContainer/{useLayoutTemplateContainer.tsx => useLayoutTemplateContainer.ts} (52%) diff --git a/public/manifest.json b/public/web-app-manifest.json similarity index 100% rename from public/manifest.json rename to public/web-app-manifest.json diff --git a/src/config/website/socialNetworks.ts b/src/config/website/socialNetworks.ts index 99527595e..6d102741a 100644 --- a/src/config/website/socialNetworks.ts +++ b/src/config/website/socialNetworks.ts @@ -1,26 +1,32 @@ import { IconNameType } from '@eleven-labs/design-system'; export const socialNetworks: { + label: string; iconName: Extract; url: string; }[] = [ { + label: 'RSS', iconName: 'rss', url: 'https://blog.eleven-labs.com/feed.xml', }, { + label: 'Facebook', iconName: 'facebook', url: 'https://www.facebook.com/11Labs', }, { + label: 'Twitter', iconName: 'twitter', url: 'https://www.twitter.com/eleven_labs/', }, { + label: 'LinkedIn', iconName: 'linkedin', url: 'https://linkedin.com/company/eleven-labs', }, { + label: 'Welcome to the Jungle', iconName: 'welcometothejungle', url: 'https://www.welcometothejungle.com/companies/eleven-labs', }, diff --git a/src/containers/LayoutTemplateContainer/useFooterContainer.tsx b/src/containers/LayoutTemplateContainer/useFooterContainer.tsx index c7a580b34..052817593 100644 --- a/src/containers/LayoutTemplateContainer/useFooterContainer.tsx +++ b/src/containers/LayoutTemplateContainer/useFooterContainer.tsx @@ -48,6 +48,7 @@ export const useFooterContainer = (): LayoutTemplateProps['footer'] => { eventLabel: socialNetwork.iconName, iconName: socialNetwork.iconName, to: socialNetwork.url, + 'aria-label': socialNetwork.label, })), languageLinks: AUTHORIZED_LANGUAGES.map((currentLang) => { const isActive = currentLang === i18n.language; diff --git a/src/containers/LayoutTemplateContainer/useLayoutTemplateContainer.tsx b/src/containers/LayoutTemplateContainer/useLayoutTemplateContainer.ts similarity index 52% rename from src/containers/LayoutTemplateContainer/useLayoutTemplateContainer.tsx rename to src/containers/LayoutTemplateContainer/useLayoutTemplateContainer.ts index 9bcfcdc46..8ce0e6810 100644 --- a/src/containers/LayoutTemplateContainer/useLayoutTemplateContainer.tsx +++ b/src/containers/LayoutTemplateContainer/useLayoutTemplateContainer.ts @@ -1,20 +1,42 @@ -import { useTitle } from 'hoofd'; +import { useHead, useLink } from 'hoofd'; import { useTranslation } from 'react-i18next'; import { useLocation } from 'react-router-dom'; +import { googleSiteVerificationKey, themeColor } from '@/config/website'; import { useCookieConsentContainer } from '@/containers/LayoutTemplateContainer/useCookieConsentContainer'; import { useFooterContainer } from '@/containers/LayoutTemplateContainer/useFooterContainer'; import { useHeaderContainer } from '@/containers/LayoutTemplateContainer/useHeaderContainer'; +import { getPathFile } from '@/helpers/assetHelper'; import { useLayoutEffect } from '@/hooks/useLayoutEffect'; import { LayoutTemplateProps } from '@/templates/LayoutTemplate'; export const useLayoutTemplateContainer = (): Omit => { - const { t } = useTranslation(); + const { t, i18n } = useTranslation(); const location = useLocation(); const header = useHeaderContainer(); const footer = useFooterContainer(); const cookieConsent = useCookieConsentContainer(); - useTitle(t('meta.title')); + useHead({ + title: t('meta.title'), + metas: [ + { + name: 'google-site-verification', + content: googleSiteVerificationKey, + }, + { + name: 'apple-mobile-web-app-title', + content: 'Blog Eleven Labs', + }, + { + name: 'theme-color', + content: themeColor, + }, + ], + language: i18n.language, + }); + useLink({ rel: 'apple-touch-icon', sizes: '120x120', href: getPathFile('/imgs/icons/apple-icon-120x120.png') }); + useLink({ rel: 'apple-touch-icon', sizes: '152x152', href: getPathFile('/imgs/icons/apple-icon-152x152.png') }); + useLink({ rel: 'apple-touch-icon', sizes: '180x180', href: getPathFile('/imgs/icons/apple-icon-180x180.png') }); /* eslint-disable @typescript-eslint/no-explicit-any */ useLayoutEffect(() => { diff --git a/src/entry-server.tsx b/src/entry-server.tsx index 2a8272bdf..ef51bc890 100644 --- a/src/entry-server.tsx +++ b/src/entry-server.tsx @@ -14,7 +14,7 @@ import { HtmlTemplate, HtmlTemplateProps } from '@/templates/HtmlTemplate'; export type RenderOptions = { request: Request; i18n: i18n; -} & Pick; +} & Pick; export const render = async (options: RenderOptions): Promise => { const dispatcher = createDispatcher(); @@ -37,9 +37,30 @@ export const render = async (options: RenderOptions): Promise => { ); const staticPayload = dispatcher.toStatic(); - return ReactDOMServer.renderToString( + const html = ReactDOMServer.renderToString( - + ({ charSet, ...meta }))} + styles={options.styles} + scripts={[ + ...(options.scripts ?? []), + ...(staticPayload.scripts?.map(({ crossorigin: crossOrigin, ...script }) => ({ crossOrigin, ...script })) ?? + []), + ]} + links={[ + ...(options.links ?? []), + ...(staticPayload.links?.map(({ crossorigin: crossOrigin, hreflang: hrefLang, ...link }) => ({ + crossOrigin, + hrefLang, + ...link, + })) ?? []), + ]} + /> ); + + return `\n${html}`; }; diff --git a/src/templates/HtmlTemplate/HtmlTemplate.tsx b/src/templates/HtmlTemplate/HtmlTemplate.tsx index b052c4cba..77ef68195 100644 --- a/src/templates/HtmlTemplate/HtmlTemplate.tsx +++ b/src/templates/HtmlTemplate/HtmlTemplate.tsx @@ -1,54 +1,63 @@ -import { StaticPayload } from 'hoofd/dist/dispatcher'; -import React from 'react'; +import * as React from 'react'; -import { googleSiteVerificationKey, themeColor } from '@/config/website'; import { getPathFile } from '@/helpers/assetHelper'; export interface HtmlTemplateProps { - staticPayload: StaticPayload; + lang: string; + title: string; content: string; - links?: StaticPayload['links']; - scripts?: StaticPayload['scripts']; + metas?: Array>; + links?: Array>; + styles?: Array & { text?: string }>; + scripts?: Array & { critical?: boolean; text?: string }>; } -export const HtmlTemplate: React.FC = ({ staticPayload, content, links, scripts }) => ( - +const renderScripts = (scripts: HtmlTemplateProps['scripts']): JSX.Element[] | undefined => + scripts?.map((script, index) => ( +