@noths/global-components-v2
v5.0.1
Published
A set of global components for NOTHS.
Downloads
513
Maintainers
Keywords
Readme
NOTHS Global Components With Contentstack
Frontend global components used at www.notonthehighstreet.com
Background & context
The purpose of this package is to redevelop the old global-components from vanilla js to React Components that listen to the Contentstack API. The development of the components is split into middleware and presentational components because not all services require both instruments. For example, the Mononoth handles the fetching of Contentstack data itself so only requires the presentational component.
Provided below are branches on how global-components-V2 are integrated in each service.
Components included
- NOTHS Navigation
Global components are components which will be on most pages of the site. except checkout.
The presentational components such as the Navigation are built using react, styled-components & ramda (Ramda was an optional choice, as a helper to assist with data sorting and passing down the datastucture as props to the presentational component)
The Middleware uses Contentstack and requires React 16.9.0+ or higher. The reason for this is due to the use of Context API that react includes in the DOM. This helps rule out other state management packages such a redux as a dependency.
Commit History integrating new navigation in other services:
SSR Webpack & Express App
https://github.com/notonthehighstreet/cms-frontend/commit/a1108ac92ccd323cc0dbfac0738cce434f26918b https://github.com/notonthehighstreet/departments-frontend/commit/1d9a800e44c1cfe0f3cb80c40a1cf7d995f5d47f https://github.com/notonthehighstreet/product-listings/commit/59d103664001122c7c7242bc06e8baa7c3b5c093
Client side only
https://github.com/notonthehighstreet/user-account/commit/a17b4d800365a2b512111054074f2972d17401dd https://github.com/notonthehighstreet/favourites/commit/feb3c936597328ab0d0adc94604be8200c5d870b
Next JS App
https://github.com/notonthehighstreet/user-account-frontend/commit/3cf54e48cd460f6f79df253eadac2298c42c74bd
Hypernova & Mononoth
https://github.com/notonthehighstreet/hypernova-app/commit/20f3598196537e7360b5850986ca9cfbe204f766 https://github.com/notonthehighstreet/notonthehighstreet/commit/505b5ef8e1e9016eb216a426c069cfc4fed0cc27 https://github.com/notonthehighstreet/notonthehighstreet/commit/926c1fd948b0972d10b7a7c758113eed12b93f97
React
import React, { Component } from 'react';
import { GlobalDataContext, Navigation } from '@noths/global-components-v2';
class App extends Component {
render() {
return (
<GlobalDataContext.Consumer>
{({ navData }) => (
<>
<Navigation navData={navData} />
<MainContent>
</>
)}
</GlobalDataContext.Consumer>
);
}
}
Server - Express Middleware
import express from 'express';
import { globalComponentsDataFetcher, GlobalDataContext } from '@noths/global-components-v2';
const appServer = express();
...
const renderApp = async (req, res) => {
const navData = await globalComponentsDataFetcher('qa', 'navigation');
Promise.all().then(() => {
const rootApp = renderToString(
<GlobalDataContext.Provider value={{ navData }}>
<App />
</GlobalDataContext.Provider>
);
const renderHtml = () => {
return `
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="root">${rootApp}</div>
<script type="text/javascript">window.GLOBAL_DATA = ${navData}</script>
</body>
</html>
`
}
res.send(rootApp);
});
}
appServer.use(renderApp);
Client - Hydrating the App
import React from 'react';
import { hydrate } from 'react-dom';
import App from './App';
// Grab the state from a global variable injected into the server-generated HTML
const preloadedGlobalState = window.GLOBAL_DATA;
// Allow the passed state to be garbage-collected
delete window.GLOBAL_DATA;
hydrate(
<GlobalDataContext.Provider value={{ navData: preloadedGlobalState }}>
<App />
</GlobalDataContext.Provider>,
document.getElementById('root')
);
Reason for calling window.GLOBAL_DATA
was the intention of adding footer also. Therefore making it Global.
Also add the css below. This should be a temporary measure until the burger menu from header in the old global-components as the burger menu lives in the header.
@media only screen and (max-width: 47.97917em) {
[global-component].gc-header .gc-header-menu {
position: absolute;
left: 0;
display: none;
}
}
Contentstack
The stack in which the Navigation Data and future Global Components Data should stay in is the "Global Components Stack"
https://app.contentstack.com/#!/stack/blt6444b9076ec27f02/dashboard
https://www.contentstack.com/docs/platforms/javascript-browser
https://www.contentstack.com/docs/platforms/javascript-browser/api-reference/
Confluence:
https://notonthehighstreet.atlassian.net/wiki/spaces/T5D/pages/756776961/Contentstack+resources . This will have the details of who to contact should you ever need more support around contentstack.
Note:
- Contentstack has three environments live (changes visible on the live site), preview (used by content editors to test changes) and qa (used by devs to test changes)
- The live and preview environments run on the same container
Cacheing
All services
- The Contentstack response is cached for x seconds (see notonthehighstreet and node services). Only data from the 'live' Contentstack environment is cached.
notonthehighstreet
- notonthehighstreet caches the response from Hypernova which contains the presentational component and uses the Contentstack response as the cache key
- When installing a new version of the presentational component in Hypernova, in order to see the updated component rendered in notonthehighstreet you will need to bust the cache by re-publishing or editing the entry in Contentstack
Past issues
- Fastly, Contentstack's CDN had slow response times, causing the whole site to slow down. There is now a 5s timeout in place in services for calls to third parties.
Contentstack Navigation Synthetics
https://app.datadoghq.com/synthetics/details/3wm-z9h-gr3
Prerequisites
- NodeJS 8
Setup & run
Install dependencies
npm install
Run Dev Mode
npm run dev
Build Production.
npm run build
NOTE: The build produces two sources. Within the build directory after running build, it will produce build/index.js
& build/components.js
. This was done distinctively to cater for hypernova & mononoth where the hypernova app would only need the presentational component component.js
where as the normal Node & React Apps would point to index.js
as they would require the middleware.
Use the externals for production builds in your app.
<script type="text/javascript" src="https://unpkg.com/react@{ ___VERSION___ }/umd/react.production.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/react-dom@{ ___VERSION___ }/umd/react-dom.production.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/contentstack@{ ___VERSION___ }/dist/web/contentstack.js"></script>
<script type="text/javascript" src="https://unpkg.com/styled-components@{ ___VERSION___ }/dist/styled-components.js"></script>
External CDN Url
The package exposes an externalCDNUrl string which points to the package script hosted on unpkg. As global-components-v2
is bundled in all consumer facing frontend services at NOTHS it makes sense to externalise the package so that users will only download the bundle once per version of the package. The external cdn url should be included after react
, react-dom
and styled-components
Usage
Webpack production config:
externals: {
'@noths/global-components-v2': 'GlobalComponentsV2',
}
Html template:
import { externalCDNUrl } from '@noths/global-components-v2';
<html>
<head>
...
<script type="text/javascript" src={externalCDNUrl} />
</head>
</html>
Testing
There are two different types of tests in the project.
Unit tests
Unit tests use Jest and Enzyme.
To Run Unit Test
npm run test
Feature Test
Feature test uses Cypress.
NOTE: this has been set up as manual process for this time being. Reason for this was due to frontend pacakages is still in early stages of integrating cypress into the CI or if we decided to take a different approach with a new tech.
To run feature tests:
npm run test:dev:features
Stats
To ensure the bundle size for what is compiled is sustainable for performance and file size is reasonable, you can use the visual bundle analyzer made by https://chrisbateman.github.io/webpack-visualizer .
To view this, run a build and a the stats.html should be in the folder as follows - build/stats.html
Releases
The project is hosted on NPM with the name @noths/global-components-v2.
TODO
- Rename this repo back to its original name "global-components"
- Move Header & Footer from vanilla js to React Components
- Develop a re-fetch of nav data on client should server fails. https://notonthehighstreet.atlassian.net/browse/T5-797
- Develop a error logging capture via data-dog. To ensure service are monitored properly. https://notonthehighstreet.atlassian.net/browse/T5-798
- Rebuild the UI of Navigation https://app.zeplin.io/project/5cf6849004fcd97a2f267a67/screen/5d35e3da66bb484104dd5776
- Remove Ramda from the New UI of navigation
- If you ever make the contenttype to include references in the content field, use this function to make the fetch https://www.contentstack.com/docs/platforms/javascript-browser/api-reference/Entry.html#includeReference & https://www.contentstack.com/docs/platforms/javascript-browser/api-reference/Entry.html#includeReferenceContentTypeUid
- Understand how to implement A/B Testing for the global components across services.
- Remove Navigation from old global-components