1. Thiết Lập Dự Án Cơ Bản
Tạo thư mục và khởi tạo dự án:
mkdir my-electron-app && cd my-electron-app
npm init -y
Chú ý: Should fill in the author and description fields in package.json; leaving them blank can cause packaging failures.
Cập nhật thông tin package.json với entry point là main.js:
{
"name": "electron-app",
"version": "1.0.0",
"description": "Ứng dụng electron đầu tiên",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"author": "Your Name",
"license": "MIT",
"devDependencies": {
"electron": "^31.2.0"
}
}
Cài đặt Electron:
npm install --save-dev electron
Tạo tập tin main.js cơ bản trong thư mục gốc:
console.log('Electron session started');
Khởi chạy với:
npm run start
Nếu thấy tin nhắn trên xuất hiện trên console, module Electron đã hoạt động.
2. Tạo Cửa Sổ Hiển Thị Nội Dung
Tạo cửa sổ trình duyệt để hiển thị nội dung web bên ngoài.
// main.js
const { app, BrowserWindow } = require('electron');
app.on('ready', () => {
const mainWindow = new BrowserWindow({
width: 900,
height: 650,
autoHideMenuBar: true,
webPreferences: {
nodeIntegration: false,
contextIsolation: true
}
});
mainWindow.loadURL('https://example.com/');
});
Nhấn Ctrl+Shift+I để bật Inspector (thanh công cụ phát triển). Dùng Ctrl+R để làm mới trang.
3. Hiển Thị Trang HTML Cục Bộ
Đặt file HTML và CSS trong thư mục pages/.
pages/index.html:
<html>
<head><meta charset="UTF-8">
<title>Trang Electron</title>
</head>
<body><h1>Trang chủ Electron</h1>
<script src="./render.js"></script>
</body>
</html>
Cập nhật main.js để tải tập tin địa phương:
mainWindow.loadFile('./pages/index.html');
4. Các Sự Kiện Lifecycle
Sử dụng app.on() để lắng nghe các sự kiện đặc trưng:
ready: Khi Electron hoàn tất khởi tạo.window-all-closed: Khi tất cả các cửa sổ đã đóng.activate: Khi người dùng kích hoạt ứng dụng (macOS).before-quit / will-quit / quit: Giai đoạn đóng ứng dụng.
5. Xử Lý Trạng Thái Mạng
Xử lý khi kết nối mạng thay đổi trong quá trình chạy ứng dụng:
// Trong render.js
window.addEventListener('online', () => console.log('Đã kết nối mạng'));
window.addEventListener('offline', () => console.log('Mất kết nối mạng'));
Ví dụ hiển thị thông báo đơn giản:
alert('Mất kết nối mạng!');
6. Giao Tiếp Giữa Các Quá Trình
Để an toàn, Electron tách biệt môi trường Node.js và trình duyệt. Có hai cách tiếp cận:
Cách 1: Cho Phép Tích Hợp Node
Trong main.js ở phần webPreferences:
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
Sau đó, trong render.js, dùng Node API trực tiếp:
const fs = require('fs');
document.getElementById('saveBtn').addEventListener('click', () => {
const content = document.getElementById('input').value;
fs.writeFileSync('D:/note.txt', content);
});
Cách 2: Dùng Preload Script (Đề Xuất Ra)
Đặt preloaded script:
// preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('api', {
saveData: (data) => ipcRenderer.send('save', data),
fetchData: () => ipcRenderer.invoke('read')
});
Cấu hình trong main.js:
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
Xử lý IPC trong chính quá trình chủ:
const { ipcMain } = require('electron');
const fs = require('fs');
ipcMain.handle('read', () => fs.readFileSync('D:/note.txt', 'utf8'));
ipcMain.on('save', (_, data) => fs.writeFileSync('D:/note.txt', data));
Gọi từ side rendering:
api.saveData(inputValue);
const saved = await api.fetchData();
7. Tạo Cửa Sổ Phụ
Tạo cửa sổ mới khi người dùng bấm nút:
// trong render.js
document.getElementById('openChild').addEventListener('click', () => {
const win = new BrowserWindow({
width: 500,
height: 400,
parent: remote.getCurrentWindow()
});
win.loadURL('https://subpage.example.com');
});
Lưu ý: Cần cấu hình enableRemoteModule: true nếu dùng phiên bản Electron mới, hoặc thay bằng IPC.
8. System Menu & Context Menu
Tạo menu trong ứng dụng:
// menu.js
const { Menu } = require('electron');
const template = [
{
label: '"Công cụ"',
submenu: [
{ label: '"Mở thiết bị phát triển"', accelerator: 'Ctrl+Shift+I', click(item, win) {
win.webContents.openDevTools();
}},
{ type: 'separator' },
{ label: '"Thoát"', role: 'quit' }
]
}
];
module.exports = Menu.buildFromTemplate(template);
Kết nối trong main.js:
const menu = require('./menu');
Menu.setApplicationMenu(menu);
Menu chuột phải:
const { remote, Menu } = require('electron');
window.addEventListener('contextmenu', (e) => {
e.preventDefault();
const ctxMenu = Menu.buildFromTemplate([
{ label: '"Bản sao"', role: 'copy' },
{ label: '"Dán"', role: 'paste' },
{ type: 'separator' },
{ label: '"Mở Inspector"', click: () => remote.getCurrentWindow().webContents.openDevTools() }
]);
ctxMenu.popup({ window: remote.getCurrentWindow() });
});
9. Shortcut Key Toàn Cục
Đăng ký phím nóng toàn hệ thống:
const { globalShortcut } = require('electron');
app.on('ready', () => {
globalShortcut.register('Ctrl+Shift+F', () => {
console.log('Tìm kiếm toàn ứng dụng đã kích hoạt');
});
});
app.on('will-quit', () => {
globalShortcut.unregisterAll();
});
10. Các Tính Năng Hệ Thống Khác
- Clipboard: dùng
remote.clipboard.writeText()hoặcclipboardmodule. - Open url trong trình duyệt mặc định:
shell.openExternal(url). - Dialog: mở cửa sổ chọn file, lưu file, messagebox với
dialog.showOpenDialog(),dialog.showSaveDialog(),dialog.showMessageBox().
11. Tự Động Tái Khởi Động Khi Phát Triển
Cài đặt nodemon và cấu hình để tự động khởi động lại khi có thay đổi:
npm install --save-dev nodemon
Cập nhật script trong package.json:
"scripts": {
"start": "nodemon --exec electron ."
}
Hoặc dùng file cấu hình nodemon.json để kiểm soát chi tiết hơn:
{
"watch": ["src", "main.js", "renderer.js"],
"ext": "js,json,html,css"
}
12. Đóng Gói Ứng Dụng
Cài đặt electron-builder:
npm install --save-dev electron-builder
Cấu hình trong package.json at build field:
"build": {
"appId": "com.example.myapp",
"asar": true,
"win": {
"target": ["nsis"],
"icon": "build/icon.ico"
},
"nsis": {
"oneClick": false,
"perMachine": true,
"createDesktopShortcut": true
}
}
Thêm dòng script:
"scripts": {
"pack": "electron-builder --dir",
"dist": "electron-builder"
}
Chạy lệnh tạo build cuối:
npm run dist
Kết Luận
Electron cho phép xây dựng ứng dụng desktop đa nền tảng nhanh chóng với kiến trúc web quen thuộc. Hãy ưu tiên IPC thay vì remote để bảo mật cao hơn và hạn chế rủi ro trong môi trường production.