nativefier
Version:
Wrap web apps natively
217 lines • 10.4 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildNativefierApp = void 0;
const path = __importStar(require("path"));
const electronGet = __importStar(require("@electron/get"));
const electron_packager_1 = __importDefault(require("electron-packager"));
const fs = __importStar(require("fs-extra"));
const log = __importStar(require("loglevel"));
const buildIcon_1 = require("./buildIcon");
const helpers_1 = require("../helpers/helpers");
const upgrade_1 = require("../helpers/upgrade/upgrade");
const optionsMain_1 = require("../options/optionsMain");
const prepareElectronApp_1 = require("./prepareElectronApp");
const OPTIONS_REQUIRING_WINDOWS_FOR_WINDOWS_BUILD = [
'icon',
'appCopyright',
'appVersion',
'buildVersion',
'versionString',
'win32metadata',
];
/**
* For Windows & Linux, we have to copy over the icon to the resources/app
* folder, which the BrowserWindow is hard-coded to read the icon from
*/
async function copyIconsIfNecessary(options, appPath) {
log.debug('Copying icons if necessary');
if (!options.packager.icon) {
log.debug('No icon specified in options; aborting');
return;
}
if (options.packager.platform === 'darwin' ||
options.packager.platform === 'mas') {
if (options.nativefier.tray !== 'false') {
//tray icon needs to be .png
log.debug('Copying icon for tray application');
const trayIconFileName = `tray-icon.png`;
const destIconPath = path.join(appPath, 'icon.png');
await fs.copy(`${path.dirname(options.packager.icon)}/${trayIconFileName}`, destIconPath);
}
else {
log.debug('No copying necessary on macOS; aborting');
}
return;
}
// windows & linux: put the icon file into the app
const destFileName = `icon${path.extname(options.packager.icon)}`;
const destIconPath = path.join(appPath, destFileName);
log.debug(`Copying icon ${options.packager.icon} to`, destIconPath);
await fs.copy(options.packager.icon, destIconPath);
}
/**
* Checks the app path array to determine if packaging completed successfully
*/
function getAppPath(appPath) {
if (!Array.isArray(appPath)) {
return appPath;
}
if (appPath.length === 0) {
return undefined; // directory already exists and `--overwrite` not set
}
if (appPath.length > 1) {
log.warn('Warning: This should not be happening, packaged app path contains more than one element:', appPath);
}
return appPath[0];
}
function isUpgrade(rawOptions) {
if (rawOptions.upgrade !== undefined &&
typeof rawOptions.upgrade === 'string' &&
rawOptions.upgrade !== '') {
rawOptions.upgradeFrom = rawOptions.upgrade;
rawOptions.upgrade = true;
return true;
}
return false;
}
function trimUnprocessableOptions(options) {
if (options.packager.platform === 'win32' && !(0, helpers_1.isWindows)() && !(0, helpers_1.hasWine)()) {
const optionsPresent = Object.entries(options)
.filter(([key, value]) => OPTIONS_REQUIRING_WINDOWS_FOR_WINDOWS_BUILD.includes(key) && !!value)
.map(([key]) => key);
if (optionsPresent.length === 0) {
return;
}
log.warn(`*Not* setting [${optionsPresent.join(', ')}], as couldn't find Wine.`, 'Wine is required when packaging a Windows app under on non-Windows platforms.', 'Also, note that Windows apps built under non-Windows platforms without Wine *will lack* certain', 'features, like a correct icon and process name. Do yourself a favor and install Wine, please.');
for (const keyToUnset of optionsPresent) {
options[keyToUnset] = undefined;
}
}
}
function getOSRunHelp(platform) {
if (platform === 'win32') {
return `the contained .exe file.`;
}
else if (platform === 'linux') {
return `the contained executable file (prefixing with ./ if necessary)\nMenu/desktop shortcuts are up to you, because Nativefier cannot know where you're going to move the app. Search for "linux .desktop file" for help, or see https://wiki.archlinux.org/index.php/Desktop_entries`;
}
else if (platform === 'darwin') {
return `the app bundle.`;
}
return '';
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
async function buildNativefierApp(rawOptions) {
var _a, _b, _c, _d;
// early-suppress potential logging before full options handling
if (rawOptions.quiet) {
log.setLevel('silent');
}
log.warn('\n\n Hi! Nativefier is minimally maintained these days, and needs more hands.\n' +
' If you have the time & motivation, help with bugfixes and maintenance is VERY welcome.\n' +
' Please go to https://github.com/nativefier/nativefier and help how you can. Thanks.\n\n');
log.info('\nProcessing options...');
let finalOutDirectory = (_a = rawOptions.out) !== null && _a !== void 0 ? _a : process.cwd();
if (isUpgrade(rawOptions)) {
log.debug('Attempting to upgrade from', rawOptions.upgradeFrom);
const oldApp = (0, upgrade_1.findUpgradeApp)(rawOptions.upgradeFrom);
if (!oldApp) {
throw new Error(`Could not find an old Nativfier app in "${rawOptions.upgradeFrom}"`);
}
rawOptions = (0, upgrade_1.useOldAppOptions)(rawOptions, oldApp);
if (rawOptions.out === undefined && rawOptions.overwrite) {
finalOutDirectory = oldApp.appRoot;
rawOptions.out = (0, helpers_1.getTempDir)('appUpgrade', 0o755);
}
}
log.debug('rawOptions', rawOptions);
const options = await (0, optionsMain_1.getOptions)(rawOptions);
log.debug('options', options);
if (options.packager.platform === 'darwin' && (0, helpers_1.isWindows)()) {
// electron-packager has to extract the desired electron package for the target platform.
// For a target platform of Mac, this zip file contains symlinks. And on Windows, extracting
// files that are symlinks need Admin permissions. So we'll check if the user is an admin, and
// fail early if not.
// For reference
// https://github.com/electron/electron-packager/issues/933
// https://github.com/electron/electron-packager/issues/1194
// https://github.com/electron/electron/issues/11094
if (!(0, helpers_1.isWindowsAdmin)()) {
throw new Error('Building an app with a target platform of Mac on a Windows machine requires admin priveleges to perform. Please rerun this command in an admin command prompt.');
}
}
log.info('\nPreparing Electron app...');
const tmpPath = (0, helpers_1.getTempDir)('app', 0o755);
await (0, prepareElectronApp_1.prepareElectronApp)(options.packager.dir, tmpPath, options);
log.info('\nConverting icons...');
options.packager.dir = tmpPath;
(0, buildIcon_1.convertIconIfNecessary)(options);
await copyIconsIfNecessary(options, tmpPath);
options.packager.quiet = !rawOptions.verbose;
log.info("\nPackaging... This will take a few seconds, maybe minutes if the requested Electron isn't cached yet...");
trimUnprocessableOptions(options);
electronGet.initializeProxy(); // https://github.com/electron/get#proxies
const appPathArray = await (0, electron_packager_1.default)(options.packager);
log.info('\nFinalizing build...');
let appPath = getAppPath(appPathArray);
if (!appPath) {
throw new Error('App Path could not be determined.');
}
if (options.packager.upgrade &&
options.packager.upgradeFrom &&
options.packager.overwrite) {
if (options.packager.platform === 'darwin') {
try {
// This is needed due to a funky thing that happens when copying Squirrel.framework
// over where it gets into a circular file reference somehow.
await fs.remove(path.join(finalOutDirectory, `${(_b = options.packager.name) !== null && _b !== void 0 ? _b : ''}.app`, 'Contents', 'Frameworks'));
}
catch (err) {
log.warn('Encountered an error when attempting to pre-delete old frameworks:', err);
}
await fs.copy(path.join(appPath, `${(_c = options.packager.name) !== null && _c !== void 0 ? _c : ''}.app`), path.join(finalOutDirectory, `${(_d = options.packager.name) !== null && _d !== void 0 ? _d : ''}.app`), {
overwrite: options.packager.overwrite,
preserveTimestamps: true,
});
}
else {
await fs.copy(appPath, finalOutDirectory, {
overwrite: options.packager.overwrite,
preserveTimestamps: true,
});
}
await fs.remove(appPath);
appPath = finalOutDirectory;
}
const osRunHelp = getOSRunHelp(options.packager.platform);
log.info(`App built to ${appPath}, move to wherever it makes sense for you and run ${osRunHelp}`);
return appPath;
}
exports.buildNativefierApp = buildNativefierApp;
//# sourceMappingURL=buildNativefierApp.js.map