From ada346afd901336df12f09efb103ee95c579c9ed Mon Sep 17 00:00:00 2001 From: Sudhanshu Yadav <sudhanshuyadav2@gmail.com> Date: Wed, 25 Nov 2020 15:36:47 +0530 Subject: [PATCH] - Support new context API #37 - Bump react dependency to 16. #37 - Uniquely identify any elements inside MetaTags by id. Fix for #35 --- .eslintrc | 1 + .prettierrc | 13 ++++++ examples/shared/page1/page1.js | 14 ++++-- examples/shared/page2/page2.js | 16 +++++-- package.json | 4 +- src/meta_tags.js | 29 ++++++++---- src/utils.js | 83 +++++++++++++++++----------------- yarn.lock | 17 +++++++ 8 files changed, 118 insertions(+), 59 deletions(-) create mode 100644 .prettierrc diff --git a/.eslintrc b/.eslintrc index c565675..4afe180 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,6 +3,7 @@ "browser": true, "es6": true }, + "extends": ["prettier"], "plugins": [ "react", //on react based application "import", diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..5a80b5f --- /dev/null +++ b/.prettierrc @@ -0,0 +1,13 @@ +{ + "printWidth": 100, + "arrowParens": "always", + "singleQuote": true, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "bracketSpacing": true, + "jsxBracketSameLine": false, + "requirePragma": false, + "proseWrap": "preserve", + "trailingComma": "all" +} \ No newline at end of file diff --git a/examples/shared/page1/page1.js b/examples/shared/page1/page1.js index c0f9eb3..1f1b9bb 100644 --- a/examples/shared/page1/page1.js +++ b/examples/shared/page1/page1.js @@ -8,17 +8,25 @@ class Page1 extends React.Component { <MetaTags> <title>React Meta Tags | Page1</title> <link rel="canonical" href="/page1" /> - <meta name="description" content="React meta tags handles document meta/head tags in isomorphic react with ease." /> + <meta + name="description" + content="React meta tags handles document meta/head tags in isomorphic react with ease." + /> <meta property="og:title" content="MyApp-Page1" /> <meta itemProp="test" content="Page1" /> </MetaTags> <div> <p> - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor + incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud + exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure + dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. + Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt + mollit anim id est laborum. </p> </div> </div> - ) + ); } } diff --git a/examples/shared/page2/page2.js b/examples/shared/page2/page2.js index 12f3f1f..43f0a24 100644 --- a/examples/shared/page2/page2.js +++ b/examples/shared/page2/page2.js @@ -7,18 +7,28 @@ class Page2 extends React.Component { <div className="page1"> <MetaTags> <title>React Meta Tags | Page2</title> - <link rel="canonical" href="/page2" ></link> + <link rel="canonical" href="/page2"></link> <meta name="description" content="This is page 2 description." /> <meta property="og:title" content="MyApp-page2" /> <meta itemProp="test" content="Page2" /> </MetaTags> <div> <p> - Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? + Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque + laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi + architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas + sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione + voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit + amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut + labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis + nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi + consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam + nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla + pariatur? </p> </div> </div> - ) + ); } } diff --git a/package.json b/package.json index 05fb1d3..cd5861d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-meta-tags", "description": "Handle document meta/head tags in isomorphic react with ease.", - "version": "0.7.4", + "version": "1.0.0", "main": "lib/index.js", "author": "Sudhanshu Yadav", "license": "MIT", @@ -44,10 +44,12 @@ "classnames": "^2.2.3", "cross-env": "^3.1.4", "eslint": "^5.6.0", + "eslint-config-prettier": "^6.15.0", "eslint-loader": "^2.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-react": "^7.11.1", "nodemon": "^1.12.1", + "prettier": "^2.2.0", "react": "^16.6.0", "react-dom": "^16.6.0", "react-router": "3", diff --git a/src/meta_tags.js b/src/meta_tags.js index 3142000..618a5c6 100644 --- a/src/meta_tags.js +++ b/src/meta_tags.js @@ -1,9 +1,15 @@ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import ReactDOM from 'react-dom'; -import {getDuplicateTitle, getDuplicateCanonical, getDuplicateMeta, appendChild, removeChild} from './utils'; +import { + getDuplicateTitle, + getDuplicateCanonical, + getDuplicateMeta, + getDuplicateElementById, + appendChild, + removeChild, +} from './utils'; import { MetaContext } from './meta_tags_context'; - /** An wrapper component to wrap element which need to shifted to head **/ class MetaTags extends Component { static contextType = MetaContext; @@ -23,10 +29,10 @@ class MetaTags extends Component { } } extractChildren() { - const {extract} = this.context; - const {children} = this.props; + const { extract } = this.context; + const { children } = this.props; - if(!children) { + if (!children) { return; } @@ -35,8 +41,8 @@ class MetaTags extends Component { } } handleChildrens() { - const {children} = this.props; - if (this.context.extract || !children){ + const { children } = this.props; + if (this.context.extract || !children) { return; } @@ -46,7 +52,7 @@ class MetaTags extends Component { const childStr = this.temporaryElement.innerHTML; //if html is not changed return - if(this.lastChildStr === childStr){ + if (this.lastChildStr === childStr) { return; } @@ -78,6 +84,10 @@ class MetaTags extends Component { if (tag === 'title') { const title = getDuplicateTitle(); if (title) removeChild(head, title); + } else if (child.id) { + // if the element has id defined remove the existing element with that id + const elm = getDuplicateElementById(child); + if (elm) removeChild(head, elm); } else if (tag === 'meta') { const meta = getDuplicateMeta(child); if (meta) removeChild(head, meta); @@ -89,7 +99,6 @@ class MetaTags extends Component { appendChild(document.head, childNodes); }); - } render() { this.extractChildren(); diff --git a/src/utils.js b/src/utils.js index 4ec0148..5f626b6 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,5 +1,5 @@ -const camelCaseProps = ['itemProp']; -const uniqueIdentifiersI = ['property', 'name', 'itemprop']; +const camelCaseProps = ['itemProp']; +const uniqueIdentifiersI = ['property', 'name', 'itemprop']; const uniqueIdentifiers = uniqueIdentifiersI.concat(camelCaseProps); //case sensitive props is defined in case anyone defined the lowercase prop const uniqueIdentifiersAll = uniqueIdentifiers.concat(['id']); @@ -12,41 +12,41 @@ const uniqueIdentifiersAll = uniqueIdentifiers.concat(['id']); function filterOutMetaWithId(metas) { metas = Array.prototype.slice.call(metas || []); - return metas.filter(meta => !meta.id); + return metas.filter((meta) => !meta.id); } - export function filterAndArrangeTags(headElms) { - let title = null, canonicalLink = null; - const metas = [], rest = []; - - headElms.forEach((elm) => { - const { type, props } = elm; - 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); - } - }); + let title = null; + let canonicalLink = null; + const metas = []; + const rest = []; + + headElms.forEach((elm) => { + const { type, props } = elm; + 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, ...removeDuplicateMetas(metas), canonicalLink, ...rest]; + return [title, ...removeDuplicateMetas(metas), canonicalLink, ...rest]; } - function removeDuplicateMetas(metas) { const addedMeta = {}; - + //initialize all the identifiers with empty array uniqueIdentifiersAll.forEach((identifier) => { addedMeta[identifier] = []; }); const filteredMetas = []; - for (let i = metas.length - 1; i >=0 ; i--) { + for (let i = metas.length - 1; i >= 0; i--) { const meta = metas[i]; const { id } = meta.props; @@ -56,22 +56,23 @@ function removeDuplicateMetas(metas) { if (id) { addMeta = !addedMeta.id[id]; - //for any other unique identifier check if meta already available with same identifier which doesn't have id + //for any other unique identifier check if meta already available with same identifier which doesn't have id } else { - addMeta = uniqueIdentifiers.filter((identifier) => { - const identifierValue = meta.props[identifier]; - const existing = addedMeta[identifier][identifierValue]; - return existing && !existing.props.id; - }).length === 0; + addMeta = + uniqueIdentifiers.filter((identifier) => { + const identifierValue = meta.props[identifier]; + const existing = addedMeta[identifier][identifierValue]; + return existing && !existing.props.id; + }).length === 0; } if (addMeta) { filteredMetas.unshift(meta); - //add meta as added + //add meta as added uniqueIdentifiersAll.forEach((identifier) => { const identifierValue = meta.props[identifier]; - if (identifierValue) addedMeta[identifier][identifierValue] = meta; + if (identifierValue) addedMeta[identifier][identifierValue] = meta; }); } } @@ -87,28 +88,26 @@ export function getDuplicateCanonical() { return document.head.querySelectorAll('link[rel="canonical"]'); } +export function getDuplicateElementById({ id }) { + return id && document.head.querySelector(`#${id}`); +} + export function getDuplicateMeta(meta) { const head = document.head; - const { id } = meta; - - //if has id and element with id is not present than return the element - if (id) { - return id && head.querySelector(`#${id}`); - } //for any other unique identifier check if metas already available with same identifier which doesn't have id return uniqueIdentifiersI.reduce((duplicates, identifier) => { const identifierValue = meta.getAttribute(identifier); - return (identifierValue ? - duplicates.concat(filterOutMetaWithId(head.querySelectorAll(`[${identifier} = "${identifierValue}"]`))) : - duplicates); + return identifierValue + ? duplicates.concat( + filterOutMetaWithId(head.querySelectorAll(`[${identifier} = "${identifierValue}"]`)), + ) + : duplicates; }, []); } - //function to append childrens on a parent export function appendChild(parent, childrens) { - if (childrens.length === undefined) childrens = [childrens]; const docFrag = document.createDocumentFragment(); diff --git a/yarn.lock b/yarn.lock index 494c43f..d3a8de8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1910,6 +1910,13 @@ escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" +eslint-config-prettier@^6.15.0: + version "6.15.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz#7f93f6cb7d45a92f1537a70ecc06366e1ac6fed9" + integrity sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw== + dependencies: + get-stdin "^6.0.0" + eslint-import-resolver-node@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" @@ -2460,6 +2467,11 @@ get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" +get-stdin@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" + integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== + get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -4120,6 +4132,11 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" +prettier@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.0.tgz#8a03c7777883b29b37fb2c4348c66a78e980418b" + integrity sha512-yYerpkvseM4iKD/BXLYUkQV5aKt4tQPqaGW6EsZjzyu0r7sVZZNPJW4Y8MyKmicp6t42XUPcBVA+H6sB3gqndw== + private@^0.1.6: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" -- GitLab