CRA Multi Page React: Add Multiple Entry Points No Eject

Introduction

Create React App (CRA) is beloved for its zero‑configuration setup, but developers often hit a wall when they need to serve more than one HTML page from the same codebase. Traditional single‑page applications (SPAs) rely on a single entry point (usually src/index.js), which makes it cumbersome to build distinct sections such as an admin panel, a marketing landing page, or a client‑specific dashboard. Fortunately, CRA can be extended to support multiple entry points without the risky step of “ejecting” the underlying webpack configuration. This article walks you through the rationale, the required tooling, the precise configuration tweaks, and the deployment considerations needed to turn a standard CRA project into a clean, maintainable multi‑page React application.

Why Multiple Entry Points Matter

When a project grows, separating concerns at the build level brings several advantages:

  • Independent bundles: Each page loads only the JavaScript and CSS it truly needs, improving initial load time.
  • Tailored HTML templates: Different pages can have unique meta tags, favicons, or third‑party scripts without polluting a single index.html.
  • Clearer code organization: Entry‑specific root components keep the component tree shallow and easier to reason about.
  • Simplified CI/CD: Deployments can target distinct URLs (e.g., /admin vs. /) while sharing the same repository and build pipeline.

Understanding these benefits helps you decide whether a multi‑page approach fits your architecture before you start tinkering with the build system.

Setting Up the Project and Adding a Second Entry

Begin with a fresh CRA project and install a lightweight override tool that lets you modify webpack without ejecting:

  • Run npx create-react-app multi‑entry-demo.
  • Install react-app-rewired and customize-cra as dev dependencies:
  • npm i -D react-app-rewired customize-cra

Next, adjust the scripts in package.json to use the rewired binary:

  • "start": "react-app-rewired start"
  • "build": "react-app-rewired build"

Create a new entry file, for example src/admin.js, and a matching HTML template public/admin.html. The template should contain a distinct div with an id that matches the root element rendered by admin.js (e.g., <div id="admin-root"></div>).

Extending the Webpack Config Without Ejecting

Now create config-overrides.js at the project root. Using customize‑cra, you can inject additional entry points and HTML plugins while preserving CRA’s defaults:

  • Import the required helpers:
  • const { override, addWebpackPlugin } = require('customize-cra');
  • Import HtmlWebpackPlugin to generate the second HTML file:
  • const HtmlWebpackPlugin = require('html-webpack-plugin');
  • Define a function that merges the new entry:
  • const addAdminEntry = () => config => {
  •   config.entry = { …config.entry, admin: ‘./src/admin.js’ };
  •   return config;
  • };
  • Export the composed overrides:
  • module.exports = override(
  •   addAdminEntry(),
  •   addWebpackPlugin(new HtmlWebpackPlugin({
  •     template: ‘./public/admin.html’,
  •     filename: ‘admin.html’,
  •     chunks: [‘admin’]
  •   }))
  • );

This configuration tells CRA to bundle admin.js separately and to emit an admin.html file that loads only the admin chunk. Because we never ran npm run eject, all future CRA updates remain compatible.

Building, Deploying, and Best Practices

Run npm run build and you will see two HTML files (index.html and admin.html) alongside their respective JavaScript bundles in the build folder. When deploying:

  • Serve index.html at the root URL (e.g., example.com/).
  • Serve admin.html at a sub‑path (e.g., example.com/admin/) or a separate sub‑domain.
  • Configure your web server to fallback to the correct HTML file for client‑side routing (e.g., RewriteRule ^admin/ - [L] for Apache).

Additional tips to keep the setup robust:

  • Lazy‑load shared components: Use dynamic import() so that common code is extracted into a shared chunk.
  • Environment variables: Prefix variables with REACT_APP_ and reference them in each entry to keep configuration consistent.
  • Testing: Run the development server with npm start; CRA will automatically serve both pages at http://localhost:3000/ and http://localhost:3000/admin.html.

By following these patterns, you maintain the simplicity of CRA while gaining the flexibility of a true multi‑page application.

Conclusion

Building a multi‑page React app with multiple entry points is entirely feasible inside the Create React App ecosystem, provided you leverage a non‑ejecting override tool such as react-app-rewired. The process involves adding extra entry files, creating dedicated HTML templates, and modestly extending the webpack configuration through config-overrides.js. The result is a set of independent bundles that load only the code each page requires, leading to faster performance, cleaner separation of concerns, and smoother deployment pipelines. By adhering to best practices—lazy‑loading shared modules, using environment variables wisely, and configuring server fallbacks—you can scale your project without sacrificing the convenience of CRA’s managed setup. This approach empowers teams to deliver richer, multi‑faceted experiences while keeping maintenance overhead low.

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Digital Malayali