/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */ var electron = require('electron'); var XLSX = require('xlsx'); var app = electron.app; require('@electron/remote/main').initialize(); // required for Electron 14+ var win = null; const EXT_REGEX = /\.(xls|xlsx|xlsm|xlsb|xml|csv|txt|dif|sylk|slk|prn|ods|fods|htm|html|numbers)$/i; const pendingPaths = []; // any paths that arrive before the window exists // send file opening events to renderer function sendToRenderer(filePath) { if (win && win.webContents) { win.webContents.send('file-opened', filePath); } else { pendingPaths.push(filePath); } } function firstSpreadsheetFromArgv() { const args = process.defaultApp // dev: electron . ? process.argv.slice(2) // skip electron executable & dir : process.argv.slice(1); // skip packaged exe return args.find(a => EXT_REGEX.test(a)); // undefined if none } /* ---- 1️⃣ single-instance guard (needed for Windows / Linux) ---- */ // on windows and linux, opening a file opens a new instance of the app, this prevents that. const gotLock = app.requestSingleInstanceLock(); if (!gotLock) app.quit(); else { app.on('second-instance', (_e, argv) => { // emitted in *primary* instance const fp = argv.find(a => EXT_REGEX.test(a)); if (fp) sendToRenderer(fp); if (win) { win.show(); win.focus(); } }); } /* ---- 2️⃣ platform-specific “open file” hooks ---- */ app.on('open-file', (event, fp) => { // macOS Dock / Finder event.preventDefault(); sendToRenderer(fp); }); app.on('open-url', (event, url) => { // you can add a custom protocol if you want to handle URLs event.preventDefault(); sendToRenderer(url.replace('file://', '')); // crude, adjust if you keep deep-links }); /* ---- 3️⃣ normal start-up, harvest argv ---- */ app.whenReady().then(() => { const fp = firstSpreadsheetFromArgv(); // Windows & Linux first launch if (fp) pendingPaths.push(fp); createWindow(); }); /* ---- 4️⃣ create the window ---- */ function createWindow() { if (win) return; win = new electron.BrowserWindow({ width: 800, height: 600, webPreferences: { worldSafeExecuteJavaScript: true, // required for Electron 12+ contextIsolation: false, // required for Electron 12+ nodeIntegration: true, enableRemoteModule: true } }); win.loadURL("file://" + __dirname + "/index.html"); require('@electron/remote/main').enable(win.webContents); // required for Electron 14 if (process.env.NODE_ENV === 'development') win.webContents.openDevTools(); // only open devtools in development win.on('closed', function () { win = null; }); win.webContents.once('did-finish-load', () => { pendingPaths.splice(0).forEach(sendToRenderer); }); } if (app.setAboutPanelOptions) app.setAboutPanelOptions({ applicationName: 'sheetjs-electron', applicationVersion: "XLSX " + XLSX.version, copyright: "(C) 2017-present SheetJS LLC" }); app.on('ready', createWindow); app.on('activate', createWindow); app.on('window-all-closed', function () { if (process.platform !== 'darwin') app.quit(); });