Starting this year, I was hired by , with the main goal of helping them migrate a legacy application from to and . Since then, we have been creating solutions inside the project, that is working greatly so far. BEN Group AngularJS React Redux In this post, I intend to show the main approaches we followed and share some solutions we created, to allow us migrate the project gradually and without loose our sanity. : Our focus here, is not refactoring legacy code, but remove it as soon as possible. We avoid solutions that takes too much time or focus in changing the legacy code in order to let it “prettier”. That said, we prime to write new code with great quality. Disclaimer Move the build to webpack. This step, I consider the most import from the whole process, once with , you can start using the instruction to get your dependencies and modules and you can start getting rid of Angular’s Dependency Injection(DI). This is also necessary to start writing code in the application. Webpack import React If you use Angular’s template cache, Pug(Jade) or any other thing that influences the build, don’t worry, Webpack will have a loader for each one of them. Don’t forget to let your Webpack configured to transpile ES2015 and JSX. This step doesn’t focus on moving all the DI to imports, but instead, make your build work with . It’s important to keep that in mind, to avoid staying in this task for weeks and cause conflicts in dozens of files. Webpack In , normally, the build process gets all the dependencies you need from node_modules and insert them in the bundle. We need to keep that behavior in the new build as well. AngularJS You need to consider the legacy code as an enemy to be defeated. We need to act with caution and we need to be strategic. This also means, that in certain moments, we need to do things that aren’t pleasant. To solve that matter, we created a file , and imported all the dependencies inside it: vendor.js ( ); ( ); require 'angular' require 'angular-resource' // ...other dependencies Most of the dependencies registered themselves globally in the object, when they are imported. So, we only need to import them as the above example. Although, some of them doesn’t do that and we need to do it manually. Bellow we have an example of what we had to do with and : window moment jQuery .moment = ( ); .$ = ( ); .jquery = .$; .jQuery = .$; window require 'moment' window require 'jquery' window window window window This practice could be weird, however, you need to consider that most of the dependencies are relying on , others and others even on . window.$ onwindow.jQuery window.jquery After creating the vendors file, import it in the entry point of your application and this way, all your dependencies will be in the bundle: ( ); require './vendors' Another step, is to ensure that all your application’s files are in the bundle. The ideal, is having each module with an index file, importing controllers, factories, views, etc.. Having that, you only need to import those indexes in the application’s entry point, same way you did with vendors, as the following example: ( ); ( ); ( ); ( ); require './vendors' require './app/common/index' require './app/core/index' require './app/layout/index' If you don’t have the indexes, you can try to follow a solution a little dare, not much advised though. That would be find a regex to match all your files and import them using , as the below example: require.context { r.keys().forEach(r); } requireAll( .context( , , /\.(js|jsx)$/)); ( ) function requireAll r require './app/' true The above code, will force to include in the bundle, all and files that are inside folder and its subfolders. If you decide to follow this way, don’t forget that you may have , and even files, and you will have to exclude them in the regex. Webpack .js .jsx /app .test.js .spec.js .stories.js Also, remember that in some cases, is counting on the ordering that your files are loaded, so, this solution could end up not working at all. Angular When you finally get your build working, hurry up to create a pull request targeting your master branch. Apart , moving the build to is already a gain for your application. The Angular’s DI makes the application to be strongly coupled and is our ally against that React Webpack Webpack Render React components inside AngularJS The second most important step, because without that is not possible to migrate gradually. The idea here, is that you could use components inside , as they were directives. To achieve that, we are currently using in our project. React Angular ngReact The ngReact repo is advising to use the lib . However, we are using Angular 1.5.8 in our app, and we end up getting some problems trying to use the other lib. I already used react2Angular in another project, that were using a more recent Angular’s version and I didn’t have any issue. That said, ngReact even not being updated anymore, has all the feature we need to transform our components into directives. My advise is: choose the lib that works for you and go ahead, both are very similar react2Angular To integrate in the project, you can install it from npm: ngReact $ npm i --save ngreact And then import it in your vendors: require(' ngreact '); You also need to install and in your project: react react-dom npm i --save react react-dom And then, register module into : react Angular angular.module('app', [' react ']); With that done, we can create a component, as we would create in a regular application: Button React React ; Button = ( ); Button; import from 'react' const ( ) => { children, ...restProps } {children} < { }> button ...restProps </ > button export default And then, we define a directive that works as a wrapper for : Button Button ; props = [ , , , , , ]; ReactButton = reactDirective(Button, props); ReactButton.$inject = [ ]; ReactButton; import from 'path/to/Button' const 'children' 'id' 'className' 'disabled' 'etc..' const => reactDirective 'reactDirective' export default In the directive’s file, we must define the name of all the props whose are used by , in order to understands what it should pass down to the component. Button ngReact Directive defined, we need to register it in : Angular reactButton ; angular .module( ) .directive(‘reactButton’, reactButton); import from 'path/to/react-button' 'app' The Angular’s modules that you gonna use to register it doesn’t matter, just make sure it was registered in the application. Once registered, we can now use the directive in any angular’s view, as the follow example: <div> < react-button class-name="btn"></ react-button > </div> Notice that here, instead of CamelCase, we use dash to split the words. In this case, reactButton becomes react-button and , becomes . It’s important to keep that in mind, given this is a common mistake and could take hours to debug. className class-name It’s common to use to render small components inside applications, but not much productive though. ngReact AngularJS allows us to pass a parameter template in the route config. Exploring that, it’s possible to create a wrapper component for each application’s screen and then use those wrappers as the following example: Angular UI Router, $stateProvider.state( , { : , : , }); 'user.login' url '/login' template '<react-screen-login></<react-screen-login>' In the above example, we define a login route and pass it to a component, which is the whole Login screen. This way, we can migrate a whole screen per time, instead of migrating component by component. My gold advise here, is to install in the project, to create and test the small components. That way is easier to build solid components and then put them together into the screens. Storybook Screens: Also known as pages, they are the root component of each route. Share dependencies Define an entire screen is amazing. However, when we come to this point, we also need to share some dependencies with . Angular React In the case of BEN, the dependencies we need, was only ready after the Angular’s initialization, after it have executed its providers, config, etc... Given that, it wasn’t possible to export them using the keyword. To go around that, we created an object and a helper function to inject the dependencies. To implement that solution, we only need to create a file named with the following code: export ngDeps.js ngDeps = {}; { .assign(ngDeps, deps); }; ngDeps; export const export ( ) function injectNgDeps deps Object export default We call inside an Angular’s process as the below example: injectNgDeps run { injectNgDeps } ; angular .module( , []) .run([ , , ($rootScope, $state) => { injectNgDeps({ $rootScope, $state }); }, ]); import from 'path/to/ngDeps' 'app' '$rootScope' '$state' We do that because we want to have access to the dependencies as soon as possible and is one of the first processes executed in the initialization. The accepts an object as argument, and merge it with the object. run injectNgDeps ngDeps When you need any dependency inside a component, you only need to do as the following: React React, { Component } ; ngDeps ; { (props) { (props); { $state, $rootScope } = ngDeps; .$state = $state; .$rootScope = $rootScope; } render() { import from 'react' import from 'path/to/ngDeps' class Login extends Component constructor super const this this return } } < /> div Notice that the first thing we do, is to import . If you try to access ngDeps.$state right after the , the result will be undefined, because the process didn’t ran yet. For that reason, we access the value inside the component’s method, because the components will be instantiated only after has initialized. ngDeps import run contructor Angular We extract the dependencies from and we assigned them to the object , because this way we can access this.$state inside any class’s method ngDeps this This way it’s possible to share any Angular’s dependency with components. However, use with parsimony. Keep always in mind: Can I export this dependency using ? If the answer is yes, you always chose to use export, otherwise you use . React ngDeps export ngDeps Another thing to highlight, is that it is important to keep the access to restrict to the top components in the tree. That means screens, and possibly some containers. And then, pass down to children by props. This way it will be easier to remove when the time comes. ngDeps ngDeps Integrate Redux in the application After solve the question about sharing dependencies between both sides, we can go ahead and integrate into the application. To do that isn’t so hard, but there are some particularities though. Redux First, configure the store following the , as you would do in any application. However, once you create the object , you must export it asthe following way: docs instructions store export const store = createStore(rootReducer); That will allow us to access the object in other files in the application store In a regular application, we integrate our containers to the , using the method from . Although, that only works because we insert the with the as the root component in the application, as we can see in the lib’s docs: store connect react-redux Provider store ReactDOM.render( <MyAppRootComponent /> , rootEl ) < = > Provider store {store} </ > Provider The problem is that we can’t have a single root component in our application, we have many. It’s impractical that we keep controlling that manually, which components should contain the Provider and which doesn’t. To solve that, we created a High Order Component, which abstracts that logic and insert the Provider as a wrapper when necessary. To make it accessible, I published it on and on as . Github NPM redux-connect-standalone To install it by NPM: npm i --save redux-connect-standalone And then, we can create our connect file and use the following code: createConnect ; store ; connect = createConnect(store); import from 'redux-connect-standalone' import 'path/to/youStore' export const Inside your components, instead of importing the method from , import it from the file you just created. And use it the same way you would use the original method: connect react-redux { connect } ; connect( mapStateToProps, mapDispatchToProps )(YourContainer); import from 'path/to/youConnect' export default As we are respecting the same signature from the original method, the day you have a as your application’s root component, you will only need to execute a search replace in the import method, to replace it by: Provider { connect } ; import from 'react-redux' If you use or intend to use redux-form in your application, I also created and published a HOC to reduxForm method, the . His usage is very similar to the HOC we saw above. redux-form-connect-standalone Final words Having those recipes in hands, it’s possible to migrate your application gradually. However, there are always other complex stuff that shows up when you are migrating an application’s base technology. It’s important to keep in mind that all the solutions above are a middle ground between Angular and React. The final goal is to get rid of all of them and use the and conventions and good practices. . React Redux’s So, whenever you create a solution, think how hard will be to get it removed later If you find any interesting solution or problem, share with us. If you like this post, help us spread the word for more people to keep evolving and improving their applications.