Skip to main content

Overview

The Video Compressor is built on Electron, utilizing a multi-process architecture that separates concerns between the main process, renderer process, and preload script. The application integrates FFmpeg for video compression and follows standard Electron security patterns.

Electron process model

1

Main process

The main process (main.js:1-29) manages the application lifecycle and creates browser windows. It runs in a Node.js environment with full system access.
2

Renderer process

The renderer process (renderer.js:1-81) handles the user interface and video compression logic. It has direct Node.js integration enabled.
3

Preload script

The preload script (preload.js:1-11) runs before the renderer process and displays version information for Chrome, Node.js, and Electron.

Main process architecture

The main process in main.js is responsible for creating and managing application windows.

Window creation

The createWindow function configures the browser window with specific security settings:
main.js:5-13
const win = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    preload: path.join(__dirname, 'preload.js'),
    nodeIntegration: true, // Enable Node integration
    contextIsolation: false // Disable context isolation for Node integration
  }
});
Node integration is enabled and context isolation is disabled to allow direct access to Node.js APIs from the renderer process. In production applications, you should use IPC communication instead for better security.

Application lifecycle

The main process manages platform-specific behaviors:
main.js:18-28
app.whenReady().then(() => {
  createWindow();

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

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit();
});
On macOS, the application stays active when all windows are closed, following platform conventions. On other platforms, the app quits automatically.

Renderer process architecture

The renderer process handles all user interactions and video compression operations.

FFmpeg integration

FFmpeg is initialized at the module level:
renderer.js:1-7
const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath = require('ffmpeg-static');
const fs = require('fs');
const os = require('os');
const path = require('path');

ffmpeg.setFfmpegPath(ffmpegPath);
The ffmpeg-static package provides a bundled FFmpeg binary, eliminating the need for users to install FFmpeg separately.

Video compression flow

The compression process follows this sequence:
1

File selection

The user selects a video file using the file input (renderer.js:9-20). The application validates that a file is selected before proceeding.
2

Temporary file creation

The selected file is read as an ArrayBuffer and written to the system’s temporary directory (renderer.js:25-30).
3

FFmpeg processing

FFmpeg compresses the video with configured output options and emits progress events (renderer.js:32-51).
4

Output and cleanup

The compressed video is saved to the videooutputs directory, and temporary files are cleaned up.

Progress tracking

The application provides real-time feedback during compression:
renderer.js:34-38
.on('progress', (progress) => {
  const percent = Math.round(progress.percent);
  progressBar.style.width = percent + '%';
  console.log('Compression progress:', percent + '%');
})

Error handling

Error handling ensures temporary files are cleaned up even when compression fails:
renderer.js:45-50
.on('error', (err) => {
  output.innerText = `Error: ${err.message}`;
  progressBar.style.width = '0%';
  console.error('Compression error:', err);
  fs.unlinkSync(tempPath); // Clean up temporary file
})

Preload script

The preload script displays version information for debugging purposes:
preload.js:1-10
window.addEventListener('DOMContentLoaded', () => {
  const replaceText = (selector, text) => {
    const element = document.getElementById(selector);
    if (element) element.innerText = text;
  };

  for (const dependency of ['chrome', 'node', 'electron']) {
    replaceText(`${dependency}-version`, process.versions[dependency]);
  }
});

IPC communication pattern

The current implementation uses direct Node.js integration rather than IPC. While this simplifies development, you should consider implementing proper IPC communication for production applications to improve security.
With the current architecture:
  • The renderer process has full Node.js access (nodeIntegration: true)
  • Context isolation is disabled (contextIsolation: false)
  • The renderer can directly use require() for Node.js modules

File structure overview

video-compressor/
├── main.js           # Main process entry point
├── renderer.js       # Renderer process logic
├── preload.js        # Preload script
├── index.html        # Application UI
├── styles.css        # Application styles
├── package.json      # Dependencies and metadata
└── videooutputs/     # Compressed video output directory

Core files

Entry point for the Electron main process. Manages window creation, application lifecycle events, and platform-specific behaviors.
Contains all video compression logic, FFmpeg integration, file handling, and UI event listeners. Runs in the renderer process with Node.js integration.
Runs before the renderer process loads. Currently displays version information for Chrome, Node.js, and Electron.
The application’s user interface. Contains file input, compression button, progress bar, and video display container.
Application styling with a dark theme. Defines the visual appearance of all UI components.

Dependencies

The application relies on these key dependencies:
  • electron (v25.0.0): Desktop application framework
  • fluent-ffmpeg (v2.1.2): FFmpeg wrapper for Node.js
  • ffmpeg-static (v5.0.0): Bundled FFmpeg binary
All dependencies are specified in package.json:8-14 and installed via npm.

Build docs developers (and LLMs) love