Switch to node-pty-prebuilt-multiarch and upgrade Electron

This commit is contained in:
Mohammad Fares
2022-09-05 20:54:57 +02:00
parent 3679e17d68
commit be7b1533d7
9 changed files with 3211 additions and 292 deletions

5
.prettierrc Normal file
View File

@@ -0,0 +1,5 @@
{
"semi": true,
"singleQuote": true,
"printWidth": 120
}

2
app.js
View File

@@ -41,7 +41,7 @@ di.require('progress', 'ProgressBar');
di.require('gif-encoder', 'GIFEncoder'); di.require('gif-encoder', 'GIFEncoder');
di.require('inquirer'); di.require('inquirer');
di.set('pty', require('@faressoft/node-pty-prebuilt')); di.set('pty', require('node-pty-prebuilt-multiarch'));
di.set('PNG', require('pngjs').PNG); di.set('PNG', require('pngjs').PNG);
di.set('spawn', require('child_process').spawn); di.set('spawn', require('child_process').spawn);
di.set('utility', require('./utility.js')); di.set('utility', require('./utility.js'));

View File

@@ -13,12 +13,16 @@
* @return {ProgressBar} * @return {ProgressBar}
*/ */
function getProgressBar(operation, framesCount) { function getProgressBar(operation, framesCount) {
return new di.ProgressBar(
return new di.ProgressBar(operation + ' ' + di.chalk.magenta('frame :current/:total') + ' :percent [:bar] :etas', { operation +
" " +
di.chalk.magenta("frame :current/:total") +
" :percent [:bar] :etas",
{
width: 30, width: 30,
total: framesCount total: framesCount,
}); }
);
} }
/** /**
@@ -28,22 +32,21 @@ function getProgressBar(operation, framesCount) {
* @return {Promise} * @return {Promise}
*/ */
function writeRecordingData(recordingFile) { function writeRecordingData(recordingFile) {
return new Promise(function (resolve, reject) {
return new Promise(function(resolve, reject) {
// Write the data into data.json file in the root path of the app // Write the data into data.json file in the root path of the app
di.fs.writeFile(di.path.join(ROOT_PATH, 'render/data.json'), JSON.stringify(recordingFile.json), 'utf8', function(error) { di.fs.writeFile(
di.path.join(ROOT_PATH, "render/data.json"),
JSON.stringify(recordingFile.json),
"utf8",
function (error) {
if (error) { if (error) {
return reject(error); return reject(error);
} }
resolve(); resolve();
}
);
}); });
});
} }
/** /**
@@ -53,29 +56,21 @@ function writeRecordingData(recordingFile) {
* @return {Promise} resolve with the parsed PNG image * @return {Promise} resolve with the parsed PNG image
*/ */
function loadPNG(path) { function loadPNG(path) {
return new Promise(function (resolve, reject) {
return new Promise(function(resolve, reject) { di.fs.readFile(path, function (error, imageData) {
di.fs.readFile(path, function(error, imageData) {
if (error) { if (error) {
return reject(error); return reject(error);
} }
new di.PNG().parse(imageData, function(error, data) { new di.PNG().parse(imageData, function (error, data) {
if (error) { if (error) {
return reject(error); return reject(error);
} }
resolve(data); resolve(data);
}); });
}); });
}); });
} }
/** /**
@@ -84,20 +79,16 @@ function loadPNG(path) {
* @return {Promise} * @return {Promise}
*/ */
function getFrameDimensions() { function getFrameDimensions() {
// The path of the first rendered frame // The path of the first rendered frame
var framePath = di.path.join(ROOT_PATH, 'render/frames/0.png'); var framePath = di.path.join(ROOT_PATH, "render/frames/0.png");
// Read and parse a PNG image file // Read and parse a PNG image file
return loadPNG(framePath).then(function(png) { return loadPNG(framePath).then(function (png) {
return {
return({
width: png.width, width: png.width,
height: png.height height: png.height,
};
}); });
});
} }
/** /**
@@ -108,25 +99,29 @@ function getFrameDimensions() {
* @return {Promise} * @return {Promise}
*/ */
function renderFrames(records, options) { function renderFrames(records, options) {
return new Promise(function (resolve, reject) {
return new Promise(function(resolve, reject) {
// The number of frames // The number of frames
var framesCount = records.length; var framesCount = records.length;
// Create a progress bar // Create a progress bar
var progressBar = getProgressBar('Rendering', Math.ceil(framesCount / options.step)); var progressBar = getProgressBar(
"Rendering",
Math.ceil(framesCount / options.step)
);
// Execute the rendering process // Execute the rendering process
var render = di.spawn(di.electron, [di.path.join(ROOT_PATH, 'render/index.js'), options.step], {detached: false}); var render = di.spawn(
di.electron,
[di.path.join(ROOT_PATH, "render/index.js"), options.step],
{ detached: false }
);
render.stderr.on('data', function(error) { render.stderr.on("data", function (error) {
render.kill(); render.kill();
reject(new Error(error)); reject(new Error(error));
}); });
render.stdout.on('data', function(data) { render.stdout.on("data", function (data) {
// Is not a recordIndex (to skip Electron's logs or new lines) // Is not a recordIndex (to skip Electron's logs or new lines)
if (di.is.not.number(parseInt(data.toString()))) { if (di.is.not.number(parseInt(data.toString()))) {
return; return;
@@ -138,11 +133,8 @@ function renderFrames(records, options) {
if (progressBar.complete) { if (progressBar.complete) {
resolve(); resolve();
} }
}); });
}); });
} }
/** /**
@@ -154,9 +146,7 @@ function renderFrames(records, options) {
* @return {Promise} * @return {Promise}
*/ */
function mergeFrames(records, options, frameDimensions) { function mergeFrames(records, options, frameDimensions) {
return new Promise(function (resolve, reject) {
return new Promise(function(resolve, reject) {
// The number of frames // The number of frames
var framesCount = records.length; var framesCount = records.length;
@@ -164,11 +154,14 @@ function mergeFrames(records, options, frameDimensions) {
var stepsCounter = 0; var stepsCounter = 0;
// Create a progress bar // Create a progress bar
var progressBar = getProgressBar('Merging', Math.ceil(framesCount / options.step)); var progressBar = getProgressBar(
"Merging",
Math.ceil(framesCount / options.step)
);
// The gif image // The gif image
var gif = new di.GIFEncoder(frameDimensions.width, frameDimensions.height, { var gif = new di.GIFEncoder(frameDimensions.width, frameDimensions.height, {
highWaterMark: 5 * 1024 * 1024 highWaterMark: 5 * 1024 * 1024,
}); });
// Pipe // Pipe
@@ -184,8 +177,9 @@ function mergeFrames(records, options, frameDimensions) {
gif.writeHeader(); gif.writeHeader();
// Foreach frame // Foreach frame
di.async.eachOfSeries(records, function(frame, index, callback) { di.async.eachOfSeries(
records,
function (frame, index, callback) {
if (stepsCounter != 0) { if (stepsCounter != 0) {
stepsCounter = (stepsCounter + 1) % options.step; stepsCounter = (stepsCounter + 1) % options.step;
return callback(); return callback();
@@ -194,11 +188,15 @@ function mergeFrames(records, options, frameDimensions) {
stepsCounter = (stepsCounter + 1) % options.step; stepsCounter = (stepsCounter + 1) % options.step;
// The path of the rendered frame // The path of the rendered frame
var framePath = di.path.join(ROOT_PATH, 'render/frames', index + '.png'); var framePath = di.path.join(
ROOT_PATH,
"render/frames",
index + ".png"
);
// Read and parse the rendered frame // Read and parse the rendered frame
loadPNG(framePath).then(function(png) { loadPNG(framePath)
.then(function (png) {
progressBar.tick(); progressBar.tick();
// Set the duration (the delay of the next frame) // Set the duration (the delay of the next frame)
@@ -211,15 +209,12 @@ function mergeFrames(records, options, frameDimensions) {
// Next // Next
callback(); callback();
})
}).catch(function(error) { .catch(function (error) {
callback(error); callback(error);
}); });
},
}, function(error) { function (error) {
if (error) { if (error) {
return reject(error); return reject(error);
} }
@@ -227,12 +222,9 @@ function mergeFrames(records, options, frameDimensions) {
// Write the footer // Write the footer
gif.finish(); gif.finish();
resolve(); resolve();
}
);
}); });
});
} }
/** /**
@@ -241,21 +233,15 @@ function mergeFrames(records, options, frameDimensions) {
* @return {Promise} * @return {Promise}
*/ */
function cleanup() { function cleanup() {
return new Promise(function (resolve, reject) {
return new Promise(function(resolve, reject) { di.fs.emptyDir(di.path.join(ROOT_PATH, "render/frames"), function (error) {
di.fs.emptyDir(di.path.join(ROOT_PATH, 'render/frames'), function(error) {
if (error) { if (error) {
return reject(error); return reject(error);
} }
resolve(); resolve();
}); });
}); });
} }
/** /**
@@ -264,12 +250,10 @@ function cleanup() {
* @param {String} outputFile the path of the rendered image * @param {String} outputFile the path of the rendered image
*/ */
function done(outputFile) { function done(outputFile) {
console.log("\n" + di.chalk.green("Successfully Rendered"));
console.log('\n' + di.chalk.green('Successfully Rendered')); console.log("The animated GIF image is saved into the file:");
console.log('The animated GIF image is saved into the file:');
console.log(di.chalk.magenta(outputFile)); console.log(di.chalk.magenta(outputFile));
process.exit(); process.exit();
} }
/** /**
@@ -278,7 +262,6 @@ function done(outputFile) {
* @param {Object} argv * @param {Object} argv
*/ */
function command(argv) { function command(argv) {
// Frames // Frames
var records = argv.recordingFile.json.records; var records = argv.recordingFile.json.records;
var config = argv.recordingFile.json.config; var config = argv.recordingFile.json.config;
@@ -287,17 +270,20 @@ function command(argv) {
var framesCount = records.length; var framesCount = records.length;
// The path of the output file // The path of the output file
var outputFile = di.utility.resolveFilePath('render' + (new Date()).getTime(), 'gif'); var outputFile = di.utility.resolveFilePath(
"render" + new Date().getTime(),
"gif"
);
// For adjusting (calculating) the frames delays // For adjusting (calculating) the frames delays
var adjustFramesDelaysOptions = { var adjustFramesDelaysOptions = {
frameDelay: config.frameDelay, frameDelay: config.frameDelay,
maxIdleTime: config.maxIdleTime maxIdleTime: config.maxIdleTime,
}; };
// For rendering the frames into PNG images // For rendering the frames into PNG images
var renderingOptions = { var renderingOptions = {
step: argv.step step: argv.step,
}; };
// For merging the rendered frames into an animated GIF image // For merging the rendered frames into an animated GIF image
@@ -305,7 +291,7 @@ function command(argv) {
quality: config.quality, quality: config.quality,
repeat: config.repeat, repeat: config.repeat,
step: argv.step, step: argv.step,
outputFile: outputFile outputFile: outputFile,
}; };
// Overwrite the quality of the rendered image // Overwrite the quality of the rendered image
@@ -320,8 +306,8 @@ function command(argv) {
} }
// Tasks // Tasks
di.asyncPromises.waterfall([ di.asyncPromises
.waterfall([
// Remove all previously rendered frames // Remove all previously rendered frames
cleanup, cleanup,
@@ -332,7 +318,11 @@ function command(argv) {
di._.partial(renderFrames, records, renderingOptions), di._.partial(renderFrames, records, renderingOptions),
// Adjust frames delays // Adjust frames delays
di._.partial(di.commands.play.adjustFramesDelays, records, adjustFramesDelaysOptions), di._.partial(
di.commands.play.adjustFramesDelays,
records,
adjustFramesDelaysOptions
),
// Get the dimensions of the first rendered frame // Get the dimensions of the first rendered frame
di._.partial(getFrameDimensions), di._.partial(getFrameDimensions),
@@ -341,14 +331,12 @@ function command(argv) {
di._.partial(mergeFrames, records, mergingOptions), di._.partial(mergeFrames, records, mergingOptions),
// Delete the temporary rendered PNG images // Delete the temporary rendered PNG images
cleanup cleanup,
])
]).then(function() { .then(function () {
done(outputFile); done(outputFile);
})
}).catch(di.errorHandler); .catch(di.errorHandler);
} }
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
@@ -359,13 +347,13 @@ function command(argv) {
* Command's usage * Command's usage
* @type {String} * @type {String}
*/ */
module.exports.command = 'render <recordingFile>'; module.exports.command = "render <recordingFile>";
/** /**
* Command's description * Command's description
* @type {String} * @type {String}
*/ */
module.exports.describe = 'Render a recording file as an animated gif image'; module.exports.describe = "Render a recording file as an animated gif image";
/** /**
* Command's handler function * Command's handler function
@@ -378,39 +366,37 @@ module.exports.handler = command;
* *
* @param {Object} yargs * @param {Object} yargs
*/ */
module.exports.builder = function(yargs) { module.exports.builder = function (yargs) {
// Define the recordingFile argument // Define the recordingFile argument
yargs.positional('recordingFile', { yargs.positional("recordingFile", {
describe: 'The recording file', describe: "The recording file",
type: 'string', type: "string",
coerce: di.utility.loadYAML coerce: di.utility.loadYAML,
}); });
// Define the output option // Define the output option
yargs.option('o', { yargs.option("o", {
alias: 'output', alias: "output",
type: 'string', type: "string",
describe: 'A name for the output file', describe: "A name for the output file",
requiresArg: true, requiresArg: true,
coerce: di._.partial(di.utility.resolveFilePath, di._, 'gif') coerce: di._.partial(di.utility.resolveFilePath, di._, "gif"),
}); });
// Define the quality option // Define the quality option
yargs.option('q', { yargs.option("q", {
alias: 'quality', alias: "quality",
type: 'number', type: "number",
describe: 'The quality of the rendered image (1 - 100)', describe: "The quality of the rendered image (1 - 100)",
requiresArg: true requiresArg: true,
}); });
// Define the quality option // Define the quality option
yargs.option('s', { yargs.option("s", {
alias: 'step', alias: "step",
type: 'number', type: "number",
describe: 'To reduce the number of rendered frames (step > 1)', describe: "To reduce the number of rendered frames (step > 1)",
requiresArg: true, requiresArg: true,
default: 1 default: 1,
}); });
}; };

View File

@@ -14,8 +14,8 @@
"terminalizer": "bin/app.js" "terminalizer": "bin/app.js"
}, },
"scripts": { "scripts": {
"dev": "NODE_ENV=development webpack --colors --watch", "dev": "NODE_ENV=development webpack --watch",
"build": "NODE_ENV=production webpack --optimize-minimize --progress --colors", "build": "NODE_ENV=production webpack --progress",
"prepublish": "npm run build" "prepublish": "npm run build"
}, },
"keywords": [ "keywords": [
@@ -41,13 +41,12 @@
"pty" "pty"
], ],
"dependencies": { "dependencies": {
"@faressoft/node-pty-prebuilt": "^0.9.0",
"async": "^2.6.3", "async": "^2.6.3",
"async-promises": "^0.2.2", "async-promises": "^0.2.2",
"chalk": "^2.4.2", "chalk": "^2.4.2",
"death": "^1.1.0", "death": "^1.1.0",
"deepmerge": "^2.2.1", "deepmerge": "^2.2.1",
"electron": "^15.5.5", "electron": "17",
"flowa": "^4.0.2", "flowa": "^4.0.2",
"fs-extra": "^5.0.0", "fs-extra": "^5.0.0",
"gif-encoder": "^0.6.1", "gif-encoder": "^0.6.1",
@@ -55,6 +54,7 @@
"is_js": "^0.9.0", "is_js": "^0.9.0",
"js-yaml": "^3.13.1", "js-yaml": "^3.13.1",
"lodash": "^4.17.15", "lodash": "^4.17.15",
"node-pty-prebuilt-multiarch": "^0.10.1-pre.5",
"performance-now": "^2.1.0", "performance-now": "^2.1.0",
"pngjs": "^3.4.0", "pngjs": "^3.4.0",
"progress": "^2.0.3", "progress": "^2.0.3",
@@ -66,13 +66,13 @@
}, },
"devDependencies": { "devDependencies": {
"ajv": "^6.12.0", "ajv": "^6.12.0",
"clean-webpack-plugin": "^0.1.19", "clean-webpack-plugin": "^4.0.0",
"css-loader": "^1.0.0", "css-loader": "^1.0.0",
"jquery": "^3.4.1", "jquery": "^3.4.1",
"mini-css-extract-plugin": "^0.4.5", "mini-css-extract-plugin": "^2.6.1",
"terminalizer-player": "^0.4.1", "terminalizer-player": "^0.4.1",
"webpack": "^4.42.0", "webpack": "^5.74.0",
"webpack-cli": "^3.3.11", "webpack-cli": "^4.10.0",
"xterm": "^3.14.5" "xterm": "^3.14.5"
} }
} }

View File

@@ -5,24 +5,27 @@
* @author Mohammad Fares <faressoft.com@gmail.com> * @author Mohammad Fares <faressoft.com@gmail.com>
*/ */
var path = require('path'), const fs = require('fs');
app = require('electron').app, const path = require('path');
BrowserWindow = require('electron').BrowserWindow, const { app } = require('electron');
ipcMain = require('electron').ipcMain, const { BrowserWindow } = require('electron');
os = require('os'); const ipcMain = require('electron').ipcMain;
const os = require('os');
let mainWindow = null;
/**
* The temporary rendering directory's path
* @type {String}
*/
var renderDir = path.join(__dirname, 'frames');
/** /**
* The step option * The step option
* To reduce the number of rendered frames (step > 1) * To reduce the number of rendered frames (step > 1)
* @type {Number} * @type {Number}
*/ */
global.step = process.argv[2] || 1; var step = process.argv[2] || 1;
/**
* The temporary rendering directory's path
* @type {String}
*/
global.renderDir = path.join(__dirname, 'frames');
// Hide the Dock for macOS // Hide the Dock for macOS
if (os.platform() == 'darwin') { if (os.platform() == 'darwin') {
@@ -36,33 +39,53 @@ app.on('ready', createWindow);
* Create a hidden browser window and load the rendering page * Create a hidden browser window and load the rendering page
*/ */
function createWindow() { function createWindow() {
// Create a browser window // Create a browser window
var win = new BrowserWindow({ mainWindow = new BrowserWindow({
show: false, show: false,
width: 8000, width: 8000,
height: 8000, height: 8000,
webPreferences: { webPreferences: {
nodeIntegration: true preload: path.join(__dirname, 'preload.js'),
} },
}); });
// Load index.html // Load index.html
win.loadURL('file://' + __dirname + '/index.html'); mainWindow.loadURL('file://' + __dirname + '/index.html');
} }
/** /**
* A callback function for the event: * A callback function for the event:
* When a frame is captured * getOptions to request the options that need
* to be passed to the renderer
* *
* @param {Object} event * @param {Object} event
* @param {Number} recordIndex
*/ */
ipcMain.on('captured', function(event, recordIndex) { ipcMain.handle('getOptions', function () {
return { step };
});
console.log(recordIndex); /**
* A callback function for the event:
* capturePage
*
* @param {Object} event
*/
ipcMain.handle('capturePage', async function (event, captureRect, frameIndex) {
const img = await mainWindow.webContents.capturePage(captureRect);
const outputPath = path.join(renderDir, frameIndex + '.png');
fs.writeFileSync(outputPath, img.toPNG());
console.log(frameIndex);
});
/**
* A callback function for the event:
* Close
*
* @param {Object} event
* @param {String} error
*/
ipcMain.on('close', function (event, error) {
mainWindow.close();
}); });
/** /**
@@ -72,8 +95,6 @@ ipcMain.on('captured', function(event, recordIndex) {
* @param {Object} event * @param {Object} event
* @param {String} error * @param {String} error
*/ */
ipcMain.on('error', function(event, error) { ipcMain.on('error', function (event, error) {
process.stderr.write(error); process.stderr.write(error);
}); });

19
render/preload.js Normal file
View File

@@ -0,0 +1,19 @@
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('app', {
close() {
return ipcRenderer.send('close');
},
getOptions() {
return ipcRenderer.invoke('getOptions');
},
capturePage(captureRect, frameIndex) {
console.log('prelaod > capturePage');
return ipcRenderer.invoke('capturePage', captureRect, frameIndex);
},
});
// Catch all unhandled errors
window.onerror = function (error) {
ipcRenderer.send('error', error);
};

View File

@@ -4,16 +4,8 @@
* @author Mohammad Fares <faressoft.com@gmail.com> * @author Mohammad Fares <faressoft.com@gmail.com>
*/ */
var fs = require('fs'), import async from 'async';
path = require('path'), import 'terminalizer-player';
async = require('async'),
remote = require('electron').remote,
ipcRenderer = require('electron').ipcRenderer,
terminalizerPlayer = require('terminalizer-player');
var currentWindow = remote.getCurrentWindow(),
capturePage = currentWindow.webContents.capturePage,
step = remote.getGlobal('step'),
renderDir = remote.getGlobal('renderDir');
// Styles // Styles
import '../css/app.css'; import '../css/app.css';
@@ -26,38 +18,41 @@ import 'xterm/dist/xterm.css';
*/ */
var stepsCounter = 0; var stepsCounter = 0;
/**
* Rendering options
*/
var options = {};
/** /**
* A callback function for the event: * A callback function for the event:
* When the document is loaded * When the document is loaded
*/ */
$(document).ready(function() { $(document).ready(async () => {
options = await app.getOptions();
// Initialize the terminalizer plugin // Initialize the terminalizer plugin
$('#terminal').terminalizer({ $('#terminal').terminalizer({
recordingFile: 'data.json', recordingFile: 'data.json',
autoplay: true, autoplay: true,
controls: false controls: false,
}); });
/** /**
* A callback function for the event: * A callback function for the event:
* When the terminal playing is started * When the terminal playing is started
*/ */
$('#terminal').one('playingStarted', function() { $('#terminal').one('playingStarted', function () {
var terminalizer = $('#terminal').data('terminalizer'); var terminalizer = $('#terminal').data('terminalizer');
// Pause the playing // Pause the playing
terminalizer.pause(); terminalizer.pause();
}); });
/** /**
* A callback function for the event: * A callback function for the event:
* When the terminal playing is paused * When the terminal playing is paused
*/ */
$('#terminal').one('playingPaused', function() { $('#terminal').one('playingPaused', function () {
var terminalizer = $('#terminal').data('terminalizer'); var terminalizer = $('#terminal').data('terminalizer');
// Reset the terminal // Reset the terminal
@@ -65,36 +60,32 @@ $(document).ready(function() {
// When the terminal's reset is done // When the terminal's reset is done
$('#terminal').one('rendered', render); $('#terminal').one('rendered', render);
}); });
}); });
/** /**
* Render each frame and capture it * Render each frame and capture it
*/ */
function render() { function render() {
var terminalizer = $('#terminal').data('terminalizer'); var terminalizer = $('#terminal').data('terminalizer');
var framesCount = terminalizer.getFramesCount(); var framesCount = terminalizer.getFramesCount();
// Foreach frame // Foreach frame
async.timesSeries(framesCount, function(frameIndex, next) { async.timesSeries(
framesCount,
terminalizer._renderFrame(frameIndex, true, function() { function (frameIndex, next) {
terminalizer._renderFrame(frameIndex, true, function () {
capture(frameIndex, next); capture(frameIndex, next);
}); });
},
}, function(error) { function (error) {
if (error) { if (error) {
throw new Error(error); throw new Error(error);
} }
currentWindow.close(); app.close();
}
}); );
} }
/** /**
@@ -104,41 +95,21 @@ function render() {
* @param {Function} callback * @param {Function} callback
*/ */
function capture(frameIndex, callback) { function capture(frameIndex, callback) {
var width = $('#terminal').width(); var width = $('#terminal').width();
var height = $('#terminal').height(); var height = $('#terminal').height();
var captureRect = {x: 0, y: 0, width: width, height: height}; var captureRect = { x: 0, y: 0, width: width, height: height };
if (stepsCounter != 0) { if (stepsCounter != 0) {
stepsCounter = (stepsCounter + 1) % step; stepsCounter = (stepsCounter + 1) % options.step;
return callback(); return callback();
} }
stepsCounter = (stepsCounter + 1) % step; stepsCounter = (stepsCounter + 1) % options.step;
capturePage(captureRect).then((img) => {
var outputPath = path.join(renderDir, frameIndex + '.png');
fs.writeFileSync(outputPath, img.toPNG());
ipcRenderer.send('captured', frameIndex);
callback();
}).catch((err) => {
throw new err;
app
.capturePage(captureRect, frameIndex)
.then(callback)
.catch((err) => {
throw err;
}); });
} }
/**
* Catch all unhandled errors
*
* @param {String} error
*/
window.onerror = function(error) {
ipcRenderer.send('error', error);
};

View File

@@ -3,7 +3,7 @@ const path = require('path');
// Extract CSS into separate files // Extract CSS into separate files
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// Global variables // Global variables
const globals = { const globals = {
@@ -11,36 +11,35 @@ const globals = {
jQuery: 'jquery', jQuery: 'jquery',
Terminal: ['xterm', 'Terminal'], Terminal: ['xterm', 'Terminal'],
'window.jQuery': 'jquery', 'window.jQuery': 'jquery',
'window.$': 'jquery' 'window.$': 'jquery',
}; };
module.exports = { module.exports = {
mode: 'production', mode: 'production',
target: 'electron-renderer', target: 'electron-renderer',
entry: { entry: {
app: './render/src/js/app.js' app: './render/src/js/app.js',
}, },
output: { output: {
filename: 'js/[name].js', filename: 'js/[name].js',
path: path.resolve(__dirname, 'render/dist'), path: path.resolve(__dirname, 'render/dist'),
publicPath: '/dist/' publicPath: '/dist/',
}, },
plugins: [ plugins: [
new CleanWebpackPlugin(['./render/dist'], {verbose: false}), new CleanWebpackPlugin({
cleanBeforeEveryBuildPatterns: [path.join(__dirname, 'render/dist')],
}),
new webpack.ProvidePlugin(globals), new webpack.ProvidePlugin(globals),
new MiniCssExtractPlugin({filename: 'css/[name].css'}), new MiniCssExtractPlugin({ filename: 'css/[name].css' }),
new webpack.NoEmitOnErrorsPlugin() new webpack.NoEmitOnErrorsPlugin(),
], ],
module: { module: {
rules: [ rules: [
// CSS // CSS
{ {
test: /\.css$/, test: /\.css$/,
use: [ use: [{ loader: MiniCssExtractPlugin.loader }, { loader: 'css-loader' }],
{loader: MiniCssExtractPlugin.loader}, },
{loader: 'css-loader'}
], ],
} },
]
}
}; };

2918
yarn.lock Normal file

File diff suppressed because it is too large Load Diff