Metal to React
This repo is a proof of concept to see how difficult is to migrate from metal-jsx to react.
What do the transforms do?
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.
How to use Transforms
- 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.
Migration Pain Points(after running transforms)
- 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" />