How React finds index.html from index.js?

·

2 min read

Table of contents

No heading

No headings in the article.

I had this question when I got started with React probably a year ago, but I clearly remember finding it annoying and confusing how index.js contacts index.html for id references.

if you have ever used react, I'm assuming you have because why not it's cool and fun to learn, you must have seen this code in index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
    <title>React App</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

and

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

in index.js. If you are confused about the above code, then for your clarification this is what you get as a bare minimum from React for creating a React app with commands something like the below:

npx create-react-app my-world
cd my-world
npm start

Clearly we can see that we are not calling or mentioning index.js in any script tag in index.html. But how it is referencing the root div element in index.html?

So I did a little dig up and this is what I have found :)

create-react-app has a very interesting setup.I first started digging in the package.json npm script start

"start": "react-scripts start"

That takes me to their binary react-scripts under node_modules/.bin

if (['build', 'eject', 'start', 'test'].includes(script)) {
  const result = spawn.sync(
    'node',
    nodeArgs
      .concat(require.resolve('../scripts/' + script))
      .concat(args.slice(scriptIndex + 1)),
    { stdio: 'inherit' }
  );

So this tells me that they are looking for a script inside ../scripts/ folder. I'm assuming that you have guessed our next step and that is (drum rolls please) to go to the react-scripts npm module(node_modules/react-scripts) and open up the node_modules/react-scripts/scripts/start.js file since I was doing npm start.

They are specifically referring to node_modules/react-scripts/config/webpack.config.dev.js

entry: [
  // Finally, this is your app's code:
  paths.appIndexJs,
],
plugins: [
  // Generates an `index.html` file with the <script> injected.
  new HtmlWebpackPlugin({
    inject: true,
    template: paths.appHtml,
  }),

as of now the webpack configs for dev & prod has been combined into one.

const configFactory = require('../config/webpack.config');

The HTMLWebpackPlugin config looks like this - This is since they have to conditionally add production config on top of this

plugins: [
  // Generates an `index.html` file with the <script> injected.
  new HtmlWebpackPlugin(
    Object.assign(
      {},
      {
        inject: true,
        template: paths.appHtml,
      },

So file referred by paths.appIndexJs is the entry file in the webpack config.

And they are using HtmlWebpackPlugin to load the html at the path paths.appHtml.

Final piece of the puzzle is linking this back.

module.exports = {
  ...
  appHtml: resolveApp('public/index.html'),
  appIndexJs: resolveModule(resolveApp, 'src/index'),
  ...
};

Wow! That was quite a journey..:P