Skip to content
SPHuff's Blog

Adding React to an Existing Application

React, webpack3 min read

One question that I’ve seen come up in many different ways and forms is “I’ve got this massive application - how do I add react to it?” As this one Redditor points out:

“If you want jsx you need webpack, and how to do that with an dinasour mvc app? No docs :(“.

Another is confused about how to bundle an existing monorepo, asking:

“Do I have to bundle them separately and then use them in the main bundle? If so, what is the best tool for bundling each of them, also webpack or something else?”

I think a lot of this misunderstanding stems from not having an existing mental model about how webpack works, and how your React application is served. So I’ll start there, and then we can talk about adding React to an existing application.

How do React applications get rendered

If you haven’t been in the web development world for a bit, you might be surprised to find that there are many different flavors of Javascript, and React Javascript (jsx) is one of them. This flavor of Javascript is NOT immediately usable by the browser. In order to make it usable, we need a couple of components:

  1. An HTML file which imports a common.js script
  2. A React component
  3. Some way to turn React -> common.js

Even though this may seem complicated at first blush, what’s happening is very straightforward. Your application needs to be able to turn React code into common Javascript that can be understood by the browser. All build tools (webpack, rollup.js, esbuild, etc.) are doing the same thing.

Ok, so how do we make that transformation happen? I’ll be using webpack and express.js to serve up the application, but the concepts will be the same regardless of your stack.

Serving up a basic React application

Step 1: Install necessary dependencies

You’ll need a bunch of packages, most of them being webpack requirements. Go ahead and run npm install -D @babel/core @babel/preset-env @babel/preset-react babel-loader express react react-dom webpack webpack-cli

Step 2: Create a basic webpack build

Now we need to tell webpack what work to do by creating webpack.config.js. All that the 20 lines of this file is saying is “read in some Javascript starting at react-component.js, bundle it into common.js, and output that bundle at react-component.bundle.js.

1const path = require('path');
2
3 module.exports = {
4 mode: 'development',
5 entry: {
6 react: '.react-component.js', // here's your react file
7 },
8 output: {
9 filename: '[name].bundle.js',
10 // this is your output folder
11 path: path.resolve(__dirname, 'dist'),
12 },
13 module: {
14 rules: [
15 {
16 test: /\.js(x)?$/, // turn all jsx into commonjs
17 use: 'babel-loader', // using this loader
18 exclude: [/node_modules/, /dist/],
19 },
20 ],
21 },
22 };

Step 3: Create your React component

We can keep this one super simple for the moment. The big thing to remember here is that our component needs to attach to a DOM element. If you don’t do that, your component won’t display.

1// react-component.js
2import React from 'react';
3import { render } from 'react-dom';
4
5const App = () => {
6 return (
7 <div>
8 Hiya from React world
9 </div>
10 );
11}
12
13render(<App />, document.getElementById('root'));

Step 4: Create a .babelrc

OK, this one needs some more explanation. In order to transform jsx -> common.js, webpack needs to use babel.js as a compiler. Like I mentioned earlier, there are many different flavors of modern Javascript, so we need to tell babel which one to expect. Create a .babelrc file like so:

1{
2 "presets": ["@babel/preset-react"]
3}

Step 5: Create a basic HTML skeleton

Now all that’s left is to create the actual HTML file that’ll be served up. At the end of the day, all browser applications are HTML plus some extra junk, so we can’t forget this part. Similar to our note for the React component, we can’t forget to create a DOM node for the component.

1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width">
6 <title>Webpack test</title>
7 </head>
8 <body>
9 <!-- note: this MUST be here for react to know where to render -->
10 <div id="root"></div>
11 <script src="react-component.bundle.js"></script>
12 </body>
13</html>

Cool, now let’s run npx webpack (or node_modules/webpack/bin/webpack.js if you don't have npx), and we should see a new bundle!! If you open up your HTML file, you should see the React app.

Hiya

It’s so beautiful 😭

Step 6: Serve up the HTML file

From there, serving our application is just a matter of serving up our HTML file. Super simple setup here:

1const express = require('express');
2const server = express();
3const port = 4000;
4
5server.listen(port, () => {
6 console.log(`server is listening on ${port}`);
7});
8
9server.use(express.static('dist')); // where our index.html and bundle lives

Can’t get easier than that. You’ll now see your React application when you hit http://localhost:4000

Adding to an existing application

Ok, now the thing you originally came here for. The main takeaway from the above work is that all you need to render React is:

  1. a way to transform it to common.js
  2. a DOM element for your component to attach to

Cool, so how does that work in practice?

Progressive Reactization

For a greenfield project starting with React, we would probably have a dummy HTML file like the above, and the rest of the DOM elements are React components. We don’t have that luxury with an existing app, so we’ll need to progressively reactify.

As a contrived example, let’s say that we want to add some nice React card components to our existing boring Node.js/vanilla Javascript app. To start, let’s create our card container component.

1// card-component.js
2import React from 'react';
3import { render } from 'react-dom';
4
5const CardContainer = () => {
6 return (
7 <div>
8 This is where your cards go.
9 </div>
10 );
11}
12
13render(<CardContainer />, document.getElementById('card-container'));

Notice that it’s the exact same formula as before - create a component, and attach it to a DOM node.

Now we need to add our component to our HTML file:

1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width">
6 <title>Webpack test</title>
7 </head>
8 <body>
9 <!-- other stuff -->
10 <div id="card-container"></div>
11 <script src="card-container.bundle.js"></script>
12 </body>
13</html>

Obviously there will be a ton of other junk, but we’ll brush over that in this example. The important parts are:

  1. The DOM node that our component references
  2. Importing the bundle that will be created by webpack

Now let’s create our slightly modified webpack.config.js

1const path = require('path');
2
3 module.exports = {
4 mode: 'development',
5 entry: {
6 react: '.src/card-container.js', // here's your react file
7 },
8 output: {
9 filename: '[name].bundle.js',
10 // this is your output folder
11 path: path.resolve(__dirname, 'dist'),
12 },
13 module: {
14 rules: [
15 {
16 test: /\.js(x)?$/, // turn all jsx into commonjs
17 use: 'babel-loader', // using this loader
18 exclude: [/node_modules/, /dist/],
19 },
20 ],
21 },
22 };

Yes, I did shamelessly copy this from before - notice though that the entry is our new component.

That should be all you need to get up and running with your existing application. If you’ve got questions, feel free to shoot me an email at [email protected] or add me on Discord at farrenzo47#9325.

© 2024 by SPHuff's Blog. All rights reserved.
Theme by LekoArts