head.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. "client";
  2. "use strict";
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.defaultHead = defaultHead;
  7. exports.default = void 0;
  8. var _extends = require("@swc/helpers/lib/_extends.js").default;
  9. var _interop_require_default = require("@swc/helpers/lib/_interop_require_default.js").default;
  10. var _interop_require_wildcard = require("@swc/helpers/lib/_interop_require_wildcard.js").default;
  11. var _react = _interop_require_wildcard(require("react"));
  12. var _sideEffect = _interop_require_default(require("./side-effect"));
  13. var _ampContext = require("./amp-context");
  14. var _headManagerContext = require("./head-manager-context");
  15. var _ampMode = require("./amp-mode");
  16. var _utils = require("./utils");
  17. 'client';
  18. function defaultHead(inAmpMode = false) {
  19. const head = [
  20. /*#__PURE__*/ _react.default.createElement("meta", {
  21. charSet: "utf-8"
  22. })
  23. ];
  24. if (!inAmpMode) {
  25. head.push(/*#__PURE__*/ _react.default.createElement("meta", {
  26. name: "viewport",
  27. content: "width=device-width"
  28. }));
  29. }
  30. return head;
  31. }
  32. function onlyReactElement(list, child) {
  33. // React children can be "string" or "number" in this case we ignore them for backwards compat
  34. if (typeof child === 'string' || typeof child === 'number') {
  35. return list;
  36. }
  37. // Adds support for React.Fragment
  38. if (child.type === _react.default.Fragment) {
  39. return list.concat(_react.default.Children.toArray(child.props.children).reduce((fragmentList, fragmentChild)=>{
  40. if (typeof fragmentChild === 'string' || typeof fragmentChild === 'number') {
  41. return fragmentList;
  42. }
  43. return fragmentList.concat(fragmentChild);
  44. }, []));
  45. }
  46. return list.concat(child);
  47. }
  48. const METATYPES = [
  49. 'name',
  50. 'httpEquiv',
  51. 'charSet',
  52. 'itemProp'
  53. ];
  54. /*
  55. returns a function for filtering head child elements
  56. which shouldn't be duplicated, like <title/>
  57. Also adds support for deduplicated `key` properties
  58. */ function unique() {
  59. const keys = new Set();
  60. const tags = new Set();
  61. const metaTypes = new Set();
  62. const metaCategories = {};
  63. return (h)=>{
  64. let isUnique = true;
  65. let hasKey = false;
  66. if (h.key && typeof h.key !== 'number' && h.key.indexOf('$') > 0) {
  67. hasKey = true;
  68. const key = h.key.slice(h.key.indexOf('$') + 1);
  69. if (keys.has(key)) {
  70. isUnique = false;
  71. } else {
  72. keys.add(key);
  73. }
  74. }
  75. // eslint-disable-next-line default-case
  76. switch(h.type){
  77. case 'title':
  78. case 'base':
  79. if (tags.has(h.type)) {
  80. isUnique = false;
  81. } else {
  82. tags.add(h.type);
  83. }
  84. break;
  85. case 'meta':
  86. for(let i = 0, len = METATYPES.length; i < len; i++){
  87. const metatype = METATYPES[i];
  88. if (!h.props.hasOwnProperty(metatype)) continue;
  89. if (metatype === 'charSet') {
  90. if (metaTypes.has(metatype)) {
  91. isUnique = false;
  92. } else {
  93. metaTypes.add(metatype);
  94. }
  95. } else {
  96. const category = h.props[metatype];
  97. const categories = metaCategories[metatype] || new Set();
  98. if ((metatype !== 'name' || !hasKey) && categories.has(category)) {
  99. isUnique = false;
  100. } else {
  101. categories.add(category);
  102. metaCategories[metatype] = categories;
  103. }
  104. }
  105. }
  106. break;
  107. }
  108. return isUnique;
  109. };
  110. }
  111. /**
  112. *
  113. * @param headChildrenElements List of children of <Head>
  114. */ function reduceComponents(headChildrenElements, props) {
  115. const { inAmpMode } = props;
  116. return headChildrenElements.reduce(onlyReactElement, []).reverse().concat(defaultHead(inAmpMode).reverse()).filter(unique()).reverse().map((c, i)=>{
  117. const key = c.key || i;
  118. if (process.env.NODE_ENV !== 'development' && process.env.__NEXT_OPTIMIZE_FONTS && !inAmpMode) {
  119. if (c.type === 'link' && c.props['href'] && // TODO(prateekbh@): Replace this with const from `constants` when the tree shaking works.
  120. [
  121. 'https://fonts.googleapis.com/css',
  122. 'https://use.typekit.net/'
  123. ].some((url)=>c.props['href'].startsWith(url))) {
  124. const newProps = _extends({}, c.props || {});
  125. newProps['data-href'] = newProps['href'];
  126. newProps['href'] = undefined;
  127. // Add this attribute to make it easy to identify optimized tags
  128. newProps['data-optimized-fonts'] = true;
  129. return /*#__PURE__*/ _react.default.cloneElement(c, newProps);
  130. }
  131. }
  132. if (process.env.NODE_ENV === 'development' && process.env.__NEXT_REACT_ROOT) {
  133. // omit JSON-LD structured data snippets from the warning
  134. if (c.type === 'script' && c.props['type'] !== 'application/ld+json') {
  135. const srcMessage = c.props['src'] ? `<script> tag with src="${c.props['src']}"` : `inline <script>`;
  136. (0, _utils).warnOnce(`Do not add <script> tags using next/head (see ${srcMessage}). Use next/script instead. \nSee more info here: https://nextjs.org/docs/messages/no-script-tags-in-head-component`);
  137. } else if (c.type === 'link' && c.props['rel'] === 'stylesheet') {
  138. (0, _utils).warnOnce(`Do not add stylesheets using next/head (see <link rel="stylesheet"> tag with href="${c.props['href']}"). Use Document instead. \nSee more info here: https://nextjs.org/docs/messages/no-stylesheets-in-head-component`);
  139. }
  140. }
  141. return /*#__PURE__*/ _react.default.cloneElement(c, {
  142. key
  143. });
  144. });
  145. }
  146. /**
  147. * This component injects elements to `<head>` of your page.
  148. * To avoid duplicated `tags` in `<head>` you can use the `key` property, which will make sure every tag is only rendered once.
  149. */ function Head({ children }) {
  150. const ampState = (0, _react).useContext(_ampContext.AmpStateContext);
  151. const headManager = (0, _react).useContext(_headManagerContext.HeadManagerContext);
  152. return /*#__PURE__*/ _react.default.createElement(_sideEffect.default, {
  153. reduceComponentsToState: reduceComponents,
  154. headManager: headManager,
  155. inAmpMode: (0, _ampMode).isInAmpMode(ampState)
  156. }, children);
  157. }
  158. var _default = Head;
  159. exports.default = _default;
  160. if ((typeof exports.default === 'function' || (typeof exports.default === 'object' && exports.default !== null)) && typeof exports.default.__esModule === 'undefined') {
  161. Object.defineProperty(exports.default, '__esModule', { value: true });
  162. Object.assign(exports.default, exports);
  163. module.exports = exports.default;
  164. }
  165. //# sourceMappingURL=head.js.map