Skip to content

Electron - Native Node Libraries

Electron - Leveraging Node.js Native Modules

Section titled “Electron - Leveraging Node.js Native Modules”

In Electron, you have full access to Node.js built-in modules, allowing you to interact with the operating system, file system, network, and more, directly from your desktop application. We previously explored the fs (File System) module. Let’s look at other useful Node.js modules.

The os module provides operating system-related utility methods and properties. This is invaluable for tailoring your application’s behavior or appearance based on the user’s environment.

Method/PropertyDescription
os.userInfo([options])Returns an object containing information about the current user, such as username, user ID, group ID, home directory, and default shell. Useful for personalization or user-specific configurations.
os.platform()Returns a string identifying the operating system platform, e.g., 'darwin' (macOS), 'win32' (Windows), 'linux'. Essential for platform-specific logic.
os.homedir()Returns the string path of the current user’s home directory. Ideal for storing user-specific application data or configurations.
os.arch()Returns a string identifying the CPU architecture, e.g., 'x64', 'arm64'. Can be used to provide architecture-specific binaries or optimizations.
os.EOLA string constant defining the operating system-specific end-of-line marker (e.g., \n on Linux/macOS, \r\n on Windows). Use this for cross-platform compatibility when writing text files.

To display this information in your Electron app, you’ll typically create a main process (main.js) to set up the BrowserWindow and a renderer process (HTML file) to display the content. For security, it’s best practice to expose Node.js modules to the renderer process selectively using a preload script and contextBridge.

Here’s an example. First, your main.js:

const { app, BrowserWindow } = require('electron');
const path = require('path');
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
// contextIsolation is true by default and recommended
// nodeIntegration is false by default and recommended
}
});
win.loadFile('index.html');
}
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});

Next, create a preload.js file in the same directory:

const { contextBridge } = require('electron');
const os = require('os');
contextBridge.exposeInMainWorld('electronOS', {
getUserInfo: () => os.userInfo(),
getPlatform: () => os.platform(),
getHomedir: () => os.homedir(),
getArch: () => os.arch(),
getEOL: () => os.EOL
});

Finally, your index.html:

<!DOCTYPE html>
<html>
<head>
<title>OS Module Info</title>
<meta charset="UTF-8">
</head>
<body>
<h1>Operating System Information</h1>
<div id="os-info">Loading...</div>
<script>
const osInfoDiv = document.getElementById('os-info');
try {
const userInfo = window.electronOS.getUserInfo();
const platform = window.electronOS.getPlatform();
const homedir = window.electronOS.getHomedir();
const arch = window.electronOS.getArch();
osInfoDiv.innerHTML =
`User Info: ${JSON.stringify(userInfo, null, 2)}<br><br>` +
`Platform: ${platform}<br>` +
`User Home Directory: ${homedir}<br>` +
`OS Architecture: ${arch}`;
} catch (error) {
osInfoDiv.textContent = 'Error accessing OS information. Make sure preload script is configured correctly.';
console.error('Error accessing OS info via contextBridge:', error);
}
</script>
</body>
</html>

Run your app using the command:

$ electron .

The application window will display system information. For example, on a Linux system, you might see:

User Info: {
"uid": 1000,
"gid": 1000,
"username": "youruser",
"homedir": "/home/youruser",
"shell": "/bin/bash"
}
Platform: linux
User Home Directory: /home/youruser
OS Architecture: x64

(Note: The actual output will vary based on your operating system and user configuration.)

The net module provides an asynchronous network API for creating TCP servers and clients (streams-based sockets). While Electron apps often use higher-level protocols like HTTP/HTTPS (with fetch API or libraries like axios) or WebSockets for client-server communication, the net module is useful for direct TCP socket programming, peer-to-peer connections, or interacting with specific network services.

Key methods from the net module include:

