---
title: "Configuring webpack to handle multiple browser windows in Electron"
description:
  "How to configure webpack to handle multiple browser windows in Electron"
canonical_url: "https://www.bigbinary.com/blog/electron-multiple-browser-windows"
markdown_url: "https://www.bigbinary.com/blog/electron-multiple-browser-windows.md"
---

# Configuring webpack to handle multiple browser windows in Electron

How to configure webpack to handle multiple browser windows in Electron

- Author: Farhan CK
- Published: November 12, 2024
- Categories: JavaScript, ReactJS, Electron

_Recently, we built [NeetoRecord](https://neetorecord.com/neetorecord/), a loom
alternative. The desktop application was built using Electron. In a series of
blogs, we capture how we built the desktop application and the challenges we ran
into. This blog is part 4 of the blog series. You can also read about
[part 1](https://www.bigbinary.com/blog/sync-store-main-renderer-electron),
[part 2](https://www.bigbinary.com/blog/publish-electron-application),
[part 3](https://www.bigbinary.com/blog/video-background-removal),
[part 5](https://www.bigbinary.com/blog/code-sign-notorize-mac-desktop-app),
[part 6](https://www.bigbinary.com/blog/deep-link-electron-app),
[part 7](https://www.bigbinary.com/blog/request-camera-micophone-permission-electron)
[part 8](https://www.bigbinary.com/blog/native-modules-electron) and
[part 9](https://www.bigbinary.com/blog/ev-code-sign-windows-application-ssl-com)
._

When developing desktop applications with Electron, managing multiple browser
windows within a single app is often necessary. Whether we need to display
different types of content or create a more complex user interface, handling
multiple windows efficiently can be challenging.

In this blog, we'll explore how to configure Webpack to manage multiple browser
windows in our Electron application, ensuring that each window operates smoothly
in our project.

### Configuring Webpack for a Single Browser Window

Before diving into the setup for multiple windows, let's first review how to
configure Webpack for a single browser window. This example focuses on the
renderer process, which is responsible for rendering the UI and handling
interactions. If interested in learning how to configure Webpack for the entire
Electron app, including the main process, check out
[this blog](https://www.bigbinary.com/blog/publish-electron-application).

Consider the following typical folder structure for an Electron project:

```js
electron-app
├── assets
├── app
├── src
│   └── main
│     └── main.js
│   └── renderer
│     └── App.jsx
│     └── index.ejs
├── node_modules
├── package.json
```

This structure separates the code for the `main` and `renderer` processes, which
is a standard practice in Electron projects.

Here's how we can configure Webpack for a single browser window:

```js
// ./config/webpack/renderer.mjs

import webpack from "webpack";
import HtmlWebpackPlugin from "html-webpack-plugin";

const configuration = {
  target: ["web", "electron-renderer"],
  entry: "src/renderer/App.jsx",
  output: {
    path: "app/dist/renderer",
    publicPath: "./",
    filename: "renderer.js",
    library: {
      type: "umd",
    },
  },
  module: {...},  // Module configuration (loaders, etc.)
  optimization: {...},  // Optimization settings (minification, etc.)
  plugins: [
    // Other plugins...
    new HtmlWebpackPlugin({
      filename: "app.html",
      template: "src/renderer/index.ejs",
    }),
  ],
};

export default configuration;
```

In this configuration:

- The `target` is set to `["web", "electron-renderer"]`, enabling both standard
  web and Electron renderer environments.
- The `entry` specifies the entry point for the renderer process, which is
  `src/renderer/App.jsx`.
- The output is bundled into a single file named `renderer.js`, which is stored
  in the `app/dist/renderer` directory. In an Electron app, it's often
  preferable to bundle everything into a single file since the files are loaded
  locally.
- The `HtmlWebpackPlugin` generates an `app.html` file from a template
  (`index.ejs`), embedding the necessary script to load `renderer.js`.

We can compile and bundle our frontend code using the following command:

```bash
webpack --config ./config/webpack/renderer.mjs
```

This will produce an `app.html` file in the `app/dist/renderer` directory, along
with `renderer.js`.

```html {7}
<!DOCTYPE html>
<html>
   <head>
      <meta charset=utf-8>
      <meta http-equiv=Content-Security-Policy content="script-src 'self' 'unsafe-inline'">
      <title>MyApp</title>
      <script defer=defer src=./renderer.js></script>
   </head>
   <body>
      <div id=root></div>
   </body>
</html>
```

The `HtmlWebpackPlugin` correctly injects the `<script/>` tag to load
`renderer.js`. This `app.html` can now be loaded into a browser window from the
`main` process.

```js
const appWindow = new BrowserWindow({
  show: false,
  width: 1408,
  height: 896,
});
appWindow.loadURL("app/dist/renderer/app.html");
appWindow.on("ready-to-show", () => {
  appWindow.show();
});
```

### Configuring Webpack for Multiple Browser Windows

With the single window setup complete, let's add another browser window to the
app. For example, let's say we want to create a `Settings.jsx` component within
the renderer folder:

```js {9}
electron-app
├── assets
├── app
├── src
│   └── main
│     └── main.js
│   └── renderer
│     └── App.jsx
│     └── Settings.jsx
│     └── index.ejs
├── node_modules
├── package.json
```

Previously, we bundled all JavaScript code into a single `renderer.js` file.
However, since we're now working with multiple windows, it makes sense to create
separate bundles for each window—one for the `App` window and another for the
`Settings` window. To achieve this, we can specify multiple entry points in
Webpack:

```js {9-10, 15}
// ./config/webpack/renderer.mjs

import webpack from "webpack";
import HtmlWebpackPlugin from "html-webpack-plugin";

const configuration = {
  target: ["web", "electron-renderer"],
  entry: {
    app: "src/renderer/App.jsx",
    settings: "src/renderer/Settings.jsx",
  },
  output: {
    path: "app/dist/renderer",
    publicPath: "./",
    filename: "[name].js", // Use placeholders to generate separate bundles
    library: {
      type: "umd",
    },
  },
  // Other configuration options...
};

export default configuration;
```

In this configuration:

- The `entry` property now contains two entry points: `app` and `settings`.
  Webpack will generate separate bundles for each, named `app.js` and
  `settings.js` respectively.
- The `filename` in the `output` section uses the `[name]` placeholder to
  dynamically generate filenames based on the entry point names.

Next, we need to generate two HTML files—one for each window. We can achieve
this by adding another instance of `HtmlWebpackPlugin` to the `plugins` array:

```js {24-32}
// ./config/webpack/renderer.mjs

import webpack from "webpack";
import HtmlWebpackPlugin from "html-webpack-plugin";

const configuration = {
  target: ["web", "electron-renderer"],
  entry: {
    app: "src/renderer/App.jsx",
    settings:"src/renderer/Settings.jsx"
  },
  output: {
    path: "app/dist/renderer",
    publicPath: "./",
    filename: '[name].js',
    library: {
      type: "umd",
    },
  },
  module: {...},
  optimization: {...},
  plugins: [
    // Other plugins...
    new HtmlWebpackPlugin({
      filename: "app.html",
      template: "src/renderer/index.ejs",
      chunks: ['app'],  // Load only the 'app' bundle
    }),
    new HtmlWebpackPlugin({
      filename: "settings.html",
      template: "src/renderer/index.ejs",
      chunks: ['settings'],  // Load only the 'settings' bundle
    }),
  ],
};

export default configuration;
```

By specifying the `chunks` property for each `HtmlWebpackPlugin` instance, we
ensure that each HTML file only includes the appropriate JavaScript bundle. The
final output will include two HTML files:

```html {8, 22}
<!-- app.html -->
<!DOCTYPE html>
<html>
   <head>
      <meta charset=utf-8>
      <meta http-equiv=Content-Security-Policy content="script-src 'self' 'unsafe-inline'">
      <title>MyApp</title>
      <script defer=defer src=./app.js></script>
   </head>
   <body>
      <div id=root></div>
   </body>
</html>

<!-- settings.html -->
<!DOCTYPE html>
<html>
   <head>
      <meta charset=utf-8>
      <meta http-equiv=Content-Security-Policy content="script-src 'self' 'unsafe-inline'">
      <title>MyApp</title>
      <script defer=defer src=./settings.js></script>
   </head>
   <body>
      <div id=root></div>
   </body>
</html>
```

Finally, from the `main` process, we can easily create two browser windows, each
with its own renderer code:

```js {6, 16}
const appWindow = new BrowserWindow({
  show: false,
  width: 1408,
  height: 896,
});
appWindow.loadURL("app/dist/renderer/app.html");
appWindow.on("ready-to-show", () => {
  appWindow.show();
});

const settingsWindow = new BrowserWindow({
  show: false,
  width: 1408,
  height: 896,
});
settingsWindow.loadURL("app/dist/renderer/settings.html");
settingsWindow.on("ready-to-show", () => {
  settingsWindow.show();
});
```

With this setup, each browser window will load its own dedicated JavaScript
bundle, ensuring that our Electron application is both efficient and modular.
This approach not only makes our code easier to manage but also enhances the
performance of our application by reducing unnecessary code loading.

## Links

- [Human page](https://www.bigbinary.com/blog/electron-multiple-browser-windows)
