@jasonscheirer/electron-forge-maker-msix
Version:
An `electron-forge` maker for MSIX that supports `electron-forge` v6 and can be used as a replacement for `electron-builder`. Supports code-signing.
133 lines • 5.77 kB
JavaScript
import { MakerBase } from '@electron-forge/maker-base';
import { getChannelYml, getAppUpdateYml } from './yaml';
import fs from 'fs-extra';
import path from 'node:path';
import { makeAppXImages as createMSIXImageTiles } from './imageAssets';
import { getPublisher, makeAppInstaller, makeAppManifest, makeManifestConfiguration, makePRI, makeContentTypeXML, } from './msixTools';
import { log, run } from './run';
import { codesign } from './sign';
import { findInWindowsKits, walk } from './walk';
export * from './msixTools';
export * from './imageAssets';
export * from './types';
const findMainExecutable = async (rootPath) => {
let executable;
for await (const fileName of walk(rootPath)) {
const relativeFileName = fileName.substring(rootPath.length).replace(/^[\\/]+/, '');
if (relativeFileName.toLocaleLowerCase().endsWith('.exe') &&
(!executable || executable.split(/[/\\]/).length > relativeFileName.split(/[/\\]/).length)) {
executable = relativeFileName;
}
}
if (!executable) {
throw new Error(`No executable file found in ${rootPath}`);
}
return executable;
};
const packageMSIXFromFolder = async (scratchPath, outMSIX, config) => {
var _a;
const makeAppXPath = (_a = config.makeAppXPath) !== null && _a !== void 0 ? _a : (await findInWindowsKits('makeappx.exe'));
await codesign(config, scratchPath);
try {
if ((await fs.stat(outMSIX)).isFile()) {
log(`${outMSIX} already exists; making new one`);
await fs.unlink(outMSIX);
}
}
catch (e) {
log(`Error looking for existing ${outMSIX}: ${e}`);
}
await run(makeAppXPath, ['pack', '/d', scratchPath, '/p', outMSIX]);
await codesign(config, outMSIX);
};
const makeAppUpdateYml = async (config, options, outPath) => {
if (!config.updater)
return;
const ymlContents = await getAppUpdateYml({
url: config.updater.url,
name: options.appName,
channel: config.updater.channel,
updaterCacheDirName: config.updater.updaterCacheDirName,
publisherName: config.updater.publisherName,
});
const resourcePath = path.join(outPath, 'resources');
log(`Writing app-update.yml to ${resourcePath}`, ymlContents);
await fs.ensureDir(resourcePath);
await fs.writeFile(path.join(resourcePath, 'app-update.yml'), ymlContents, 'utf8');
};
const makeChannelYml = async (config, options, installerPath) => {
if (!config.updater)
return;
const channel = config.updater.channel || 'latest';
const version = options.packageJSON.version;
const channelFilePath = path.resolve(installerPath, `${channel}.yml`);
const ymlContents = await getChannelYml({
installerPath,
version,
platform: 'win32',
});
log(`Writing ${channel}.yml to ${installerPath}`, ymlContents);
await fs.writeFile(channelFilePath, ymlContents, 'utf8');
return channelFilePath;
};
export default class MakerMSIX extends MakerBase {
constructor() {
super(...arguments);
this.name = 'msix';
this.defaultPlatforms = ['win32'];
}
isSupportedOnCurrentPlatform() {
return process.platform === 'win32';
}
async make(options) {
var _a;
const appID = (_a = this.config.internalAppID) !== null && _a !== void 0 ? _a : options.appName
.toUpperCase()
.replace(/[^A-Z]/g, '')
.slice(0, 10);
// Copy out files to scratch directory for signing/packaging
const msixBuildFolderRootPath = path.join(options.makeDir, 'msix/build/');
if (await fs.pathExists(msixBuildFolderRootPath)) {
await fs.remove(msixBuildFolderRootPath);
}
const programFilesPath = path.join(msixBuildFolderRootPath, options.appName);
await fs.ensureDir(programFilesPath);
await fs.copy(options.dir, programFilesPath);
// Make sure the build dir exists
const outPath = path.join(options.makeDir, `${options.appName}-${options.targetArch}-msix/`);
await fs.ensureDir(outPath);
// Find all the files to be installed
const executable = await findMainExecutable(msixBuildFolderRootPath);
// Generate images for various tile sizes
await createMSIXImageTiles(appID, msixBuildFolderRootPath, this.config);
// Courtesy: if publisher is not set, pull from signed exe
let publisher;
if (this.config.publisher) {
publisher = this.config.publisher;
}
else {
publisher = await getPublisher(path.join(msixBuildFolderRootPath, executable), this.config);
}
const manifestConfig = makeManifestConfiguration({
appID,
version: options.packageJSON.version,
executable,
config: {
...this.config,
publisher,
},
options,
});
// Actual AppxManifest.xml, the orchestration layer
const appInstallerPath = await makeAppInstaller(outPath, msixBuildFolderRootPath, manifestConfig);
await makePRI(msixBuildFolderRootPath, this.config);
await makeAppUpdateYml(this.config, options, programFilesPath);
await makeAppManifest(msixBuildFolderRootPath, manifestConfig);
await makeContentTypeXML(msixBuildFolderRootPath);
const outMSIX = path.join(outPath, manifestConfig.msixFilename);
await packageMSIXFromFolder(msixBuildFolderRootPath, outMSIX, this.config);
const channelYamlPath = await makeChannelYml(this.config, options, outPath);
return [outMSIX, appInstallerPath, channelYamlPath].filter(Boolean);
}
}
//# sourceMappingURL=makerMsix.js.map