4.4 KiB
TASK-003: Runtime React 18.3.1 Upgrade - CHANGELOG
Summary
Upgraded the noodl-viewer-react runtime package from React 16.8/17 to React 18.3.1. This affects deployed/published Noodl projects.
Note
: Originally targeted React 19, but React 19 removed UMD build support. React 18.3.1 is the latest version with UMD bundles and provides 95%+ compatibility with React 19 APIs.
Date: December 13, 2025
Changes Made
1. Main Entry Point (noodl-viewer-react.js)
File: packages/noodl-viewer-react/noodl-viewer-react.js
- Changed
ReactDOM.render()→ReactDOM.createRoot().render() - Changed
ReactDOM.hydrate()→ReactDOM.hydrateRoot() - Added
currentRootvariable for root management - Added
unmount()method for cleanup
// Before (React 16/17)
ReactDOM.render(element, container);
ReactDOM.hydrate(element, container);
// After (React 18)
const root = ReactDOM.createRoot(container);
root.render(element);
const root = ReactDOM.hydrateRoot(container, element);
2. React Component Node (react-component-node.js)
File: packages/noodl-viewer-react/src/react-component-node.js
- Removed
ReactDOM.findDOMNode()usage (deprecated in React 18) - Added
_domElementstorage inNoodlReactComponentref callback - Updated
getDOMElement()method to use stored DOM element reference - Removed unused
ReactDOMimport after findDOMNode removal
// Before (React 16/17)
import ReactDOM from 'react-dom';
// ...
const domElement = ReactDOM.findDOMNode(ref);
// After (React 18)
// No ReactDOM import needed
// DOM element stored via ref callback
if (ref && ref instanceof Element) {
noodlNode._domElement = ref;
}
3. Group Component (Group.tsx)
File: packages/noodl-viewer-react/src/components/visual/Group/Group.tsx
- Converted
UNSAFE_componentWillReceiveProps→componentDidUpdate(prevProps) - Merged scroll initialization logic into single
componentDidUpdate
4. Drag Component (Drag.tsx)
File: packages/noodl-viewer-react/src/components/visual/Drag/Drag.tsx
- Converted
UNSAFE_componentWillReceiveProps→componentDidUpdate(prevProps)
5. UMD Bundles (static/shared/)
Files:
-
packages/noodl-viewer-react/static/shared/react.production.min.js -
packages/noodl-viewer-react/static/shared/react-dom.production.min.js -
Updated from React 16.8.1 to React 18.3.1 UMD bundles
-
Downloaded from
unpkg.com/react@18.3.1/umd/
6. SSR Package (static/ssr/package.json)
File: packages/noodl-viewer-react/static/ssr/package.json
- Updated
reactdependency:^17.0.2→^18.3.1 - Updated
react-domdependency:^17.0.2→^18.3.1
API Migration Summary
| Old API (React 16/17) | New API (React 18) | Status |
|---|---|---|
ReactDOM.render() |
ReactDOM.createRoot().render() |
✅ Migrated |
ReactDOM.hydrate() |
ReactDOM.hydrateRoot() |
✅ Migrated |
ReactDOM.findDOMNode() |
Ref callbacks with DOM storage | ✅ Migrated |
UNSAFE_componentWillReceiveProps |
componentDidUpdate(prevProps) |
✅ Migrated |
Build Verification
- ✅
npm run ci:build:viewerpassed successfully - ✅ Webpack compiled with no errors
- ✅ React externals properly configured (
external "React",external "ReactDOM")
Why React 18.3.1 Instead of React 19?
React 19 (released December 2024) removed UMD build support. The Noodl runtime architecture relies on loading React as external UMD bundles via webpack externals:
// webpack.config.js
externals: {
react: 'React',
'react-dom': 'ReactDOM'
}
React 18.3.1 is:
- The last version with official UMD bundles
- Fully compatible with createRoot/hydrateRoot APIs
- Provides a stable foundation for deployed projects
Future consideration: Evaluate ESM-based loading or custom React 19 bundle generation.
Files Modified
packages/noodl-viewer-react/noodl-viewer-react.jspackages/noodl-viewer-react/src/react-component-node.jspackages/noodl-viewer-react/src/components/visual/Group/Group.tsxpackages/noodl-viewer-react/src/components/visual/Drag/Drag.tsxpackages/noodl-viewer-react/static/shared/react.production.min.jspackages/noodl-viewer-react/static/shared/react-dom.production.min.jspackages/noodl-viewer-react/static/ssr/package.jsondev-docs/reference/LEARNINGS-RUNTIME.md(created - runtime documentation)