Skip to content

Commit

Permalink
Supplant MagentoRouteHandler (#1966)
Browse files Browse the repository at this point in the history
* Supplant MagentoRouteHandler with Routes

* Handle PR feedback

* Address PR feedback

* Export error strings

* Fix unit tests

* Remove client-only route consideration
  • Loading branch information
jimbo authored and dpatil-magento committed Nov 13, 2019
1 parent 0f91cd4 commit d0164ba
Show file tree
Hide file tree
Showing 14 changed files with 458 additions and 36 deletions.
15 changes: 15 additions & 0 deletions packages/peregrine/lib/talons/MagentoRoute/addToCache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const addToCache = async (...urls) => {
if (!window.caches) {
throw new Error(
'Current environment does not support CacheStorage at window.caches.'
);
}

const cache = await window.caches.open(
`workbox-runtime-${location.origin}/`
);

await cache.addAll(urls);
};

export default addToCache;
57 changes: 57 additions & 0 deletions packages/peregrine/lib/talons/MagentoRoute/getRouteComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import resolveUnknownRoute from '../../Router/resolveUnknownRoute';

export const INTERNAL_ERROR = 'INTERNAL_ERROR';
export const NOT_FOUND = 'NOT_FOUND';

const getRouteComponent = async (apiBase, pathname) => {
// At build time, `fetchRootComponent` is injected as a global.
// Depending on the environment, this global will be either an
// ES module with a `default` property, or a plain CJS module.
const fetchRoot =
'default' in fetchRootComponent
? fetchRootComponent.default
: fetchRootComponent;

try {
// try to resolve the route
// if this throws, we essentially have a 500 Internal Error
const resolvedRoute = await resolveUnknownRoute({
apiBase,
route: pathname
});

// urlResolver query returns null if a route can't be found
if (!resolvedRoute) {
throw new Error('404');
}

const { type, id } = resolvedRoute;
// if resolution and destructuring succeed but return no match
// then we have a straightforward 404 Not Found
if (!type || !id) {
throw new Error('404');
}

// at this point we should have a matching RootComponent
// if this throws, we essentially have a 500 Internal Error
const component = await fetchRoot(type);

// associate the matching RootComponent with this location
return {
component,
id,
pathname,
type
};
} catch (e) {
const routeError = e.message === '404' ? NOT_FOUND : INTERNAL_ERROR;

console.error(e);

// we don't have a matching RootComponent, but we've checked for one
// so associate the appropriate error case with this location
return { pathname, routeError };
}
};

export default getRouteComponent;
2 changes: 2 additions & 0 deletions packages/peregrine/lib/talons/MagentoRoute/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { INTERNAL_ERROR, NOT_FOUND } from './getRouteComponent';
export { useMagentoRoute } from './useMagentoRoute';
61 changes: 61 additions & 0 deletions packages/peregrine/lib/talons/MagentoRoute/useMagentoRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { useEffect, useRef, useState } from 'react';
import { useLocation } from 'react-router-dom';
import { useApolloClient } from '@apollo/react-hooks';

import addToCache from './addToCache';
import getRouteComponent from './getRouteComponent';

const IS_LOADING = { isLoading: true };

export const useMagentoRoute = () => {
const [componentMap, setComponentMap] = useState(new Map());
const { apiBase } = useApolloClient();
const { pathname } = useLocation();
const isMountedRef = useRef(false);

const routeData = componentMap.get(pathname);

// ask Magento for a RootComponent that matches the current pathname
useEffect(() => {
// avoid asking if we already know the answer
const isKnown = componentMap.has(pathname);

// ask again following a prior failure
const isNotFound = isKnown && componentMap.get(pathname).id === -1;
const shouldReload = isNotFound && navigator.onLine;

if (!isKnown || shouldReload) {
getRouteComponent(apiBase, pathname).then(
({ component, id, pathname, routeError }) => {
// avoid setting state if unmounted
if (!isMountedRef.current) {
return;
}

// add the pathname to the browser cache
addToCache(pathname);

// then add the pathname and result to local state
setComponentMap(prevMap => {
const nextMap = new Map(prevMap);
const nextValue = routeError
? { hasError: true, routeError }
: { component, id };

return nextMap.set(pathname, nextValue);
});
}
);
}
}, [apiBase, componentMap, pathname]);

useEffect(() => {
isMountedRef.current = true;

return () => {
isMountedRef.current = false;
};
}, []);

return routeData || IS_LOADING;
};
2 changes: 1 addition & 1 deletion packages/venia-ui/lib/RootComponents/Search/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
* description = 'Basic Search'
* pageTypes = SEARCH
*/
export { default } from './search';
export { default } from '../../components/SearchPage';
1 change: 0 additions & 1 deletion packages/venia-ui/lib/RootComponents/Search/search.js

This file was deleted.

Loading

0 comments on commit d0164ba

Please sign in to comment.