title: Configure Webpack with Electron to use ES6 imports?
body: <p>I am trying to use <strong>Webpack</strong> since I want to use ES modules in my <strong>Electron</strong> application but having some hurdles. I just want to use <code>import</code> in my <code>main</code> as well as <code>renderer</code> processes.</p>
  
  <p>My application structure is as follows - </p>
  
  <pre><code>- src/                  // contains basic html, css &amp; js
    - index.html          // &lt;h1&gt;Hello World&lt;/h1&gt;
    - style.css           // is empty
    - app.js              // console.log('it works ')
  - app/                  // contains electron code
    - main_window.js
    - custom_tray.js
  - index.js              // entry point for electron application
  - dist/                 // output bundle generated from webpack
    - bundle.js
  </code></pre>
  
  <p>My <code>index.js</code> file looks like - </p>
  
  <pre><code>import path from "path";
  import { app } from "electron";
  
  import MainWindow from "./app/main_window";
  import CustomTray from "./app/custom_tray";
  
  let win = null,
      tray = null;
  
  app.on("ready", () =&gt; {
      // app.dock.hide();
      win = new MainWindow(path.join("file://", __dirname, "/src/index.html"));
  
      win.on("closed", () =&gt; {
          win = null;
      });
  
      tray = new CustomTray(win);
  });
  </code></pre>
  
  <p>My <code>main_window.js</code> file looks like -</p>
  
  <pre><code>import { BrowserWindow } from "electron";
  
  const config = {
      width: 250,
      height: 350,
      show: false,
      frame: false,
      radii: [500, 500, 500, 500],
      resizable: false,
      fullscreenable: false
  };
  
  class MainWindow extends BrowserWindow {
      constructor(url) {
          super(config);
  
          this.loadURL(url);
          this.on("blur", this.onBlur);
          this.show();
      }
  
      onBlur = () =&gt; {
          this.hide();
      };
  }
  
  export default MainWindow;
  </code></pre>
  
  <p>My <code>custom_tray.js</code> looks like -</p>
  
  <pre><code>import path from "path";
  import { app, Tray, Menu } from "electron";
  
  const iconPath = path.join(__dirname, "../src/assets/iconTemplate.png");
  
  class CustomTray extends Tray {
      constructor(mainWindow) {
          super(iconPath);
          this.mainWindow = mainWindow;
  
          this.setToolTip("Thirsty");
  
          this.on("click", this.onClick);
          this.on("right-click", this.onRightClick);
      }
  
      onClick = (event, bounds) =&gt; {
          const { x, y } = bounds;
          const { width, height } = this.mainWindow.getBounds();
  
          const isMac = process.platform === "darwin";
  
          if (this.mainWindow.isVisible()) {
              this.mainWindow.hide();
          } else {
              this.mainWindow.setBounds({
                  x: x - width / 2,
                  y: isMac ? y : y - height,
                  width,
                  height
              });
              this.mainWindow.show();
          }
      };
  
      onRightClick = () =&gt; {
          const menuConfig = Menu.buildFromTemplate([
              {
                  label: "Quit",
                  click: () =&gt; app.quit()
              }
          ]);
          this.popUpContextMenu(menuConfig);
      };
  }
  
  export default CustomTray;
  </code></pre>
  
  <p>And my <code>webpack.main.config.js</code> looks like -</p>
  
  <pre><code>const path = require("path");
  
  const config = {
      entry: "./index.js",
      output: {
          path: path.resolve(__dirname, "dist"),
          filename: "bundle.js"
      },
      module: {
          rules: [{ test: /\.js$/, exclude: /node_modules/, use: "babel-loader" }]
      },
      stats: {
          colors: true
      },
      target: "electron-main",
      devtool: "source-map"
  };
  
  module.exports = config;
  </code></pre>
  
  <p>And my <code>webpack.renderer.config.js</code> looks like -</p>
  
  <pre><code>const path = require("path");
  const HtmlWebpackPlugin = require("html-webpack-plugin");
  const CopyWebpackPlugin = require("copy-webpack-plugin");
  
  const config = {
      entry: "./src/app.js",
      output: {
          path: path.resolve(__dirname, "dist/renderer"),
          filename: "app.js"
      },
      module: {
          rules: [
              {
                  test: /\.js$/,
                  exclude: /node_modules/,
                  use: "babel-loader"
              },
              {
                  test: /\.css$/,
                  use: {
                      loader: "css-loader",
                      options: {
                          minimize: true
                      }
                  }
              },
              {
                  test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                  use: {
                      loader: "url-loader",
                      query: {
                          limit: 10000,
                          name: "imgs/[name].[ext]"
                      }
                  }
              },
              {
                  test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
                  use: {
                      loader: "url-loader",
                      query: {
                          limit: 10000,
                          name: "fonts/[name].[ext]"
                      }
                  }
              }
          ]
      },
      stats: {
          colors: true
      },
      target: "electron-renderer",
      devtool: "source-map",
      plugins: [
          new CopyWebpackPlugin([
              { from: "src/app.css" },
              { from: "src/assets", to: "assets/" }
          ]),
          new HtmlWebpackPlugin({
              filename: "index.html",
              template: path.resolve(__dirname, "./src/index.html"),
              minify: {
                  collapseWhitespace: true,
                  removeAttributeQuotes: true,
                  removeComments: true
              }
          })
      ]
  };
  
  module.exports = config;
  </code></pre>
  
  <p>My <strong>scripts</strong> in <strong>package.json</strong> look like</p>
  
  <pre><code>"scripts": {
      "dev:main": "webpack --mode development --config webpack.main.config.js",
      "dev:renderer": "webpack --mode development --config webpack.renderer.config.js",
      "dev:all": "npm run dev:main &amp;&amp; npm run dev:renderer",
      "build:main": "webpack --mode production --config webpack.main.config.js",
      "build:renderer": "webpack --mode production --config webpack.renderer.config.js",
      "build:all": "npm run build:main &amp;&amp; npm run build:renderer",
      "prestart": "npm run build:all",
      "electron": "electron dist/index.js",
      "start": "npm run electron",
  }
  </code></pre>
  
  <p>Currently my application creates a <strong>dist/bundle.js</strong> but when I run <strong>electron dist/bundle.js</strong> it doesn't work. I get it, it might be because it does not contain <strong>src</strong> folder but when I copy <strong>src</strong> folder into <strong>dist</strong> it still doesn't work.</p>
  
  <p>Firstly, I run <code>npm run dev:main</code> to generate <code>dist/bundle.js</code> then I run <code>npm run dev:renderer</code> to generate <code>dist/renderer/bundle.js</code> &amp; then I run <code>npm run start</code> to start my electron application. </p>
  
  <p>It gives me error "Uncaught Exception: Error: Requires constructor call at new MainWindow" which is in <code>index.js</code> where I call constructor <code>new MainWindow()</code></p>
  
  <p>I just want to use ES6 in all my JS files. Is there any boilerplate because the ones I found have tons of additional stuff like React JS &amp; all plus a huge number of optimizations ?</p>