This repo is a proof of concept to see how difficult is to migrate from metal-jsx to react.
Tested on:
macOS: v10.12.6
node: v11.8.0
npm: v6.5.0
The goal is for the jscodeshift transforms to do ~90% of the work. The remaining 10% is likely specific application code that can't be converted 1-to-1 from metal to react.
Note: If you are using decorators in your code base, you will need to install and run this branch for jscodeshift to work properly. Do this by cloning this, and run npm install && npm install -g .
in that repo.
- Run all transforms on codebase.
node ${TRANSFORMS_DIR}/all.js
in the directory you want to run the transforms against. - Install new dependencies,
npm i --save react react-dom react-redux && npm i --save-dev babel-preset-react
- Update babel config, remove
metal-jsx
preset and addreact
preset.- You may also need
babel-polyfill
installed and specified in your webpack config.
- You may also need
- Now you can try to build your app and work out any errors that happen in the build process
- Once you get your app building successfully, you'll need to manually handle errors you see in your browser.
- A large set of errors will likely be due to Router, try to swap in a new router early in migration.
- Now you'll need to go through work through all of the
METAL_JSX_CODE_MOD:
comments manually. - Finally, once you get all the errors figured out, its best to run whatever formatter you want to ensure code cleanliness. I personally prefer prettier.
- Need to manually go through and migrate to new Router framework.
- Likely either react-router or reach-router
elementClasses
is unique in metal-jsx and is used quite a bit. Manually migrating to adding className for each component is time consuming.- POSSIBLE_SOLUTION: Use element-classes transform to manually add
this.props.elementClasses
to every component and slowly migrate away from this. (this is the route I chose to use.) - POSSIBLE_SOLUTION: Create a babel plugin to make elementClasses behave like they do in metal-jsx. See babel-plugin-react-element-classes
- POSSIBLE_SOLUTION: Use element-classes transform to manually add
- Non 1-for-1 lifecycles need to be manually addressed.
detached
,disposed
, andwillReceiveState
all getFIXME_
appended to their name so we can easily address them.willAttach
,willReceiveProps
,willUpdate
have 1-for-1 equivalents but they are soon to be deprecated and considered unsafe.- All
sync{PROP_NAME}
methods must also be manually migrated. Using eithergetDerivedStateFromProps
orUNSAFE_componentWillReceiveProps
from react.
- Any 3rd party metal-jsx package needs to be removed and migrated over.
- POSSIBLE_SOLUTION: Create some sort of bridge component that allows use of metal-jsx inside of react. Codesandbox Example
- The context API is much different in react, this requires manual migration to the new context API.
- POSSIBLE_SOLUTION: Create a simple guide for what that migration would look like.
- Fixing any
style
attributes on jsx requires manual migration to using react's format for style- POSSIBLE_SOLUTION: We might be able to come up with a transform to do this.
- Not all
Config
API is supported. Such assetter
,valueFn
,validator
,inRange
,writeOnly
andinternal
.- For now, we just remove all of these via tranforms.
this.otherProps()
works slightly differently than...this.props
. This can introduce bugs if you don't explicitly omit certain props. For example...
Metal
class MetalApp extends Metal.Component {
static PROPS = {
foo: Config.value('bar')
};
render() {
return <div {...this.otherProps()} />;
}
}
<MetalApp someCoolProp="baz" />;
// <div someCoolProp="baz" />
React
//React
class ReactApp extends React.Component {
defaultProps = {
foo: 'bar'
};
render() {
return <div {...this.props} />;
}
}
<ReactApp someCoolProp="baz" />;
// <div someCoolProp="baz" foo="bar" />