ITACS
ITACS

Reputation: 93

Uncaught ReferenceError: require is not defined in Electron Js when using require() in html page

I'm new to Electron Js and I am trying to make a custom titlebar as a project. I made the titlebar in a html page called nav.html and imported it in index.html (the main page)

nav.html :

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />


    <title>Document</title>

    <style>
      * {
        margin: 0;
        padding: 0;
      }
      button {
        margin: 0;
        padding: 0;
        border: none;
        outline: none;
        background-color: transparent;
        height: 35px;
      }
      .header {
        background-color: black;
        color: white;
        overflow: hidden;
      }
#title {
        width: 80%;
        -webkit-app-region: drag;
        -webkit-user-select: none;
        user-select: none;
      }
      svg.restore {
        fill: rgb(255, 255, 255) !important;
        width: 15px;
        height: 15px;
        padding: 10px 14px;
      }
      svg.restore:hover {
        fill: rgb(255, 255, 255) !important;
        background-color: #5e5e5e !important;
      }

      button.minimize {
        padding: 3.5px 16px;
        color: white;
      }
      button.minimize:hover {
        background-color: #5e5e5e !important;
      }

      .maximize {
        cursor: default;
        fill: white;
        padding: 10px 14px;
        height: 15px;
        width: 15px;
        display: none;
      }
      .maximize:hover {
        background-color: #5e5e5e !important;
        color: white;
      }

      button.close {
        padding: 3.3px 14px;
        color: white;
      }
      button.close:hover {
        background-color: red !important;
      }
    </style>
  </head>
  <body>
<div
      class="header"
      style="display: flex; align-items: center; justify-content: space-between;"
    >
      <div id="title"></div>
      <div style="display: flex; align-items: center; justify-content: center;">
        <button
          style="font-size: 25px; cursor: default"
          class="minimize"
          id="minimize"
        >
          -
        </button>
        <button>
          <svg
            width="25px"
            height="25px"
            viewBox="0 0 512 512"
            xmlns="http://www.w3.org/2000/svg"
            style="cursor: default"
            class="restore"
            id="restore"
          >
            <path
              d="M352,153H40.247a24.028,24.028,0,0,0-24,24V458a24.028,24.028,0,0,0,24,24H352a24.028,24.028,0,0,0,24-24V177A24.028,24.028,0,0,0,352,153Zm-8,32v45.22H48.247V185ZM48.247,450V262.22H344V450Z"
              class="ci-primary"
            />
            <path
              d="M472,32H152a24.028,24.028,0,0,0-24,24v65h32V64H464V339.143H408v32h64a24.028,24.028,0,0,0,24-24V56A24.028,24.028,0,0,0,472,32Z"
              class="ci-primary"
            />
          </svg>

          <svg
            viewBox="0 0 1024 1024"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            class="maximize"
            id="maximize"
          >
            <path
              d="M896 85.333333H128a42.666667 42.666667 0 0 0-42.666667 42.666667v768a42.666667 42.666667 0 0 0 42.666667 42.666667h768a42.666667 42.666667 0 0 0 42.666667-42.666667V128a42.666667 42.666667 0 0 0-42.666667-42.666667z m-42.666667 768H170.666667V426.666667h682.666666z m0-512H170.666667V170.666667h682.666666z"
            />
          </svg>
        </button>
        <button
          style="font-size: 25px; cursor: default"
          class="close"
          id="close"
        >
          &times;
        </button>
      </div>
    </div>
    <script>
      document.getElementById("title").innerHTML = document.title;
      // ipc connection between main.js and nav.html buttons to mainpulate the function of the window asynchronously
      const { ipcRenderer } = require("electron");
      const ipc = ipcRenderer;

      const restore = document.querySelector("#restore");
      const maximize = document.querySelector("#maximize");
      const minimize = document.querySelector("#minimize");
      const closeBtn = document.querySelector("#close");

      // close the window
      closeBtn.onclick = function(){
        ipc.send("closeApp");
        console.log('mama earth');
      }
      restore.onclick = function () {
        maximize.style.display = "block";
        restore.style.display = "none";
      };
      maximize.onclick = function () {
        restore.style.display = "block";
        maximize.style.display = "none";
      };
    </script>
  </body>
</html>

I have added inline styles as well as style tag and script tag in the same html document

Problem comes when I am not able to use require('electron') in a script tag. I am trying to make the top window buttons and using the ipcRenderer to process them to main.js.

Main.js :

const { app, BrowserWindow , ipcMain} = require('electron')
const path = require('path')
const ipc = ipcMain

function createWindow() {
  const win = new BrowserWindow({
    width: 1200,
    height: 700,
    center: true,
    minHeight: 700,
    minWidth: 1200,
    frame: false,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation : true,
      devTools: true,
      preload: path.join(__dirname, 'preload.js'),
    }
  })

  win.loadFile('index.html')

  //close window function 
  ipc.on('closeApp', () => {
    console.log('app is closed')
    win.close()
  })
}

app.whenReady().then(() => {
  createWindow()

  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow()
    }
  })
})

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

I have just added the index.html and preload.js for no confussion :

index.html :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
    
    <title>Home</title>

    <link rel="stylesheet" href="style.css" />

    <script src="main.js"></script>

</head>
<body>
    <iframe id="nav-placeholder" src="nav.html" width="100%" style="border: none;height: 35px !important;" loading="eager"></iframe>
    <a href="nav.html">Go to nav page</a>
</body>
</html>

Preload.js :

window.addEventListener('DOMContentLoaded', () => {
    const replaceText = (selector, text) => {
      const element = document.getElementById(selector)
      if (element) element.innerText = text
    }
  
    for (const type of ['chrome', 'node', 'electron']) {
      replaceText(`${type}-version`, process.versions[type])
    }
  })

I tried using require JS but I had no idea how to do it. If anyone has an answer to it or can guide me through the error it would be highly appreciatable!

Thank you in advance!

Upvotes: 0

Views: 2658

Answers (2)

reZach
reZach

Reputation: 9489

@Dony is right, in today's Electron world, using require in the HTML page is a big no no. (disclaimer, I wrote the blog post that he's linking to).

I'm curious reading your question, are you looking to create a navigation or a menu? If it's a menu, then Electron has support to do this natively through the Menu class.

You ask a really great question, because setting this up in a secure way requires some communication between the renderer and main processes. My template uses this pattern within the menu to update the app's language, alongside this package.

I unfortunately don't have enough time to thoroughly go into detail at this moment, but will suggest you first take a peak at whether it may be a menu you are looking to add your functionality to. If it is, I hope some of my repository's files can direct you in the place where you can see how to set up the link between the js and the html file within an Electron application.

I'm also currently in the process of writing an "Ultimate Electron guide" that would cover these topics in a thorough blog post. I estimate it's many weeks out as I intend to go in great detail to explain Electron concepts such as this one. It'll be up on https://www.debugandrelease.com/ when I post it (subscribe if you'd like an email when it goes out).

Upvotes: 0

Dony
Dony

Reputation: 1979

You probably read some deprecated articles or forum posts, because calling electron from an HTML file is now an "old way" to use the ipcRenderer.

For security reasons, electron should not be directly accessible from your HTML page. You should only require ipcRenderer from your preload script, where you can put it in a method. Then, you can access your method by sharing it with the contextBridge.

I know this might be confusing at the beginning. You can find a well documented example here about What/How to use the ContextBridge https://github.com/reZach/secure-electron-template/blob/master/docs/newtoelectron.md

Upvotes: 1

Related Questions