javascripthtmldirectoryelectron

How to use a relative path in a parent folder in electron app?


How do I use a relative path without specifying a specific drive in my electron app? I need to use something like SRC="/FILE.HTML" so my app will work on any drive installed not just a specific location. I know ./ and ../ go to previous parent folders but how can I go a few more directories back? I've seen things like %appdir%/MAIN DIR/SUB DIR/FILE.HTML, however I'm not sure how that works? Maybe I can setup some kind of variable to use in my path like that? So far I've only been able to use direct paths to go to files in previous folder which constricts my software to a specific drive.

Example: MAIN DIR/SUB DIR/FILE.HTML

EDIT: My electron app isnt displaying my Main.html. I think it has to do with my paths but im not sure?

enter image description here

enter image description here

enter image description here

enter image description here


Solution

  • Using absolute paths will cause you issues, especially during / after build process. Your Electron application would be built referencing files in the wrong directories. Relevant file reference is the way to go here.

    IMPORTANT: I am seeing a lot of inconsistent directory naming and file references in your directory structure. EG: Main.html is in your JAVASCRIPT directory. Main.js (not your application entry point) is not shown in your directory structure. Same for your Index.css file. As a result, answering this question accurately is difficult due to the many "norms" usually found in project structure and naming conventions. Comment at the bottom of this answer for more information / help.


    Within your package.json file, the "main": "..." line is the entry point to your application. As this is relative to your project root and your Main.js file is at your project root, your entry point will be "Main.js"

    PS: "electron" doesn't need to be a dependency, only a devDependency.

    package.json (project root)

    {
        "name": "electron.menu",
        "version": "00.00.01",
        "description": "Electron Menu Portable Start Menu",
        "main": "Main.js"
        "scripts": {
            "start": "electron .",
            "test": "echo \"Error: no test specified\" && exit 1"
        },
        "keywords": [],
        "author": "Armored Security Group",
        "license": "MIT",
        "devDependencies": {
            "electron": "^19.0.6"
        }
    }
    

    Within your Main.js file, the path to your index.html file, or in your case, your Main.html file, is again, relative (this time to the Main.js file as this is the file requiring it).

    Using Node's path.join([...path]); method (as you have) will place you in good stead.

    Note the use of win.loadFile(...) instead of win.loadURL(...)

    Main.js (main process)

    const { app, BrowserWindow } = require('electron');
    const url = require('url');
    const path = require('path');
    
    let win
    
    function createWindow() {
        win = new BrowserWindow({
            width: 800,
            height: 600
        });
        
        win.loadFile(path.join(__dirname, 'ROOT.ASSETS/CODE.FILES/JAVASCRIPT/Main.html'));
        
        return win;
    }
    
    app.on('ready', () => {
        win = createWindow();
    });
    

    Lastly, within your Main.html file, all paths will be relevant to the file itself. IE: Main.html.

    That said, I don't see Main.js within your ROOT.ASSETS/CODE.FILES/JAVASCRIPT directory.

    Additionally, I don't see Index.css within your ROOT.ASSETS/CODE.FILES/ STYLESHEET /INDEX.STYLE directory.

    PS: Place your Javascript file(s) after the closing tag of your </body> element. That way, you do not need to defer and your script(s) will always have a full DOM to work with (unless you need to make an update to your DOM before the page is rendered).

    ROOT.ASSETS/CODE.FILES/JAVASCRIPT/Main.html (render process)

    <!DOCTYPE html>
    <html lang="en-us">
        <head>
            <meta charset="UTF-8">
            <title>Electron Menu</title>
            <link rel="stylesheet" type="text/css" href="../STYLESHEET/INDEX.STYLE/Index.css" />
        </head>
        
        <body>
            ...
        </body>
        
        <script src="/Main.js"></script>
    </html>
    

    PS: One final note, there is no real need to have directory names or file name use upper case unless you are using camelCase.


    Update

    Relative & Absolute Paths

    Path reference is different between file systems and internet URL's

    File Systems

    For our file systems example we will use:

    D:/
    └── path
        └── to
            └── my
                ├── first
                |   └── file.txt
                └── second
                    └── file.txt
    

    Absolute Paths

    Absolute paths are paths that refer to the whole file path. They are absolute.

    D:/path/to/my/first/file.txt
    D:/path/to/my/second/file.txt
    

    Let's say are are somewhere in the D:/ drive. You could be anywhere.

    To get to your "first" file you would use the full path to the first text file.

    D:/path/to/my/first/file.txt
    

    Alternatively, you could use

    /path/to/my/first/file.txt
    

    This will take you to the same location if you are already in the D:/ drive. If you are in another drive, it will take you to the absolute path in that drive instead.

    To get to your "second" file you would use the full path to the second text file.

    D:/path/to/my/second/file.txt
    

    or

    /path/to/my/second/file.txt
    

    Relative Paths

    Relative paths are paths that refer to a point in the file system from another point in the file system.

    Let's say we open a console starting at the D:/ directory. IE: The root of the D:/ drive.

    D:/
    

    To get to your "first" file you would use the path to the first text file. The reference will always start from the current directory. In this case, it happens to be the root of the D:/ drive.

    path/to/my/first/text.file
    

    From here, to get to your "second" file, you will need to move up one directory level ../, which will take you to path/to/my. From here you then need to move down into the second directory to the second text file.

    ../second/file.txt
    

    If you want to go to the root of the drive that you are currently in (without worrying about what drive you are in) use /.

    /
    

    This will take you back to:

    D:/
    

    Linux also has ./ which is used to reference a relative path.

    Internet URL's

    Similar to file systems, but used when referencing URL addresses.

    For our Internet URL's example we will use:

    www.example.com
    └── path
        └── to
            └── my
                ├── cool
                |   └── page.html
                └── other-cool
                    └── page.html
    

    Absolute URL

    https://www.example.com/path/to/my/cool/page.html
    

    Relative URL

    Let's navigate to another page without using the absolute URL to the other page.

    ../other-cool/page.html
    

    As we are already in the cool path, this takes us up one level to my and back down through other-cool to page.html.

    IE:

    https://www.example.com/path/to/my/other-cool/page.html
    

    To move up two levels from here, would would use

    ../../
    

    Which would take us to

    https://www.example.com/path/to
    

    Typical Electron Folder Structure

    After we finish coding our Electron application, we "build" it. Our newly "built" code must be placed in a different directory to that of our "source" code else we would overwrite our source code.

    Thus we will use the dist and src names as folder names.

    build is often used as an intermediary to hold specific OS architecture output during the build process.

    Project Root
    ├── build
    ├── dist
    ├── node_modules
    ├── src
    ├── tests
    ├── .gitignore
    ├── package.json
    └── package-lock.json
    

    As a personal preference, I then split my src folder into directories / files like below.

    src
    ├── main-process
    |   ├── dialogs
    |   ├── localization
    |   ├── menus
    |   |   ├── main-menu.js
    |   |   └── tray-menu.js
    |   ├── preferences
    |   ├── windows
    |   |   └── main-window.js
    |   ├── main.js
    |   └── preload.js
    ├── render-process
    |   ├── css
    |   |   └── index.css
    |   ├── html
    |   |   └── index.html
    |   ├── images
    |   └── js
    |       └── index.js
    └── config.json 
    

    Therefore, a basic package.json file would refer to your main entry file main.js like this.

    package.json

    {
      "name": "myApp",
      "productName": "My cool application",
      "version": "1.0.0",
      "main": "src/main-process/main.js"
      "scripts": {
        "watch": "",
        "start": "electron .",
        "lint": "",
        "unit-test": ",
        "clean": "",
        "bundle-win": "electron-packager ./ server-x --overwrite --out=build/bundles --platform=win32 --arch=all --prune=true --asar --icon='./src/render-process/images/icons/icon.png'",
        "dist-win": "electron-builder --windows ",
        "release": ""
      },
      "devDependencies": {
        "electron": "^19.0.0",
        "electron-builder": "^23.0.0",
        "electron-packager": "^15.0.0"
      }
    }
    

    Your main.js file would look like this.

    main.js (main process)

    const { app, BrowserWindow } = require('electron');
    const url = require('url');
    const path = require('path');
    
    let win
    
    function createWindow() {
        win = new BrowserWindow({
            width: 800,
            height: 600
        });
        
        win.loadFile(path.join(__dirname, '../render-process/html/index.html'));
        
        return win;
    }
    
    app.on('ready', () => {
        win = createWindow();
    });
    

    And finally, your index.html file would look like this.

    index.html (render process)

    <!DOCTYPE html>
    <html lang="en-us">
        <head>
            <meta charset="UTF-8">
            <title>Electron Menu</title>
            <link rel="stylesheet" type="text/css" href="../css/index.css" />
        </head>
        
        <body>
            ...
        </body>
        
        <script src="../js/index.js"></script>
    </html>