react-meta-tags
Advanced tools
Comparing version 0.6.0 to 0.7.0
/** | ||
* react-meta-tags - 0.6.0 | ||
* react-meta-tags - 0.7.0 | ||
* Author : Sudhanshu Yadav | ||
@@ -295,3 +295,9 @@ * Copyright (c) 2016, 2018 to Sudhanshu Yadav, released under the MIT license. | ||
var uniqueIdentifiers = ['property', 'name', 'itemprop']; | ||
var uniqueIdentifiersI = ['property', 'name', 'itemprop']; | ||
/** | ||
Note: | ||
1. In server side we will add meta tags and title at last after fitering | ||
2. In client we will match and replace meta tagString | ||
3. For now we will not support link and other tags properly, they can be added but we will not check for uniqueness and will not decide placement | ||
**/ | ||
@@ -304,2 +310,3 @@ function filterOutMetaWithId(metas) { | ||
} | ||
function getDuplicateTitle() { | ||
@@ -320,3 +327,3 @@ return document.head.querySelectorAll('title'); | ||
return uniqueIdentifiers.reduce(function (duplicates, identifier) { | ||
return uniqueIdentifiersI.reduce(function (duplicates, identifier) { | ||
var identifierValue = meta.getAttribute(identifier); | ||
@@ -323,0 +330,0 @@ return identifierValue ? duplicates.concat(filterOutMetaWithId(head.querySelectorAll("[".concat(identifier, " = \"").concat(identifierValue, "\"]")))) : duplicates; |
/** | ||
* react-meta-tags - 0.6.0 | ||
* react-meta-tags - 0.7.0 | ||
* Author : Sudhanshu Yadav | ||
@@ -301,3 +301,9 @@ * Copyright (c) 2016, 2018 to Sudhanshu Yadav, released under the MIT license. | ||
var uniqueIdentifiers = ['property', 'name', 'itemprop']; | ||
var uniqueIdentifiersI = ['property', 'name', 'itemprop']; | ||
/** | ||
Note: | ||
1. In server side we will add meta tags and title at last after fitering | ||
2. In client we will match and replace meta tagString | ||
3. For now we will not support link and other tags properly, they can be added but we will not check for uniqueness and will not decide placement | ||
**/ | ||
@@ -310,2 +316,3 @@ function filterOutMetaWithId(metas) { | ||
} | ||
function getDuplicateTitle() { | ||
@@ -326,3 +333,3 @@ return document.head.querySelectorAll('title'); | ||
return uniqueIdentifiers.reduce(function (duplicates, identifier) { | ||
return uniqueIdentifiersI.reduce(function (duplicates, identifier) { | ||
var identifierValue = meta.getAttribute(identifier); | ||
@@ -329,0 +336,0 @@ return identifierValue ? duplicates.concat(filterOutMetaWithId(head.querySelectorAll("[".concat(identifier, " = \"").concat(identifierValue, "\"]")))) : duplicates; |
/** | ||
* react-meta-tags - 0.6.0 | ||
* react-meta-tags - 0.7.0 | ||
* Author : Sudhanshu Yadav | ||
@@ -4,0 +4,0 @@ * Copyright (c) 2016, 2018 to Sudhanshu Yadav, released under the MIT license. |
@@ -11,4 +11,50 @@ import express from 'express'; | ||
const app = express(); | ||
const app = express() | ||
function renderToString(metaTagsInstance, reactString) { | ||
const meta = metaTagsInstance.renderToString(); | ||
const html = ` | ||
<html lang="en"> | ||
<head> | ||
<meta charSet="utf-8"/> | ||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | ||
<meta http-equiv="x-ua-compatible" content="ie=edge"> | ||
${meta} | ||
<!-- Bootstrap CSS --> | ||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.4/css/bootstrap.min.css" integrity="2hfp1SzUoho7/TsGGGDaFdsuuDL0LX2hnUp6VkX3CUQ2K4K+xjboZdsXyp4oUHZj" crossorigin="anonymous"> | ||
</head> | ||
<body> | ||
<div id="app">${reactString}</div> | ||
<script src="http://localhost:9010/bundle.js"></script> | ||
</body> | ||
</html> | ||
`; | ||
return html; | ||
} | ||
function renderToStringFromJSx(metaTagsInstance, reactString) { | ||
const tags = metaTagsInstance.getTags(); | ||
const wholeHtml = ( | ||
<html lang="en"> | ||
<head> | ||
<meta charSet="utf-8"/> | ||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> | ||
<meta httpEquiv="x-ua-compatible" content="ie=edge" /> | ||
{tags} | ||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.4/css/bootstrap.min.css" integrity="2hfp1SzUoho7/TsGGGDaFdsuuDL0LX2hnUp6VkX3CUQ2K4K+xjboZdsXyp4oUHZj" crossOrigin="anonymous" /> | ||
</head> | ||
<body> | ||
<div id="app" dangerouslySetInnerHTML={{__html: reactString}} /> | ||
<script src="http://localhost:9010/bundle.js"></script> | ||
</body> | ||
</html> | ||
); | ||
return ReactDomServer.renderToString(wholeHtml) | ||
} | ||
app.use((req, res) => { | ||
@@ -23,42 +69,23 @@ match({ | ||
} else if (renderProps) { | ||
let reactString; | ||
let reactString; | ||
const metaTagsInstance = MetaTagsServer(); | ||
const metaTagsInstance = MetaTagsServer(); | ||
try{ | ||
reactString = ReactDomServer.renderToString( | ||
<MetaTagsContext extract = {metaTagsInstance.extract}> | ||
<RouterContext {...renderProps}/> | ||
</MetaTagsContext> | ||
); | ||
} | ||
catch(e){ | ||
console.log(e); | ||
res.status(500).send(e.stack); | ||
return; | ||
} | ||
try{ | ||
reactString = ReactDomServer.renderToString( | ||
<MetaTagsContext extract = {metaTagsInstance.extract}> | ||
<RouterContext {...renderProps}/> | ||
</MetaTagsContext> | ||
); | ||
} | ||
catch(e){ | ||
console.log(e); | ||
res.status(500).send(e.stack); | ||
return; | ||
} | ||
//const meta = metaTagsInstance.renderToString(); | ||
const meta = ''; | ||
//const html = renderToString(metaTagsInstance, reactString); | ||
const html = renderToStringFromJSx(metaTagsInstance, reactString); | ||
const template = ` | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta charSet="utf-8"/> | ||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | ||
<meta http-equiv="x-ua-compatible" content="ie=edge"> | ||
${meta} | ||
<!-- Bootstrap CSS --> | ||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.4/css/bootstrap.min.css" integrity="2hfp1SzUoho7/TsGGGDaFdsuuDL0LX2hnUp6VkX3CUQ2K4K+xjboZdsXyp4oUHZj" crossorigin="anonymous"> | ||
</head> | ||
<body> | ||
<div id="app">${reactString}</div> | ||
<script src="http://localhost:9000/bundle.js"></script> | ||
</body> | ||
`; | ||
res.status(200).send(template) | ||
res.status(200).send(html); | ||
} else { | ||
@@ -71,4 +98,4 @@ console.log('redirected'); | ||
app.listen(8070, function() { | ||
app.listen(8070, () => { | ||
console.log('Listening on 8070'); | ||
}) |
@@ -20,8 +20,14 @@ "use strict"; | ||
extract: function extract(elms) { | ||
headElms.push(elms); | ||
if (!(elms instanceof Array)) { | ||
elms = [elms]; | ||
} | ||
headElms = headElms.concat(elms); | ||
}, | ||
renderToString: function renderToString() { | ||
var filteredElms = (0, _utils.filterAndArrangeTags)(headElms); | ||
var headComponent = _react.default.createElement("div", { | ||
className: "react-head-temp" | ||
}, headElms); | ||
}, filteredElms); | ||
@@ -34,15 +40,6 @@ var componentStr = _server.default.renderToStaticMarkup(headComponent); //remove wrapper div from string | ||
}); | ||
var _extractMetaAndTitle = (0, _utils.extractMetaAndTitle)(componentStr), | ||
_extractMetaAndTitle$ = _extractMetaAndTitle.title, | ||
title = _extractMetaAndTitle$ === void 0 ? '' : _extractMetaAndTitle$, | ||
metas = _extractMetaAndTitle.metas, | ||
_extractMetaAndTitle$2 = _extractMetaAndTitle.canonicalLink, | ||
canonicalLink = _extractMetaAndTitle$2 === void 0 ? '' : _extractMetaAndTitle$2, | ||
rest = _extractMetaAndTitle.rest; | ||
var metasStr = (0, _utils.removeDuplicateMetas)(metas).map(function (meta) { | ||
return meta._tagString; | ||
}).join(''); | ||
return "\n ".concat(title, "\n ").concat(metasStr, "\n ").concat(canonicalLink, "\n ").concat(rest, "\n "); | ||
return componentStr; | ||
}, | ||
getTags: function getTags() { | ||
return (0, _utils.filterAndArrangeTags)(headElms); | ||
} | ||
@@ -49,0 +46,0 @@ }; |
@@ -6,4 +6,3 @@ "use strict"; | ||
}); | ||
exports.extractMetaAndTitle = extractMetaAndTitle; | ||
exports.removeDuplicateMetas = removeDuplicateMetas; | ||
exports.filterAndArrangeTags = filterAndArrangeTags; | ||
exports.getDuplicateTitle = getDuplicateTitle; | ||
@@ -16,11 +15,14 @@ exports.getDuplicateCanonical = getDuplicateCanonical; | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } | ||
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } | ||
var metaRegex = /<meta[^<>]*?=(['"].*?['"]|[^<>]*?)*?\/?>/g; | ||
var canonicalLinkRegex = /<link[^<>]*?rel=['"]canonical['"].*?(\/>|<\/link>)/g; | ||
var titleRegex = /<title[^<>]*?>(.*?)<\/title>/g; | ||
var attributesRegex = /(\S*?)=("(.*?)"|'(.*?)'|([^<>\s]*))/g; | ||
var uniqueIdentifiers = ['property', 'name', 'itemprop']; | ||
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } | ||
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } | ||
var camelCaseProps = ['itemProp']; | ||
var uniqueIdentifiersI = ['property', 'name', 'itemprop']; | ||
var uniqueIdentifiers = uniqueIdentifiersI.concat(camelCaseProps); //case sensitive props is defined in case anyone defined the lowercase prop | ||
var uniqueIdentifiersAll = uniqueIdentifiers.concat(['id']); | ||
@@ -34,15 +36,2 @@ /** | ||
function getAttributes(tagString) { | ||
var attr = {}; | ||
if (!tagString) return attr; | ||
var match = attributesRegex.exec(tagString); | ||
while (match !== null) { | ||
attr[match[1].toLowerCase()] = match[3] || match[4] || match[5]; | ||
match = attributesRegex.exec(tagString); | ||
} | ||
return attr; | ||
} | ||
function filterOutMetaWithId(metas) { | ||
@@ -55,28 +44,22 @@ metas = Array.prototype.slice.call(metas || []); | ||
function extractMetaAndTitle(domString) { | ||
var title, canonicalLink; | ||
var metas = []; //extract title, only take the last title, remove title from the string | ||
function filterAndArrangeTags(headElms) { | ||
var title = null, | ||
canonicalLink = null; | ||
var metas = [], | ||
rest = []; | ||
headElms.forEach(function (elm) { | ||
var type = elm.type, | ||
props = elm.props; | ||
domString = domString.replace(titleRegex, function (titleStr) { | ||
title = titleStr; | ||
return ''; | ||
}); //extract canonical | ||
domString = domString.replace(canonicalLinkRegex, function (canonicalLinkStr) { | ||
canonicalLink = canonicalLinkStr; | ||
return ''; | ||
}); //extract metas | ||
domString = domString.replace(metaRegex, function (_tagString) { | ||
metas.push(_objectSpread({}, getAttributes(_tagString), { | ||
_tagString: _tagString | ||
})); | ||
return ''; | ||
if (type === 'title') { | ||
title = elm; | ||
} else if (type === 'link' && props.rel === 'canonical') { | ||
canonicalLink = elm; | ||
} else if (type === 'meta') { | ||
metas.push(elm); | ||
} else { | ||
rest.push(elm); | ||
} | ||
}); | ||
return { | ||
title: title, | ||
metas: metas, | ||
canonicalLink: canonicalLink, | ||
rest: domString | ||
}; | ||
return [title].concat(_toConsumableArray(removeDuplicateMetas(metas)), [canonicalLink], rest); | ||
} | ||
@@ -94,3 +77,3 @@ | ||
var meta = metas[i]; | ||
var id = meta.id; | ||
var id = meta.props.id; | ||
var addMeta = false; //if has id and element with id is not present than always add meta | ||
@@ -102,4 +85,5 @@ | ||
addMeta = uniqueIdentifiers.filter(function (identifier) { | ||
var existing = addedMeta[identifier][meta[identifier]]; | ||
return existing && !existing.id; | ||
var identifierValue = meta.props[identifier]; | ||
var existing = addedMeta[identifier][identifierValue]; | ||
return existing && !existing.props.id; | ||
}).length === 0; | ||
@@ -112,3 +96,3 @@ } | ||
uniqueIdentifiersAll.forEach(function (identifier) { | ||
var identifierValue = meta[identifier]; | ||
var identifierValue = meta.props[identifier]; | ||
if (identifierValue) addedMeta[identifier][identifierValue] = meta; | ||
@@ -143,3 +127,3 @@ }); | ||
return uniqueIdentifiers.reduce(function (duplicates, identifier) { | ||
return uniqueIdentifiersI.reduce(function (duplicates, identifier) { | ||
var identifierValue = meta.getAttribute(identifier); | ||
@@ -146,0 +130,0 @@ return identifierValue ? duplicates.concat(filterOutMetaWithId(head.querySelectorAll("[".concat(identifier, " = \"").concat(identifierValue, "\"]")))) : duplicates; |
{ | ||
"name": "react-meta-tags", | ||
"description": "Handle document meta/head tags in isomorphic react with ease.", | ||
"version": "0.6.0", | ||
"version": "0.7.0", | ||
"main": "lib/index.js", | ||
@@ -28,3 +28,3 @@ "author": "Sudhanshu Yadav", | ||
"scripts": { | ||
"start": "cross-env nodemon example.js | npm run start-dev", | ||
"start": "cross-env npm run start-dev | nodemon example.js", | ||
"start-dev": "cross-env webpack-dev-server --content-base example/ --config webpack.dev.config.js --watch-poll --progress --inline --hot", | ||
@@ -31,0 +31,0 @@ "bundle": "cross-env NODE_ENV=production rollup -c rollup.config.js && npm run compile", |
@@ -71,33 +71,33 @@ # react-meta-tags | ||
app.use((req, res) => { | ||
//make sure you get a new metatags instance for each request | ||
const metaTagsInstance = MetaTagsServer(); | ||
//make sure you get a new metatags instance for each request | ||
const metaTagsInstance = MetaTagsServer(); | ||
//react router match | ||
match({ | ||
routes, location: req.url | ||
}, (error, redirectLocation, renderProps) => { | ||
let reactString; | ||
//react router match | ||
match({ | ||
routes, location: req.url | ||
}, (error, redirectLocation, renderProps) => { | ||
let reactString; | ||
try{ | ||
reactString = ReactDomServer.renderToString( | ||
<Provider store={store}> {/*** If you are using redux ***/} | ||
{/* You have to pass extract method through MetaTagsContext so it can catch meta tags */} | ||
<MetaTagsContext extract = {metaTagsInstance.extract}> | ||
<RouterContext {...renderProps}/> | ||
</MetaTagsContext> | ||
</Provider> | ||
); | ||
} | ||
catch(e){ | ||
res.status(500).send(e.stack); | ||
return; | ||
} | ||
try{ | ||
reactString = ReactDomServer.renderToString( | ||
<Provider store={store}> {/*** If you are using redux ***/} | ||
{/* You have to pass extract method through MetaTagsContext so it can catch meta tags */} | ||
<MetaTagsContext extract = {metaTagsInstance.extract}> | ||
<RouterContext {...renderProps}/> | ||
</MetaTagsContext> | ||
</Provider> | ||
); | ||
} | ||
catch(e){ | ||
res.status(500).send(e.stack); | ||
return; | ||
} | ||
//get all title and metatags as string | ||
const meta = metaTagsInstance.renderToString(); | ||
//get all title and metatags as string | ||
const meta = metaTagsInstance.renderToString(); | ||
//append metatag string to your template | ||
const template = (` | ||
<!doctype html> | ||
<html lang="en-us"> | ||
//append metatag string to your layout | ||
const htmlStr = (` | ||
<!doctype html> | ||
<html lang="en-us"> | ||
<head> | ||
@@ -111,7 +111,8 @@ <meta charSet="utf-8"/> | ||
</div> | ||
</body> | ||
`); | ||
</body> | ||
</html> | ||
`); | ||
res.status(200).send(template); | ||
}); | ||
res.status(200).send(layout); | ||
}); | ||
}); | ||
@@ -128,2 +129,28 @@ ``` | ||
#### JSX Layout | ||
You might also be using React to define your layout, in which case you can use `getTags` method from `metaTagsInstance`. The layout part of above server side example will look like this. | ||
```jsx | ||
//get all title and metatags as React elements | ||
const metaTags = metaTagsInstance.getTags(); | ||
//append metatag string to your layout | ||
const layout = ( | ||
<html lang="en-us"> | ||
<head> | ||
<meta charSet="utf-8"/> | ||
{metaTags} | ||
</head> | ||
<body> | ||
<div id="app" dangerouslySetInnerHTML={{__html: reactString}} /> | ||
</body> | ||
</html> | ||
); | ||
const htmlStr = ReactDomServer.renderToString(layout); | ||
res.status(200).send(htmlStr); | ||
``` | ||
## Meta Tag Uniqueness | ||
@@ -130,0 +157,0 @@ - The module uniquely identifies meta tag by id / property / name / itemProp attribute. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
270549
1411
157
0