#!/usr/bin/env node import 'source-map-support/register'; import * as commander from 'commander'; import * as dns from 'dns'; import * as log from 'loglevel'; import { buildNativefierApp } from './main'; // package.json is `require`d to let tsc strip the `src` folder by determining // baseUrl=src. A static import would prevent that and cause an ugly extra "src" folder const packageJson = require('../package.json'); // eslint-disable-line @typescript-eslint/no-var-requires function collect(val: any, memo: any[]): any[] { memo.push(val); return memo; } function parseBooleanOrString(val: string): boolean | string { switch (val) { case 'true': return true; case 'false': return false; default: return val; } } function parseJson(val: string): any { if (!val) return {}; return JSON.parse(val); } function getProcessEnvs(val: string): any { if (!val) { return {}; } return { processEnvs: parseJson(val) }; } function checkInternet(): void { dns.lookup('npmjs.com', (err) => { if (err && err.code === 'ENOTFOUND') { log.warn( '\nNo Internet Connection\nTo offline build, download electron from https://github.com/electron/electron/releases\nand place in ~/AppData/Local/electron/Cache/ on Windows,\n~/.cache/electron on Linux or ~/Library/Caches/electron/ on Mac\nUse --electron-version to specify the version you downloaded.', ); } }); } if (require.main === module) { const sanitizedArgs = []; process.argv.forEach((arg) => { if (sanitizedArgs.length > 0) { const previousArg = sanitizedArgs[sanitizedArgs.length - 1]; // Work around commander.js not supporting default argument for options if ( previousArg === '--tray' && !['true', 'false', 'start-in-tray'].includes(arg) ) { sanitizedArgs.push('true'); } } sanitizedArgs.push(arg); }); const positionalOptions = { targetUrl: '', out: '', }; commander .name('nativefier') .version(packageJson.version, '-v, --version') .arguments(' [dest]') .action((url, outputDirectory) => { positionalOptions.targetUrl = url; positionalOptions.out = outputDirectory; }) .option('-n, --name ', 'app name') .option('-p, --platform ', "'mac', 'mas', 'linux' or 'windows'") .option('-a, --arch ', "'ia32' or 'x64' or 'armv7l'") .option( '--app-version ', '(macOS, windows only) the version of the app. Maps to the `ProductVersion` metadata property on Windows, and `CFBundleShortVersionString` on macOS.', ) .option( '--build-version ', '(macOS, windows only) The build version of the app. Maps to `FileVersion` metadata property on Windows, and `CFBundleVersion` on macOS', ) .option( '--app-copyright ', '(macOS, windows only) a human-readable copyright line for the app. Maps to `LegalCopyright` metadata property on Windows, and `NSHumanReadableCopyright` on macOS', ) .option( '--win32metadata ', '(windows only) a JSON string of key/value pairs (ProductName, InternalName, FileDescription) to embed as executable metadata', parseJson, ) .option( '-e, --electron-version ', "electron version to package, without the 'v', see https://github.com/electron/electron/releases", ) .option( '--no-overwrite', 'do not override output directory if it already exists; defaults to false', ) .option( '-c, --conceal', 'packages the app source code into an asar archive; defaults to false', ) .option( '--counter', '(macOS only) set a dock count badge, determined by looking for a number in the window title; defaults to false', ) .option( '--bounce', '(macOS only) make he dock icon bounce when the counter increases; defaults to false', ) .option( '-i, --icon ', 'the icon file to use as the icon for the app (should be a .png)', ) .option( '--width ', 'set window default width; defaults to 1280px', parseInt, ) .option( '--height ', 'set window default height; defaults to 800px', parseInt, ) .option( '--min-width ', 'set window minimum width; defaults to 0px', parseInt, ) .option( '--min-height ', 'set window minimum height; defaults to 0px', parseInt, ) .option( '--max-width ', 'set window maximum width; default is unlimited', parseInt, ) .option( '--max-height ', 'set window maximum height; default is unlimited', parseInt, ) .option('--x ', 'set window x location', parseInt) .option('--y ', 'set window y location', parseInt) .option('-m, --show-menu-bar', 'set menu bar visible; defaults to false') .option( '-f, --fast-quit', '(macOS only) quit app on window close; defaults to false', ) .option('-u, --user-agent ', 'set the app user agent string') .option( '--honest', 'prevent the normal changing of the user agent string to appear as a regular Chrome browser', ) .option('--ignore-certificate', 'ignore certificate-related errors') .option('--disable-gpu', 'disable hardware acceleration') .option( '--ignore-gpu-blacklist', 'force WebGL apps to work on unsupported GPUs', ) .option('--enable-es3-apis', 'force activation of WebGL 2.0') .option( '--insecure', 'enable loading of insecure content; defaults to false', ) .option('--flash', 'enables Adobe Flash; defaults to false') .option( '--flash-path ', 'path to Chrome flash plugin; find it in `chrome://plugins`', ) .option( '--disk-cache-size ', 'forces the maximum disk space (in bytes) to be used by the disk cache', ) .option( '--inject ', 'path to a CSS/JS file to be injected. Pass multiple times to inject multiple files.', collect, [], ) .option('--full-screen', 'always start the app full screen') .option('--maximize', 'always start the app maximized') .option('--hide-window-frame', 'disable window frame and controls') .option('--verbose', 'enable verbose/debug/troubleshooting logs') .option('--disable-context-menu', 'disable the context menu (right click)') .option( '--disable-dev-tools', 'disable developer tools (Ctrl+Shift+I / F12)', ) .option( '--zoom ', 'default zoom factor to use when the app is opened; defaults to 1.0', parseFloat, ) .option( '--internal-urls ', 'regex of URLs to consider "internal"; all other URLs will be opened in an external browser. Default: URLs on same second-level domain as app', ) .option( '--proxy-rules ', 'proxy rules; see https://www.electronjs.org/docs/api/session#sessetproxyconfig', ) .option( '--crash-reporter ', 'remote server URL to send crash reports', ) .option( '--single-instance', 'allow only a single instance of the application', ) .option( '--clear-cache', 'prevent the application from preserving cache between launches', ) .option( '--processEnvs ', 'a JSON string of key/value pairs to be set as environment variables before any browser windows are opened', getProcessEnvs, ) .option( '--file-download-options ', 'a JSON string of key/value pairs to be set as file download options. See https://github.com/sindresorhus/electron-dl for available options.', parseJson, ) .option( '--tray [start-in-tray]', "Allow app to stay in system tray. If 'start-in-tray' is set as argument, don't show main window on first start", parseBooleanOrString, ) .option('--basic-auth-username ', 'basic http(s) auth username') .option('--basic-auth-password ', 'basic http(s) auth password') .option('--always-on-top', 'enable always on top window') .option( '--title-bar-style ', "(macOS only) set title bar style ('hidden', 'hiddenInset'). Consider injecting custom CSS (via --inject) for better integration", ) .option( '--global-shortcuts ', 'JSON file defining global shortcuts. See https://github.com/jiahaog/nativefier/blob/master/docs/api.md#global-shortcuts', ) .option( '--browserwindow-options ', 'a JSON string that will be sent directly into electron BrowserWindow options. See https://github.com/jiahaog/nativefier/blob/master/docs/api.md#browserwindow-options', parseJson, ) .option( '--background-color ', "sets the app background color, for better integration while the app is loading. Example value: '#2e2c29'", ) .option( '--darwin-dark-mode-support', '(macOS only) enable Dark Mode support on macOS 10.14+', ) .parse(sanitizedArgs); if (!process.argv.slice(2).length) { commander.help(); } checkInternet(); const options = { ...positionalOptions, ...commander.opts() }; buildNativefierApp(options) .then((appPath) => { if (!appPath) { log.info(`App *not* built to ${appPath}`); return; } log.info(`App built to ${appPath}`); }) .catch((error) => { log.error('Error during build. Run with --verbose for details.', error); }); }