Skip to content

Commit

Permalink
fix all components to use helmet directly, update example to use serv…
Browse files Browse the repository at this point in the history
…er side rendering, update readme
  • Loading branch information
Jim Skerritt committed Nov 27, 2018
1 parent b4c85d6 commit 9d92e35
Show file tree
Hide file tree
Showing 13 changed files with 197 additions and 984 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
[![CircleCI](https://circleci.com/gh/payscale/react-beret.svg?style=svg)](https://circleci.com/gh/payscale/react-beret)


# beret

Beret is a library for building HTML templates with React. It contains components for encapsulating the stuff that your page needs to work. Things like Google Tag Manager, web fonts, etc., are required, but are distractions from actually building your content. Componentizing them with beret helps you to get back to what matters and prevent plugins and assets from falling through the cracks.

Beret is intended to be used with server side rendering since many resources are required to be on the page before it is loaded. We also recommend using [React Helmet](https://github.com/nfl/react-helmet) to manage changes to the document head.
Beret is intended to be used with server-side rendering since many resources are required to be on the page before it is loaded. We use [React Helmet](https://github.com/nfl/react-helmet) to manage head elements.

## Example

To see an example of beret in action, check out the `examples` folder. It uses server-side rendering to create `index.html`. You can view the result in this repository or follow these steps to play with it for yourself:

1. Clone this repository.
1. Run `yarn install:peers` to install all dependencies and peer dependencies.
1. Run `yarn example`.
1. Open `examples/index.html` in your editor or your browser.

## Contributing

Expand Down
3 changes: 1 addition & 2 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
module.exports = {
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: ['react-hot-loader/babel']
presets: ['@babel/preset-env', '@babel/preset-react']
};
36 changes: 26 additions & 10 deletions examples/App.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
import React, { Fragment } from 'react';
import { hot } from 'react-hot-loader';
import Helmet from 'react-helmet';
import React from 'react';
import { Ads, Favicons, Gtm, WebFont } from '../src/lib';

const App = () => (
<Fragment>
<Helmet>
<title>Hello World</title>
</Helmet>
<div>Hello World</div>
</Fragment>
<div className="example-app" style={{ fontFamily: 'Roboto, sans-serif', fontSize: '32px' }}>
<Ads
slots={[{
networkCode: '123456',
name: 'Test_100x100',
width: 100,
height: 100,
elementId: 'testAd'
}]}
/>
<Favicons
favicons={[{
href: 'favicon-96x96.png',
sizes: '96x96',
type: 'image/png'
}]}
/>
<Gtm containerId="abc123" />
<WebFont
families={[{ fontName: 'Roboto', weights: [300, 400, 700, 900] }]}
/>
Inspect this page to see beret's rendered elements.
</div>
);

export default hot(module)(App);
export default App;
Binary file added examples/favicon-96x96.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 36 additions & 2 deletions examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,43 @@
<head>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>beret example</title>
<link data-react-helmet="true" rel="icon" href="favicon-96x96.png" sizes="96x96" type="image/png"/>
<script data-react-helmet="true" >var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
(function () {
var gads = document.createElement('script');
gads.async = true;
gads.type = 'text/javascript';
var useSSL = 'https:' == document.location.protocol;
gads.src = (useSSL ? 'https:' : 'http:') + '//www.googletagservices.com/tag/js/gpt.js';
var node = document.getElementsByTagName('script')[0];
node.parentNode.insertBefore(gads, node);
})();</script><script data-react-helmet="true" >googletag.cmd.push(function () {
if (hasAcceptedCookiePolicy()) {
googletag.defineSlot('/123456/Test_100x100', [100, 100], 'testAd').addService(googletag.pubads());
}
googletag.pubads().enableSingleRequest();
googletag.pubads().collapseEmptyDivs();
googletag.enableServices();
});</script><script data-react-helmet="true" >(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','abc123');</script><script data-react-helmet="true" >WebFontConfig = {
google: { families: ["Roboto:300,400,700,900"] }
};
(function() {
var wf = document.createElement('script');
wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
'://ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();</script>
</head>
<body>
<div id="app"></div>
<script src="/dist/example.js"></script>
<div class="example-app" style="font-family:Roboto, sans-serif;font-size:32px" data-reactroot="">Inspect this page to see beret&#x27;s rendered elements.</div>
</body>
</html>
36 changes: 32 additions & 4 deletions examples/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
import React from 'react';
import { render } from 'react-dom';
import App from './App';
require('@babel/register')({
presets: ['@babel/preset-env', '@babel/preset-react']
});

render(<App />, document.getElementById('app'));
const fs = require('fs');
const path = require('path');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const Helmet = require('react-helmet').default;
const App = require('./App').default;

console.log('rendering example server side react...');

const content = ReactDOMServer.renderToString(React.createElement(App));
const helmet = Helmet.renderStatic();

const html = `<!doctype html>
<html lang="en">
<head>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>beret example</title>
${helmet.link.toString()}
${helmet.script.toString()}
</head>
<body>
${content}
</body>
</html>`;

fs.writeFileSync(path.join(__dirname, 'index.html'), html);

console.log('done! open examples/index.html to view');
17 changes: 8 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
"main": "./dist/lib/index.js",
"scripts": {
"build": "webpack --mode=production",
"example": "node examples/index.js",
"install:peers": "node ./scripts/install-peers.js",
"lint:fix": "eslint --fix --config .eslintrc --format table src",
"lint": "eslint --config .eslintrc --format table src",
"start": "webpack-dev-server --hot --inline --config webpack.config.dev.js",
"test": "jest",
"test:watch": "jest --watch"
},
Expand All @@ -39,15 +39,16 @@
]
},
"peerDependencies": {
"prop-types": "^15.0.0",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-helmet": "^5.0.0"
"prop-types": ">=15.0.0",
"react": ">=16.0.0",
"react-dom": ">=16.0.0",
"react-helmet": ">=4.0.0"
},
"devDependencies": {
"@babel/core": "7.1.6",
"@babel/preset-env": "7.1.6",
"@babel/preset-react": "7.0.0",
"@babel/register": "^7.0.0",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "10.0.1",
"babel-jest": "23.6.0",
Expand All @@ -59,9 +60,7 @@
"eslint-plugin-react": "7.11.1",
"jest": "23.6.0",
"json-format": "1.0.1",
"react-hot-loader": "4.3.12",
"webpack": "4.26.0",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "3.1.10"
"webpack-cli": "^3.1.2"
}
}
}
25 changes: 11 additions & 14 deletions src/lib/Ads.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import Helmet from 'react-helmet';
import PropTypes from 'prop-types';

// Google Ads Marketing (DoubleClick)
Expand All @@ -11,10 +12,9 @@ const Ads = ({ slots }) => {
);

return (
<React.Fragment>
<script
dangerouslySetInnerHTML={{
__html: `var googletag = googletag || {};
<Helmet>
<script>
{`var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
(function () {
var gads = document.createElement('script');
Expand All @@ -24,22 +24,19 @@ googletag.cmd = googletag.cmd || [];
gads.src = (useSSL ? 'https:' : 'http:') + '//www.googletagservices.com/tag/js/gpt.js';
var node = document.getElementsByTagName('script')[0];
node.parentNode.insertBefore(gads, node);
})();`
}}
/>
<script
dangerouslySetInnerHTML={{
__html: `googletag.cmd.push(function () {
})();`}
</script>
<script>
{`googletag.cmd.push(function () {
if (hasAcceptedCookiePolicy()) {
${adStrings.join()}
}
googletag.pubads().enableSingleRequest();
googletag.pubads().collapseEmptyDivs();
googletag.enableServices();
});`
}}
/>
</React.Fragment>
});`}
</script>
</Helmet>
);
};

Expand Down
6 changes: 4 additions & 2 deletions src/lib/Favicons.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import Helmet from 'react-helmet';
import PropTypes from 'prop-types';

const Favicons = ({ favicons }) => {
Expand All @@ -7,16 +8,17 @@ const Favicons = ({ favicons }) => {
}

return (
<React.Fragment>
<Helmet>
{favicons.map(favicon => (
<link
key={favicon.href}
rel={favicon.rel || 'icon'}
href={favicon.href}
sizes={favicon.sizes}
type={favicon.type}
/>)
)}
</React.Fragment>
</Helmet>
);
};

Expand Down
13 changes: 7 additions & 6 deletions src/lib/Gtm.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import React from 'react';
import Helmet from 'react-helmet';
import PropTypes from 'prop-types';

// Google Tag Manager
const Gtm = ({ containerId }) => (
<script
dangerouslySetInnerHTML={{
__html: `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
<Helmet>
<script>
{`(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${containerId}');`
}}
/>
})(window,document,'script','dataLayer','${containerId}');`}
</script>
</Helmet>
);

Gtm.propTypes = {
Expand Down
13 changes: 7 additions & 6 deletions src/lib/Vwo.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import React from 'react';
import Helmet from 'react-helmet';
import PropTypes from 'prop-types';

// Visual Web Optimizer (VWO) (A/B testing)
const Vwo = ({ accountId, init }) => {
window.__vwo_init = init ? init : Vwo.defaultProps.init;
return (
<script
dangerouslySetInnerHTML={{
__html: `var _vwo_settings_timer;
<Helmet>
<script>
{`var _vwo_settings_timer;
var _vwo_code = (function () {
var account_id = '${accountId}',
settings_tolerance = 2000,
library_tolerance = 2500,
use_existing_jquery = false,
f = false, d = document; return { use_existing_jquery: function () { return use_existing_jquery; }, library_tolerance: function () { return library_tolerance; }, finish: function () { if (!f) { f = true; var a = d.getElementById('_vis_opt_path_hides'); if (a) a.parentNode.removeChild(a); } }, finished: function () { return f; }, load: function (a) { var b = d.createElement('script'); b.src = a; b.type = 'text/javascript'; b.innerText; b.onerror = function () { _vwo_code.finish(); }; d.getElementsByTagName('head')[0].appendChild(b); }, init: function () { settings_timer = setTimeout('_vwo_code.finish()', settings_tolerance); var a = d.createElement('style'), b = 'body{opacity:0 !important;filter:alpha(opacity=0) !important;background:none !important;}', h = d.getElementsByTagName('head')[0]; a.setAttribute('id', '_vis_opt_path_hides'); a.setAttribute('type', 'text/css'); if (a.styleSheet) a.styleSheet.cssText = b; else a.appendChild(d.createTextNode(b)); h.appendChild(a); this.load('//dev.visualwebsiteoptimizer.com/j.php?a=' + account_id + '&u=' + encodeURIComponent(d.URL) + '&r=' + Math.random()); return settings_timer; } };
}());
__vwo_init(_vwo_code);`
}}
/>
__vwo_init(_vwo_code);`}
</script>
</Helmet>
);
};

Expand Down
13 changes: 7 additions & 6 deletions src/lib/WebFont.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import Helmet from 'react-helmet';
import PropTypes from 'prop-types';

const WebFont = ({ families }) => {
Expand All @@ -9,9 +10,9 @@ const WebFont = ({ families }) => {
const familyStrings = families.map(family => `${family.fontName}:${family.weights.join(',')}`);

return (
<script
dangerouslySetInnerHTML={{
__html: `WebFontConfig = {
<Helmet>
<script>
{`WebFontConfig = {
google: { families: ${JSON.stringify(familyStrings)} }
};
(function() {
Expand All @@ -22,9 +23,9 @@ const WebFont = ({ families }) => {
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();`
}}
/>
})();`}
</script>
</Helmet>
);
};

Expand Down
Loading

0 comments on commit 9d92e35

Please sign in to comment.