Skip to content

Commit db58222

Browse files
authored
Merge pull request #846 from microsoft/tyriar/electron_example
Update electron example
2 parents 48620be + a31ab6c commit db58222

File tree

8 files changed

+919
-85
lines changed

8 files changed

+919
-85
lines changed

.eslintrc.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ module.exports = {
1111
},
1212
"ignorePatterns": [
1313
"**/typings/*.d.ts",
14-
"scripts/**/*"
14+
"scripts/**/*",
15+
"examples/**/*",
1516
],
1617
"plugins": [
1718
"@typescript-eslint"

examples/electron/README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
1-
This is a minimal example of getting a terminal running in Electron using [node-pty](https://github.com/Tyriar/node-pty) and [xterm.js](https://github.com/sourcelair/xterm.js).
1+
This is a minimal example of getting a terminal running in Electron using [node-pty](https://github.com/microsoft/node-pty) and [xterm.js](https://github.com/xtermjs/xterm.js).
22

33
![](./images/preview.png)
44

5+
It works by using xterm.js on the renderer process and node-pty on the main process with IPC to communicate back and forth.
6+
57
## Usage
68

79
```bash
8-
# Install npm dependencies using Electron's version of V8
9-
./npm_install.sh
10+
# Install dependencies (Windows)
11+
./npm-install.bat
12+
13+
# Install dependencies (non-Windows)
14+
./npm-install.sh
15+
1016
# Launch the app
1117
npm start
1218
```

examples/electron/index.html

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
</head>
88
<body>
99
<div id="xterm"></div>
10+
<script src="./node_modules/xterm/lib/xterm.js"></script>
11+
<script type="module" src="./renderer.js"></script>
1012
</body>
11-
<script>
12-
require('./renderer.js')
13-
</script>
1413
</html>

examples/electron/main.js

Lines changed: 60 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,77 @@
1-
const electron = require('electron')
2-
// Module to control application life.
3-
const app = electron.app
4-
// Module to create native browser window.
5-
const BrowserWindow = electron.BrowserWindow
1+
const { app, BrowserWindow, ipcMain } = require('electron');
2+
const path = require('path');
3+
const os = require('os');
4+
const pty = require('node-pty');
65

7-
const path = require('path')
8-
const url = require('url')
6+
let mainWindow;
7+
let ptyProcess;
98

10-
// Keep a global reference of the window object, if you don't, the window will
11-
// be closed automatically when the JavaScript object is garbage collected.
12-
let mainWindow
13-
14-
// node-pty is not yet context aware
15-
app.allowRendererProcessReuse = false;
16-
17-
function createWindow () {
18-
// Create the browser window.
9+
function createWindow() {
1910
mainWindow = new BrowserWindow({
2011
width: 800,
2112
height: 600,
22-
// Node integration is required to run node-pty in the renderer process
2313
webPreferences: {
24-
nodeIntegration: true
14+
preload: path.join(__dirname, 'preload.js'),
15+
contextIsolation: true,
16+
nodeIntegration: false
2517
}
26-
})
18+
});
2719

28-
// and load the index.html of the app.
29-
mainWindow.loadURL(url.format({
30-
pathname: path.join(__dirname, 'index.html'),
31-
protocol: 'file:',
32-
slashes: true
33-
}))
20+
mainWindow.loadFile('index.html');
3421

35-
// Open the DevTools.
36-
// mainWindow.webContents.openDevTools()
37-
38-
// Emitted when the window is closed.
39-
mainWindow.on('closed', function () {
40-
// Dereference the window object, usually you would store windows
41-
// in an array if your app supports multi windows, this is the time
42-
// when you should delete the corresponding element.
43-
mainWindow = null
44-
})
22+
mainWindow.on('closed', () => {
23+
if (ptyProcess) {
24+
ptyProcess.kill();
25+
ptyProcess = null;
26+
}
27+
mainWindow = null;
28+
});
4529
}
4630

47-
// This method will be called when Electron has finished
48-
// initialization and is ready to create browser windows.
49-
// Some APIs can only be used after this event occurs.
50-
app.on('ready', createWindow)
31+
// Handle pty spawn request from renderer
32+
ipcMain.on('pty-spawn', () => {
33+
if (ptyProcess) return;
34+
35+
const shell = process.env[os.platform() === 'win32' ? 'COMSPEC' : 'SHELL'];
36+
ptyProcess = pty.spawn(shell, [], {
37+
name: 'xterm-256color',
38+
cols: 80,
39+
rows: 30,
40+
cwd: process.env.HOME || process.env.USERPROFILE,
41+
env: process.env
42+
});
43+
44+
ptyProcess.onData(data => {
45+
if (mainWindow && !mainWindow.isDestroyed()) {
46+
mainWindow.webContents.send('pty-data', data);
47+
}
48+
});
49+
});
5150

52-
// Quit when all windows are closed.
53-
app.on('window-all-closed', function () {
54-
// On OS X it is common for applications and their menu bar
55-
// to stay active until the user quits explicitly with Cmd + Q
51+
// Handle pty input from renderer
52+
ipcMain.on('pty-write', (_, data) => {
53+
if (ptyProcess) {
54+
ptyProcess.write(data);
55+
}
56+
});
57+
58+
// Handle resize from renderer
59+
ipcMain.on('pty-resize', (_, { cols, rows }) => {
60+
if (ptyProcess) {
61+
ptyProcess.resize(cols, rows);
62+
}
63+
});
64+
65+
app.whenReady().then(createWindow);
66+
67+
app.on('window-all-closed', () => {
5668
if (process.platform !== 'darwin') {
57-
app.quit()
69+
app.quit();
5870
}
59-
})
71+
});
6072

61-
app.on('activate', function () {
62-
// On OS X it's common to re-create a window in the app when the
63-
// dock icon is clicked and there are no other windows open.
73+
app.on('activate', () => {
6474
if (mainWindow === null) {
65-
createWindow()
75+
createWindow();
6676
}
67-
})
68-
69-
// In this file you can include the rest of your app's specific main process
70-
// code. You can also put them in separate files and require them here.
77+
});

0 commit comments

Comments
 (0)