Migrating Angular JS app to React

We often have to deal with legacy code at some point. In my organization, we have an app that uses the AngularJS framework and is not touched for quite some years. Recently, we were tasked to add a new feature to that app.

The app had quite a lot of outdated dependencies with dependencies coming from both bower.json andpackage.json. The build tool used older versions of Gulp andWebpack.

We tried to add the new feature without upgrading any of the packages, but it resulted in a lot of pain. Even a tiny change to the old AngularJS framework was tiresome.

Upgrading to the latest version of Angular required a complete rewrite of the entire app. We all know rewriting an entire application needs a lot of man work. So, we decided to look for options that offer an incremental upgrade.

All the apps in my organization use React. Hence, we decided to move forward to introduce React to this project. I took the responsibility to do it. After some research on Google, some libraries like ngReact, react2angular, angular2react offer migration to React from legacy Angular JS code.

Since the app uses v1.2.28 of AngularJS, ngReact is the only package that offers support as other packages are targeted for higher versions.

Now, let’s see how to introduce React + Typescript into an Angular JS app using ngReact along with tools like Prettier, ESLint etc.,

This can be done in a series of following steps:

  • Install dependencies
  • Webpack configuration
  • Adding tsconfig.json
  • Adding ESLint config
  • Loading dependencies
  • Adding React component

Install dependencies

Install the necessary dependencies. The demonstration uses yarn for dependency inclusion.

Add the following as devDependencies

yarn add typescript @types/react @types/react-dom @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-config-prettier eslint-plugin-react eslint-plugin-react-hooks prettier -D

Add the following as dependencies

yarn add react react-dom ngreact

Webpack Configuration

Add the necessary dependencies for webpack.

yarn add ts-loader fork-ts-checker-webpack-plugin -D

The project used a combination of Gulp and Webpack for bundling. As a first step, I upgraded all the dependencies of Gulp and Webpack. Since removing Gulp needed a lot of effort, we decided to remove it at a later stage.

Adjust the webpack configuration as follows:

As you can see in the above example, the ts-loader package manages the files with extension .ts and .tsx. It is also advised to include the transpileOnly option to true so that fork-ts-checker-webpack-plugin takes care of type checking.

If you use AngularJS < 1.3.14, it is also important to add the corresponding loader as seen in the snippet to recognize `require(‘angular’)`

Adding tsconfig.json

To enable Typescript, add the tsconfig.json with allowJs option set totrue and jsx option set toreact-jsx. Enabling this option, allows you to skip React import in every file for newer versions of React.

Adding ESLint config

Create a .eslintrc file and add the necessary plugins of your choice like below. To avoid typescript, linting js files, apply @typescript-eslint plugin only for files with extension .ts and .tsx in overrides section as seen in the snippet.

Loading dependencies

Create a vendors.js file and include high-level dependencies.ngReact requires loading React and AngularJS dependencies before its inclusion as below.

Including react directive

In your root module, include react as the first module before all others as follows:

Adding a component

Now with all the setup done, let’s add our first good old hello world react component.

Utility function

Before creating the components, we need an additional step to convert the React component into an AngularJS directive.

These three lines of code do the conversion. This function takes the React component and the array of property strings as arguments and converts it to an angular directive.

React component

Create a HelloWorld.tsx file as below.

Pass the component and the props as an array ["name"] and export the return value from the createAngularDirective as provided in the snippet above.

Creating Angular Directive

Within the Angular JS module, embed theReact directive like below. Now, one could access the<hello-world> directive in the AngularJS HTML file.

Using the directive within HTML

Here, the value "name" comes from AngularJS scope, i.e.$scope.name. This way, one can use React component within the AngularJS module and pass props as well.

Navigation between routes

One could use window.history.pushState in the React component to navigating to the respective AngularJS route.

Configure Husky

Husky hooks allow prettifying files.

yarn add husky pretty-quick -D

Add the following script under scripts in package.json and run it only once using the commandyarn prepareafter installing husky.

"prepare" : "husky install"

Then create a pre-commit hook as:

npx husky add .husky/pre-commit "yarn pretty-quick -- staged"

This creates necessary files for the hook and runs prettier for staged files at the time of commit.

More info on Husky v6 can be found here.

Fullstack developer at Mercateo Gruppe

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store