Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
lib
node_modules
.idea/
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ This package is a fork of [React Helmet](https://github.com/nfl/react-helmet).

`react-helmet` relies on `react-side-effect`, which is not thread-safe. If you are doing anything asynchronous on the server, you need Helmet to encapsulate data on a per-request basis, this package does just that.

Supports React 16.6+, including React 17, 18, and 19.

## Usage

**New is 1.0.0:** No more default export! `import { Helmet } from 'react-helmet-async'`
Expand Down
3 changes: 1 addition & 2 deletions __tests__/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { ReactNode } from 'react';
import React, { StrictMode } from 'react';
import React, { StrictMode, act } from 'react';
import { createRoot } from 'react-dom/client';
import type { Root } from 'react-dom/client';
import { act } from 'react-dom/test-utils';

import Provider from '../src/Provider';

Expand Down
1 change: 1 addition & 0 deletions build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const shared = {
entryPoints: ['src/index.tsx'],
bundle: true,
external: Object.keys(dependencies).concat(Object.keys(peerDependencies)),
jsx: 'automatic' as const,
};

build({
Expand Down
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"@types/eslint": "8.44.8",
"@types/invariant": "2.2.37",
"@types/jsdom": "21.1.6",
"@types/react": "18.2.39",
"@types/react": "^19.0.1",
"@types/shallowequal": "1.1.5",
"@vitejs/plugin-react": "4.2.0",
"esbuild": "0.19.8",
Expand All @@ -37,16 +37,16 @@
"jsdom": "22.1.0",
"prettier": "3.1.0",
"raf": "3.4.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"rimraf": "5.0.5",
"tsx": "4.6.1",
"typescript": "5.2.2",
"vite": "4.5.0",
"vitest": "0.34.6"
},
"peerDependencies": {
"react": "^16.6.0 || ^17.0.0 || ^18.0.0"
"react": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"scripts": {
"clean": "rimraf lib",
Expand All @@ -57,6 +57,7 @@
"test-update": "yarn test -u",
"compile": "yarn run clean && NODE_ENV=production tsx build.ts && yarn types",
"prepare": "yarn compile && husky install",
"types": "tsc src/index.tsx --jsx react --declaration --esModuleInterop --allowJs --emitDeclarationOnly --outDir lib"
}
"types": "tsc src/index.tsx --jsx react-jsx --declaration --esModuleInterop --allowJs --emitDeclarationOnly --outDir lib"
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
4 changes: 2 additions & 2 deletions src/Provider.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { PropsWithChildren } from 'react';
import React, { Component } from 'react';
import { Component, createContext } from 'react';

import HelmetData, { isDocument } from './HelmetData';
import type { HelmetServerState } from './types';

const defaultValue = {};

export const Context = React.createContext(defaultValue);
export const Context = createContext(defaultValue);

interface ProviderProps {
context?: {
Expand Down
8 changes: 5 additions & 3 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { PropsWithChildren, ReactElement, ReactNode } from 'react';
import React, { Component } from 'react';
import { Component, Children } from 'react';
import fastCompare from 'react-fast-compare';
import invariant from 'invariant';

Expand Down Expand Up @@ -143,12 +143,14 @@ export class Helmet extends Component<PropsWithChildren<HelmetProps>> {
mapChildrenToProps(children: ReactNode, newProps: Props) {
let arrayTypeChildren = {};

React.Children.forEach(children as JSX.Element, (child: ReactElement) => {
Children.forEach(children as JSX.Element, (child: ReactElement) => {
if (!child || !child.props) {
return;
}

const { children: nestedChildren, ...childProps } = child.props;
// React 19 changed how props are accessed - need to handle both old and new behavior
const props = child.props as any;
const { children: nestedChildren, ...childProps } = props;
// convert React props to HTML attributes
const newChildProps = Object.keys(childProps).reduce((obj: Props, key) => {
obj[HTML_TAG_MAP[key] || key] = childProps[key];
Expand Down
6 changes: 3 additions & 3 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import { createElement } from 'react';

import {
HELMET_ATTRIBUTE,
Expand Down Expand Up @@ -93,7 +93,7 @@ const generateTitleAsReactComponent = (_type: string, title: string, attributes:
};
const props = convertElementAttributesToReactProps(attributes, initProps);

return [React.createElement(TAG_NAMES.TITLE, props, title)];
return [createElement(TAG_NAMES.TITLE, props, title)];
};

const generateTagsAsReactComponent = (type: string, tags: any[]) =>
Expand All @@ -118,7 +118,7 @@ const generateTagsAsReactComponent = (type: string, tags: any[]) =>
}
});

return React.createElement(type, mappedTag);
return createElement(type, mappedTag);
});

const getMethodsForTag = (type: string, tags: any, encode = true) => {
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"types": ["vitest/globals"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react",
"jsx": "react-jsx",
"module": "CommonJS",
"moduleResolution": "node",
"resolveJsonModule": true,
Expand Down
4 changes: 3 additions & 1 deletion vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ interface VitestConfigExport extends UserConfig {
}

export default defineConfig({
plugins: [react()],
plugins: [react({
jsxRuntime: 'automatic',
})],
test: {
globals: true,
environment: 'jsdom',
Expand Down
78 changes: 55 additions & 23 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1090,7 +1090,7 @@
dependencies:
"@types/react" "*"

"@types/react@*", "@types/react@18.2.39":
"@types/react@*":
version "18.2.39"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.39.tgz#744bee99e053ad61fe74eb8b897f3ab5b19a7e25"
integrity sha512-Oiw+ppED6IremMInLV4HXGbfbG6GyziY3kqAwJYOR0PNbkYDmLWQA3a95EhdSmamsvbkJN96ZNN+YD+fGjzSBA==
Expand All @@ -1099,6 +1099,13 @@
"@types/scheduler" "*"
csstype "^3.0.2"

"@types/react@^19.0.1":
version "19.2.7"
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.7.tgz#84e62c0f23e8e4e5ac2cadcea1ffeacccae7f62f"
integrity sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==
dependencies:
csstype "^3.2.2"

"@types/scheduler@*":
version "0.16.8"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff"
Expand Down Expand Up @@ -1762,6 +1769,11 @@ csstype@^3.0.2:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==

csstype@^3.2.2:
version "3.2.3"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a"
integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==

damerau-levenshtein@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
Expand Down Expand Up @@ -3432,7 +3444,7 @@ lodash@^4.17.15:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==

loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
loose-envify@^1.0.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
Expand Down Expand Up @@ -4008,13 +4020,12 @@ raf@3.4.1:
dependencies:
performance-now "^2.1.0"

react-dom@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
react-dom@^19.0.0:
version "19.2.3"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.2.3.tgz#f0b61d7e5c4a86773889fcc1853af3ed5f215b17"
integrity sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==
dependencies:
loose-envify "^1.1.0"
scheduler "^0.23.0"
scheduler "^0.27.0"

react-fast-compare@^3.2.2:
version "3.2.2"
Expand All @@ -4041,12 +4052,10 @@ react-refresh@^0.14.0:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==

react@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
dependencies:
loose-envify "^1.1.0"
react@^19.0.0:
version "19.2.3"
resolved "https://registry.yarnpkg.com/react/-/react-19.2.3.tgz#d83e5e8e7a258cf6b4fe28640515f99b87cd19b8"
integrity sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==

read-pkg-up@^7.0.1:
version "7.0.1"
Expand Down Expand Up @@ -4275,12 +4284,10 @@ saxes@^6.0.0:
dependencies:
xmlchars "^2.2.0"

scheduler@^0.23.0:
version "0.23.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
dependencies:
loose-envify "^1.1.0"
scheduler@^0.27.0:
version "0.27.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.27.0.tgz#0c4ef82d67d1e5c1e359e8fc76d3a87f045fe5bd"
integrity sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==

"semver@2 || 3 || 4 || 5":
version "5.7.2"
Expand Down Expand Up @@ -4424,7 +4431,16 @@ stop-iteration-iterator@^1.0.0:
dependencies:
internal-slot "^1.0.4"

"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"

string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
Expand Down Expand Up @@ -4491,7 +4507,14 @@ string_decoder@^1.1.1:
dependencies:
safe-buffer "~5.2.0"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"

strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
Expand Down Expand Up @@ -4997,7 +5020,16 @@ why-is-node-running@^2.2.2:
siginfo "^2.0.0"
stackback "0.0.2"

"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
Expand Down