UNPKG

electron2appx

Version:

Compile Electron Apps into Windows Store AppX packages

169 lines (146 loc) 6.66 kB
'use strict' const path = require('path') const spawn = require('child_process').spawn const chalk = require('chalk') const fs = require('fs-extra') const Tail = require('./vendor/tail').Tail const utils = require('./utils') /** * Converts the given Electron app using Project Centennial * Container Virtualization. * * @param program - Program object containing the user's instructions * @returns - Promise */ function convertWithContainer (program) { return new Promise((resolve, reject) => { if (!program.desktopConverter) { utils.log('Could not find the Project Centennial Desktop App Converter, which is required to') utils.log('run the conversion to appx using a Windows Container.\n') utils.log('Consult the documentation at https://aka.ms/electron-windows-store for a tutorial.\n') utils.log('You can find the Desktop App Converter at https://www.microsoft.com/en-us/download/details.aspx?id=51691\n') utils.log('Exiting now - restart when you downloaded and unpacked the Desktop App Converter!') process.exit(0) } let preAppx = path.join(program.outputDirectory, 'pre-appx') let installer = path.join(program.outputDirectory, 'ElectronInstaller.exe') let logfile = path.join(program.outputDirectory, 'logs', 'conversion.log') let converterArgs = [ `-LogFile ${logfile}`, `-Installer '${installer}'`, `-Converter '${path.join(program.desktopConverter, 'DesktopAppConverter.ps1')}'`, `-ExpandedBaseImage ${program.expandedBaseImage}`, `-Destination '${preAppx}'`, `-PackageName "${program.packageName}"`, `-Version ${program.packageVersion}`, `-Publisher "${program.publisher}"`, `-AppExecutable '${program.packageExecutable}'` ] let args = `& {& '${path.resolve(__dirname, '..', 'ps1', 'convert.ps1')}' ${converterArgs.join(' ')}}` let child, tail utils.log(chalk.green.bold('Starting Conversion...')) utils.debug(`Conversion parameters used: ${JSON.stringify(converterArgs)}`) try { child = spawn('powershell.exe', ['-NoProfile', '-NoLogo', args]) } catch (error) { reject(error) } child.stdout.on('data', (data) => utils.debug(data.toString())) child.stderr.on('data', (data) => utils.debug(data.toString())) child.on('exit', () => { // The conversion process exited, let's look for a log file // However, give the PS process a 3s headstart, since we'll // crash if the logfile does not exist yet setTimeout(() => { tail = new Tail(logfile, { fromBeginning: true }) tail.on('line', (data) => { utils.log(data) if (data.indexOf('Conversion complete') > -1) { utils.log('') tail.unwatch() resolve() } else if (data.indexOf('An error occurred') > -1) { tail.unwatch() reject(new Error('Detected error in conversion log')) } }) tail.on('error', (err) => utils.log(err)) }, 3000) }) child.stdin.end() }) } /** * Converts the given Electron app using simple file copy * mechanisms. * * @param program - Program object containing the user's instructions * @returns - Promise */ function convertWithFileCopy (program) { return new Promise((resolve, reject) => { let preAppx = path.join(program.outputDirectory, 'pre-appx') let app = path.join(preAppx, 'app') let manifest = path.join(preAppx, 'AppXManifest.xml') let manifestTemplate = path.join(__dirname, '..', 'template', 'AppXManifest.xml') let assets = path.join(preAppx, 'assets') let assetsTemplate = path.join(__dirname, '..', 'template', 'assets') utils.log(chalk.green.bold('Starting Conversion...')) utils.debug(`Using pre-appx folder: ${preAppx}`) utils.debug(`Using app from: ${app}`) utils.debug(`Using manifest template from: ${manifestTemplate}`) utils.debug(`Using asset template from ${assetsTemplate}`) // Clean output folder utils.log(chalk.green.bold('Cleaning pre-appx output folder...')) fs.emptyDirSync(preAppx) // Copy in the new manifest, app, assets utils.log(chalk.green.bold('Copying data...')) fs.copySync(manifestTemplate, manifest) utils.debug('Copied manifest template to destination') if (program.assets) { utils.debug('Not copying asset template to destination because custom assets are provided') } else { fs.copySync(assetsTemplate, assets) utils.debug('Copied asset template to destination') } fs.copySync(program.inputDirectory, app) utils.debug('Copied input app files to destination') // Then, overwrite the manifest fs.readFile(manifest, 'utf8', (err, data) => { utils.log(chalk.green.bold('Creating manifest..')) let result = data let executable = program.packageExecutable || `app\\${program.packageName}.exe` if (err) { utils.debug(`Could not read manifest template. Error: ${JSON.stringify(err)}`) return utils.log(err) } result = result.replace(/\${publisherName}/g, program.publisher) result = result.replace(/\${publisherDisplayName}/g, program.publisherDisplayName || 'Reserved') result = result.replace(/\${identityName}/g, program.identityName || program.packageName) result = result.replace(/\${applicationId}/g, program.applicationId || program.packageName) result = result.replace(/\${packageVersion}/g, program.packageVersion) result = result.replace(/\${packageName}/g, program.packageName) result = result.replace(/\${packageExecutable}/g, executable) result = result.replace(/\${packageDisplayName}/g, program.packageDisplayName || program.packageName) result = result.replace(/\${packageDescription}/g, program.packageDescription || program.packageName) result = result.replace(/\${packageBackgroundColor}/g, program.packageBackgroundColor || '#464646') fs.writeFile(manifest, result, 'utf8', (err) => { if (err) { const errorMessage = `Could not write manifest file in pre-appx location. Error: ${JSON.stringify(err)}` utils.debug(errorMessage) return reject(new Error(errorMessage)) } resolve() }) }) }) } module.exports = function (program) { if (program.containerVirtualization) { return convertWithContainer(program) } else { return convertWithFileCopy(program) } }