From fb0c79c182b7cbfc8341589cc0356dabbfcfe8d6 Mon Sep 17 00:00:00 2001 From: sc-illiakovalenko <55081915+sc-illiakovalenko@users.noreply.github.com> Date: Thu, 21 Jan 2021 09:40:11 +0200 Subject: [PATCH] [NextJS] Fix dev mode fast refresh in Experience Editor (#532) --- packages/sitecore-jss-nextjs/src/index.ts | 2 ++ packages/sitecore-jss-nextjs/src/utils.ts | 39 +++++++++++++++++++++++ samples/nextjs/src/pages/[[...path]].tsx | 12 ++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/packages/sitecore-jss-nextjs/src/index.ts b/packages/sitecore-jss-nextjs/src/index.ts index a32b9b5098..1cef6d8477 100644 --- a/packages/sitecore-jss-nextjs/src/index.ts +++ b/packages/sitecore-jss-nextjs/src/index.ts @@ -47,6 +47,8 @@ export { useComponentProps, } from './components/ComponentPropsContext'; +export { handleExperienceEditorFastRefresh } from './utils'; + export { EditingData, EditingPreviewData, isEditingData } from './sharedTypes/editing-data'; export { EditingDataService, diff --git a/packages/sitecore-jss-nextjs/src/utils.ts b/packages/sitecore-jss-nextjs/src/utils.ts index e025653d2b..20bfeb2ca9 100644 --- a/packages/sitecore-jss-nextjs/src/utils.ts +++ b/packages/sitecore-jss-nextjs/src/utils.ts @@ -1,4 +1,5 @@ import chalk from 'chalk'; +import { isExperienceEditorActive, resetExperienceEditorChromes } from '@sitecore-jss/sitecore-jss'; export const getPublicUrl = (): string => { let url = process.env.PUBLIC_URL; @@ -20,6 +21,44 @@ export const getPublicUrl = (): string => { return url.toString().replace(/\/$/, ''); }; +/** + * Since Experience Editor does not support Fast Refresh: + * 1. Subscribe on events provided by webpack. + * 2. Reset experience editor chromes when build is finished + * @param {boolean} [forceReload] force page reload instead of reset chromes + * @default forceReload false + */ +export const handleExperienceEditorFastRefresh = (forceReload = false): void => { + if (isExperienceEditorActive()) { + const eventSource = new window.EventSource(`${getPublicUrl()}/_next/webpack-hmr`); + + window.addEventListener('beforeunload', () => eventSource.close()); + + eventSource.onopen = () => console.log('[Experience Editor Fast Refresh Listener] Online'); + + eventSource.onmessage = (event) => { + if (event.data.indexOf('{') === -1) return; // heartbeat + + const payload = JSON.parse(event.data); + + console.debug( + `[Experience Editor Fast Refresh Listener] Saw event: ${JSON.stringify(payload)}` + ); + + if (payload.action !== 'built') return; + + if (forceReload) return window.location.reload(); + + setTimeout(() => { + console.log( + '[Experience Editor HMR Listener] Experience Editor does not support Fast Refresh, reloading chromes...' + ); + resetExperienceEditorChromes(); + }, 500); + }; + } +}; + export const getJssEditingSecret = (): string => { const secret = process.env.JSS_EDITING_SECRET; if (!secret || secret.length === 0) { diff --git a/samples/nextjs/src/pages/[[...path]].tsx b/samples/nextjs/src/pages/[[...path]].tsx index 6a8f62aa74..963999e1fe 100644 --- a/samples/nextjs/src/pages/[[...path]].tsx +++ b/samples/nextjs/src/pages/[[...path]].tsx @@ -1,13 +1,23 @@ +import { useEffect } from 'react'; import { GetStaticPaths, GetStaticProps } from 'next'; import NotFound from 'components/NotFound'; import Layout from 'components/Layout'; -import { SitecoreContext, ComponentPropsContext } from '@sitecore-jss/sitecore-jss-nextjs'; +import { + SitecoreContext, + ComponentPropsContext, + handleExperienceEditorFastRefresh, +} from '@sitecore-jss/sitecore-jss-nextjs'; import { StyleguideSitecoreContextValue } from 'lib/component-props'; import { SitecorePageProps } from 'lib/page-props'; import { sitecorePagePropsFactory } from 'lib/page-props-factory'; import { componentFactory } from 'temp/componentFactory'; const SitecorePage = ({ notFound, layoutData, componentProps }: SitecorePageProps): JSX.Element => { + useEffect(() => { + // Since Experience Editor does not support Fast Refresh need to refresh EE chromes after Fast Refresh finished + handleExperienceEditorFastRefresh(); + }, []); + if (notFound) { return ; }