Method/ClassDescription
net.createServer([options][, connectionListener])Creates a new TCP server. The connectionListener function is automatically set as a listener for the 'connection' event, which fires when a new client connects.
net.createConnection(options[, connectionListener]) / net.connect(options[, connectionListener])Creates a new net.Socket and initiates a connection to the specified address and port. Returns the socket.
net.Server.listen(port[, host][, backlog][, callback])Starts the server, making it listen for connections on the specified port and host. If host is omitted, the server accepts connections on any IPv4/IPv6 address.
net.Server.close([callback])Stops the server from accepting new connections. Existing connections are allowed to finish. The server emits a 'close' event when all connections are ended.
net.Socket.connect(port[, host][, connectListener])Opens the connection for a given socket instance. If port and host are given, the socket connects as a TCP client.
net.Socket.write(data[, encoding][, callback])Sends data on the socket.
net.Socket.on('data', listener)Event emitted when data is received from the other end of the socket.

For comprehensive details, refer to the official Node.js net module documentation.

Let’s illustrate with an Electron app acting as a TCP client connecting to a simple Node.js TCP server. First, create server.js (run this with Node.js, not Electron):

const net = require('net');
const server = net.createServer((connection) => {
console.log('Client Connected');
connection.on('end', () => {
console.log('Client disconnected');
});
connection.on('error', (err) => {
console.error('Connection error:', err.message);
});
connection.write('Hello from TCP Server!\r\n');
// Echo back anything received
connection.pipe(connection);
});
const PORT = 8080;
server.listen(PORT, () => {
console.log(`TCP Server running on port ${PORT}`);
});

Use the same main.js as in the OS module example (which sets up a BrowserWindow and loads index.html). Update index.html for the TCP client functionality:

<!DOCTYPE html>
<html>
<head>
<title>Net Module Client</title>
<meta charset="UTF-8">
</head>
<body>
<h1>TCP Client</h1>
<div id="status">Connecting...</div>
<pre id="messages"></pre>
<script>
// IMPORTANT: Directly using 'require("net")' in the renderer
// requires 'nodeIntegration: true' in BrowserWindow webPreferences.
// This is generally discouraged for security reasons.
// For production apps, consider performing network operations in the
// main process and communicating with the renderer via IPC and preload scripts.
// For this educational example, we assume nodeIntegration might be enabled,
// or this script is adapted for a preload context.
// If using a preload script with contextBridge, you would expose 'net' functionalities.
// Example (conceptual, assuming 'electronNet' exposed via contextBridge):
// const client = window.electronNet.connect({ port: 8080 });
// Direct usage (requires nodeIntegration: true or execution in a Node-enabled environment):
try {
const net = require('net');
const statusDiv = document.getElementById('status');
const messagesPre = document.getElementById('messages');
const client = net.connect({ port: 8080 }, () => {
console.log('Connection established with server!');
statusDiv.textContent = 'Connected to server!';
client.write('Hello server from Electron client!\r\n');
});
client.on('data', (data) => {
console.log('Data from server:', data.toString());
messagesPre.textContent += data.toString();
// For this example, let's end after first message from server.
// client.end();
});
client.on('end', () => {
console.log('Disconnected from server');
statusDiv.textContent = 'Disconnected from server.';
});
client.on('error', (err) => {
console.error('Connection error:', err.message);
statusDiv.textContent = `Connection Error: ${err.message}`;
});
} catch (error) {
document.getElementById('status').textContent =
'Error: Could not load net module. Ensure Node integration is enabled or use a preload script.';
console.error(error);
}
</script>
</body>
</html>

To run this:

  1. Start the TCP server: node server.js in your terminal.
  2. Run the Electron application: electron . in your terminal (in the project directory).

The Electron app window will attempt to connect to the server. If successful, it will display “Connected to server!” and then any messages received from the server, such as “Hello from TCP Server!”. The server console will log client connections and disconnections.

While direct use of net in the renderer is shown for simplicity, remember that for robust and secure applications, network operations are often better handled in the main process or a utility process, with results communicated to the renderer via IPC.