From f1eae84e25e0446a41138400f504e7dd847370e2 Mon Sep 17 00:00:00 2001 From: vjrj Date: Sat, 18 Jul 2026 06:14:14 +0200 Subject: [PATCH] deps: react-helmet -> react-helmet-async 2 react-helmet 5 is unmaintained and breaks under React 18 StrictMode. Same API in the 15 pages; HelmetProvider wraps in the client entry. Browser-verified: per-page titles, meta description and hreflang alternates all inject. REST smoke byte-identical. --- UPGRADE.md | 1 + imports/startup/client/index.js | 7 +- imports/ui/layouts/App/App.js | 2 +- imports/ui/pages/Fires/Fires.js | 2 +- imports/ui/pages/FiresMap/FiresMap.js | 2 +- imports/ui/pages/Index/Index.js | 2 +- imports/ui/pages/Login/Login.js | 2 +- imports/ui/pages/Logout/Logout.js | 2 +- imports/ui/pages/NotFound/NotFound.js | 2 +- imports/ui/pages/Page/Page.js | 2 +- .../pages/RecoverPassword/RecoverPassword.js | 2 +- .../ui/pages/ResetPassword/ResetPassword.js | 2 +- imports/ui/pages/Signup/Signup.js | 2 +- imports/ui/pages/Status/Status.js | 2 +- .../ui/pages/Subscriptions/Subscriptions.js | 2 +- .../pages/Subscriptions/SubscriptionsMap.js | 2 +- imports/ui/pages/VerifyEmail/VerifyEmail.js | 2 +- package-lock.json | 100 +++++------------- package.json | 2 +- 19 files changed, 47 insertions(+), 93 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 6d6f6d0..c2a9fe1 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -315,6 +315,7 @@ MONGO_CONTAINER=tcef-mongo7 MONGO_SHELL=mongosh MONGO_PORT=27019 ./smoke/smoke.s | maximum:server-transform, meteorhacks:zones, less, markdown, test stack | — | — | ✅ removed (dead/unused) | | fourseven:scss | 4.5.4 | 4.14.1 | ✅ node-12 compatible | | node-gcm | 1.0.2 | — | ✅ removed (dead API, moved to microservice) | +| react-helmet | 5.2.0 | react-helmet-async 2.0.5 | ✅ done — react-helmet is unmaintained and misbehaves under React 18 StrictMode. Drop-in: same `` children API across the 15 pages; `` wraps `` in `imports/startup/client/index.js`. Verified in browser: per-page titles, meta description and hreflang alternates injected (`data-rh`). Note: head updates are rAF-deferred (like react-helmet), so hidden/background tabs don't flush — irrelevant for real users. | | reactstrap | 5.0.0-alpha.3 | — | ✅ removed — zero imports in the codebase (react-bootstrap covers all UI). | | react-leaflet-sidebarv2 | 0.5.1 | — | ✅ removed — never imported. | | react-router-hash-link | 1.1.1 | — | ✅ removed — only a commented-out import in Index.js. | diff --git a/imports/startup/client/index.js b/imports/startup/client/index.js index 4d68742..f5dd1e2 100644 --- a/imports/startup/client/index.js +++ b/imports/startup/client/index.js @@ -1,6 +1,7 @@ /* global */ import React from 'react'; import { createRoot } from 'react-dom/client'; +import { HelmetProvider } from 'react-helmet-async'; import { Meteor } from 'meteor/meteor'; import '/imports/startup/client/modernizr'; import App from '../../ui/layouts/App/App'; @@ -15,5 +16,9 @@ else { Modernizr.on('webp', (result) => { if (Meteor.isDevelopment) console.log(`webp ${result ? '' : 'not '}supported`); }); - Meteor.startup(() => createRoot(document.getElementById('react-root')).render()); + Meteor.startup(() => createRoot(document.getElementById('react-root')).render( + + + + )); } diff --git a/imports/ui/layouts/App/App.js b/imports/ui/layouts/App/App.js index 11f7d74..7ab58c0 100644 --- a/imports/ui/layouts/App/App.js +++ b/imports/ui/layouts/App/App.js @@ -6,7 +6,7 @@ import PropTypes from 'prop-types'; import { Router, Switch, Route } from 'react-router-dom'; import { Grid } from 'react-bootstrap'; import { I18nextProvider } from 'react-i18next'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; import { Meteor } from 'meteor/meteor'; import { withTracker } from 'meteor/react-meteor-data'; // https://github.com/gadicc/meteor-blaze-react-component/ diff --git a/imports/ui/pages/Fires/Fires.js b/imports/ui/pages/Fires/Fires.js index 17873e2..676de6b 100644 --- a/imports/ui/pages/Fires/Fires.js +++ b/imports/ui/pages/Fires/Fires.js @@ -9,7 +9,7 @@ import { translate, Trans } from 'react-i18next'; import { Row, Col, Alert, FormGroup } from 'react-bootstrap'; import { Meteor } from 'meteor/meteor'; import { Bert } from 'meteor/themeteorchef:bert'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; import { Map, GeoJSON } from 'react-leaflet'; import { rectangleAround } from 'map-common-utils'; import DefMapLayers from '/imports/ui/components/Maps/DefMapLayers'; diff --git a/imports/ui/pages/FiresMap/FiresMap.js b/imports/ui/pages/FiresMap/FiresMap.js index 34ad09f..7904fb5 100644 --- a/imports/ui/pages/FiresMap/FiresMap.js +++ b/imports/ui/pages/FiresMap/FiresMap.js @@ -9,7 +9,7 @@ import { Meteor } from 'meteor/meteor'; import { ReactiveVar } from 'meteor/reactive-var'; import { withTracker } from 'meteor/react-meteor-data'; import { Tracker } from 'meteor/tracker'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; import { Trans, translate } from 'react-i18next'; import { Map } from 'react-leaflet'; import Control from 'react-leaflet-control'; diff --git a/imports/ui/pages/Index/Index.js b/imports/ui/pages/Index/Index.js index 9ac6eab..e71bd1f 100644 --- a/imports/ui/pages/Index/Index.js +++ b/imports/ui/pages/Index/Index.js @@ -5,7 +5,7 @@ import 'simple-line-icons/css/simple-line-icons.css'; import React, { Component } from 'react'; import { translate, Trans } from 'react-i18next'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; import PropTypes from 'prop-types'; // import { Link } from 'react-router-dom'; // https://www.npmjs.com/package/react-resize-detector diff --git a/imports/ui/pages/Login/Login.js b/imports/ui/pages/Login/Login.js index 0ff48f8..3d1d449 100644 --- a/imports/ui/pages/Login/Login.js +++ b/imports/ui/pages/Login/Login.js @@ -6,7 +6,7 @@ import { Row, FormGroup, ControlLabel, Button } from 'react-bootstrap'; import { Link } from 'react-router-dom'; import { Meteor } from 'meteor/meteor'; import { Bert } from 'meteor/themeteorchef:bert'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; import { translate } from 'react-i18next'; import { T9n } from 'meteor-accounts-t9n'; import { testId } from '/imports/ui/components/Utils/TestUtils'; diff --git a/imports/ui/pages/Logout/Logout.js b/imports/ui/pages/Logout/Logout.js index 87293d8..8ae84e9 100644 --- a/imports/ui/pages/Logout/Logout.js +++ b/imports/ui/pages/Logout/Logout.js @@ -2,7 +2,7 @@ import React from 'react'; import { Meteor } from 'meteor/meteor'; import Icon from '../../components/Icon/Icon'; import { translate, Trans } from 'react-i18next'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; import './Logout.scss'; diff --git a/imports/ui/pages/NotFound/NotFound.js b/imports/ui/pages/NotFound/NotFound.js index fee65d3..7c63949 100644 --- a/imports/ui/pages/NotFound/NotFound.js +++ b/imports/ui/pages/NotFound/NotFound.js @@ -1,7 +1,7 @@ import React from 'react'; import { Alert } from 'react-bootstrap'; import { translate, Trans } from 'react-i18next'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; const NotFound = () => (
diff --git a/imports/ui/pages/Page/Page.js b/imports/ui/pages/Page/Page.js index 3d8bfb3..0123ab2 100644 --- a/imports/ui/pages/Page/Page.js +++ b/imports/ui/pages/Page/Page.js @@ -6,7 +6,7 @@ import { ReactiveVar } from 'meteor/reactive-var'; import i18n from '/imports/startup/client/i18n'; import PageHeader from '../../components/PageHeader/PageHeader'; import Content from '../../components/Content/Content'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; import './Page.scss'; diff --git a/imports/ui/pages/RecoverPassword/RecoverPassword.js b/imports/ui/pages/RecoverPassword/RecoverPassword.js index 72c9156..4649e4b 100644 --- a/imports/ui/pages/RecoverPassword/RecoverPassword.js +++ b/imports/ui/pages/RecoverPassword/RecoverPassword.js @@ -5,7 +5,7 @@ import PropTypes from 'prop-types'; import { Link } from 'react-router-dom'; import { Accounts } from 'meteor/accounts-base'; import { Bert } from 'meteor/themeteorchef:bert'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; import AccountPageFooter from '../../components/AccountPageFooter/AccountPageFooter'; import validate from '../../../modules/validate'; import { translate } from 'react-i18next'; diff --git a/imports/ui/pages/ResetPassword/ResetPassword.js b/imports/ui/pages/ResetPassword/ResetPassword.js index bd5e1b2..f2e6647 100644 --- a/imports/ui/pages/ResetPassword/ResetPassword.js +++ b/imports/ui/pages/ResetPassword/ResetPassword.js @@ -4,7 +4,7 @@ import { Row, Alert, FormGroup, ControlLabel, Button } from 'react-bootstrap'; import Col from '../../components/Col/Col'; import { Accounts } from 'meteor/accounts-base'; import { Bert } from 'meteor/themeteorchef:bert'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; import validate from '../../../modules/validate'; import { translate } from 'react-i18next'; import { T9n } from 'meteor-accounts-t9n'; diff --git a/imports/ui/pages/Signup/Signup.js b/imports/ui/pages/Signup/Signup.js index 2dbe15b..6a9e080 100644 --- a/imports/ui/pages/Signup/Signup.js +++ b/imports/ui/pages/Signup/Signup.js @@ -10,7 +10,7 @@ import { Accounts } from 'meteor/accounts-base'; import { Bert } from 'meteor/themeteorchef:bert'; import { translate, Trans } from 'react-i18next'; import { T9n } from 'meteor-accounts-t9n'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; import { testId } from '/imports/ui/components/Utils/TestUtils'; import Col from '../../components/Col/Col'; import Icon from '../../components/Icon/Icon'; diff --git a/imports/ui/pages/Status/Status.js b/imports/ui/pages/Status/Status.js index 3909468..7712cf4 100644 --- a/imports/ui/pages/Status/Status.js +++ b/imports/ui/pages/Status/Status.js @@ -7,7 +7,7 @@ import PropTypes from 'prop-types'; import { translate } from 'react-i18next'; import { withTracker } from 'meteor/react-meteor-data'; import Blaze from 'meteor/gadicc:blaze-react-component'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; /* https://github.com/meteor/docs/blob/version-NEXT/long-form/oplog-observe-driver.md diff --git a/imports/ui/pages/Subscriptions/Subscriptions.js b/imports/ui/pages/Subscriptions/Subscriptions.js index 6e7e9b9..061c230 100644 --- a/imports/ui/pages/Subscriptions/Subscriptions.js +++ b/imports/ui/pages/Subscriptions/Subscriptions.js @@ -9,7 +9,7 @@ import { Meteor } from 'meteor/meteor'; import { withTracker } from 'meteor/react-meteor-data'; import { Trans, translate } from 'react-i18next'; import { Bert } from 'meteor/themeteorchef:bert'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; import UserSubsToFiresCollection from '/imports/api/Subscriptions/Subscriptions'; import SelectionMap, { action } from '/imports/ui/components/SelectionMap/SelectionMap'; import confirm from '/imports/ui/components/Prompt/Confirm'; diff --git a/imports/ui/pages/Subscriptions/SubscriptionsMap.js b/imports/ui/pages/Subscriptions/SubscriptionsMap.js index 52d6874..6ecb652 100644 --- a/imports/ui/pages/Subscriptions/SubscriptionsMap.js +++ b/imports/ui/pages/Subscriptions/SubscriptionsMap.js @@ -9,7 +9,7 @@ import { Meteor } from 'meteor/meteor'; import { withTracker } from 'meteor/react-meteor-data'; import { Trans, translate } from 'react-i18next'; import { Map } from 'react-leaflet'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; import L from 'leaflet'; import 'leaflet/dist/leaflet.css'; import 'leaflet-graphicscale/dist/Leaflet.GraphicScale.min.css'; diff --git a/imports/ui/pages/VerifyEmail/VerifyEmail.js b/imports/ui/pages/VerifyEmail/VerifyEmail.js index 6bdc918..cd6b0c7 100644 --- a/imports/ui/pages/VerifyEmail/VerifyEmail.js +++ b/imports/ui/pages/VerifyEmail/VerifyEmail.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Alert } from 'react-bootstrap'; import { Meteor } from 'meteor/meteor'; -import { Helmet } from 'react-helmet'; +import { Helmet } from 'react-helmet-async'; import { Accounts } from 'meteor/accounts-base'; import { Bert } from 'meteor/themeteorchef:bert'; import { translate } from 'react-i18next'; diff --git a/package-lock.json b/package-lock.json index c74248b..0f7cdc8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -64,7 +64,7 @@ "react-bootstrap": "^0.31.5", "react-confirm": "^0.1.16", "react-dom": "^18.3.1", - "react-helmet": "^5.2.0", + "react-helmet-async": "^2.0.5", "react-i18next": "^7.4.0", "react-leaflet": "^1.8.0", "react-leaflet-control": "^1.4.0", @@ -3543,15 +3543,6 @@ "semver": "^5.3.0" } }, - "node_modules/babel-preset-env/node_modules/invariant": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", - "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", - "dev": true, - "dependencies": { - "loose-envify": "^1.0.0" - } - }, "node_modules/babel-preset-jest": { "version": "21.2.0", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-21.2.0.tgz", @@ -3817,15 +3808,6 @@ "node": ">=0.10.0" } }, - "node_modules/babel-traverse/node_modules/invariant": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", - "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", - "dev": true, - "dependencies": { - "loose-envify": "^1.0.0" - } - }, "node_modules/babel-traverse/node_modules/to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", @@ -4951,11 +4933,6 @@ "node": ">=0.10.0" } }, - "node_modules/deep-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" - }, "node_modules/deep-is": { "version": "0.1.3", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", @@ -6354,11 +6331,6 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, - "node_modules/exenv": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", - "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=" - }, "node_modules/expand-brackets": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", @@ -8406,14 +8378,6 @@ "warning": "^3.0.0" } }, - "node_modules/history/node_modules/invariant": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", - "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, "node_modules/history/node_modules/warning": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", @@ -8810,8 +8774,10 @@ } }, "node_modules/invariant": { - "version": "2.2.2", - "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", "dependencies": { "loose-envify": "^1.0.0" } @@ -19686,26 +19652,24 @@ "react": "^18.3.1" } }, - "node_modules/react-helmet": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-5.2.0.tgz", - "integrity": "sha1-qBgR3yExOm1VxfBYxK66XW89l6c=", + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" + }, + "node_modules/react-helmet-async": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-2.0.5.tgz", + "integrity": "sha512-rYUYHeus+i27MvFE+Jaa4WsyBKGkL6qVgbJvSBoX8mbsWoABJXdEO0bZyi0F6i+4f0NuIb8AvqPMj3iXFHkMwg==", + "license": "Apache-2.0", "dependencies": { - "deep-equal": "^1.0.1", - "object-assign": "^4.1.1", - "prop-types": "^15.5.4", - "react-side-effect": "^1.1.0" + "invariant": "^2.2.4", + "react-fast-compare": "^3.2.2", + "shallowequal": "^1.1.0" }, "peerDependencies": { - "react": ">=15.0.0" - } - }, - "node_modules/react-helmet/node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "engines": { - "node": ">=0.10.0" + "react": "^16.6.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-i18next": { @@ -19916,14 +19880,6 @@ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz", "integrity": "sha1-ND24TGAYxlB3iJgkATWhQg7iLOA=" }, - "node_modules/react-router-dom/node_modules/invariant": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", - "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, "node_modules/react-router-dom/node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -19990,15 +19946,6 @@ "react": "^0.13.0 || ^0.14.0 || ^15.0.0 || ^16.0.0-0" } }, - "node_modules/react-side-effect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-1.1.3.tgz", - "integrity": "sha1-USwlq+DewXKDTEAB7FxR4E1BvFw=", - "dependencies": { - "exenv": "^1.2.1", - "shallowequal": "^1.0.1" - } - }, "node_modules/read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -20763,9 +20710,10 @@ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, "node_modules/shallowequal": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.0.2.tgz", - "integrity": "sha512-zlVXeVUKvo+HEv1e2KQF/csyeMKx2oHvatQ9l6XjCUj3agvC8XGf6R9HvIPDSmp8FNPvx7b5kaEJTRi7CqxtEw==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" }, "node_modules/shebang-command": { "version": "1.2.0", diff --git a/package.json b/package.json index f5cb800..b835348 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "react-bootstrap": "^0.31.5", "react-confirm": "^0.1.16", "react-dom": "^18.3.1", - "react-helmet": "^5.2.0", + "react-helmet-async": "^2.0.5", "react-i18next": "^7.4.0", "react-leaflet": "^1.8.0", "react-leaflet-control": "^1.4.0",