How React JS index.js file contacting index.html for id references? [duplicate]

I recently get started with react.

My index.html contains

<!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 index.js contains

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

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

My doubt is I didn't mention index.js in any script tag in index.html. But how it is referencing the root div element in index.html? I was wondering as it is working fine. Please explain me.

I had run these commands to create the app

npm install -g create-react-app
create-react-app hello-world
cd hello-world
npm start

Solution 1:

Create-React-App has a very interesting setup.

I 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
I'll post the relevant stuff here.

switch (script) {
  case 'build':
  case 'eject':
  case 'start':
  case 'test': {
    const result = spawn.sync(
      'node',
      [require.resolve('../scripts/' + script)].concat(args),
      { stdio: 'inherit' }
    );

So this tells me that they are looking for script inside ../scripts/ folder.

So I 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.

Now here is where I found the webpack config I was looking for.
They were specifically referring to node_modules/react-scripts/config/webpack.config.dev.js. I'll post the relevant stuff here.

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,
  }),

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 to the files you posted. Posting relevant stuff from paths.js

const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
module.exports = {
  ...
  appHtml: resolveApp('public/index.html'),
  appIndexJs: resolveApp('src/index.js'),
  ...
}

So inside your application directory,
appHtml is file public/index.html
appIndexJs is file src/index.js

Your two files in question.
Wow! That was quite a journey..:P


Update 1 - As of [email protected]

The react-scripts binary under node_modules/.bin has changed the logic as below. Essentially doing the same thing.

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' }
  );

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,
      },

The paths file code has some updates

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