@mjcctech/meteor-desktop
Version:
Build a Meteor's desktop client with hot code push.
921 lines (789 loc) • 33.1 kB
JavaScript
"use strict";var module1=module;module1.export({default:()=>ElectronApp});var regeneratorRuntime;module1.link('regenerator-runtime/runtime',{default(v){regeneratorRuntime=v}},0);var asar;module1.link('asar',{default(v){asar=v}},1);var assignIn;module1.link('lodash/assignIn',{default(v){assignIn=v}},2);var _;module1.link('lodash',{default(v){_=v}},3);var LocalInstaller,progress;module1.link('install-local',{LocalInstaller(v){LocalInstaller=v},progress(v){progress=v}},4);var transformFileSync;module1.link('@babel/core',{transformFileSync(v){transformFileSync=v}},5);var crypto;module1.link('crypto',{default(v){crypto=v}},6);var del;module1.link('del',{default(v){del=v}},7);var presetEnv;module1.link('@babel/preset-env',{default(v){presetEnv=v}},8);var fs;module1.link('fs',{default(v){fs=v}},9);var path;module1.link('path',{default(v){path=v}},10);var shell;module1.link('shelljs',{default(v){shell=v}},11);var semver;module1.link('semver',{default(v){semver=v}},12);var uglify;module1.link('terser',{default(v){uglify=v}},13);var Log;module1.link('./log',{default(v){Log=v}},14);var ElectronAppScaffold;module1.link('./electronAppScaffold',{default(v){ElectronAppScaffold=v}},15);var DependenciesManager;module1.link('./dependenciesManager',{default(v){DependenciesManager=v}},16);var BinaryModuleDetector;module1.link('./binaryModulesDetector',{default(v){BinaryModuleDetector=v}},17);// eslint-disable-next-line no-unused-vars
shell.config.fatal = true;
/**
* Represents the .desktop dir scaffold.
* @class
*/
class ElectronApp {
/**
* @param {MeteorDesktop} $ - context
* @constructor
*/
constructor($) {
this.log = new Log('electronApp');
this.scaffold = new ElectronAppScaffold($);
this.depsManager = new DependenciesManager(
$,
this.scaffold.getDefaultPackageJson().dependencies
);
this.$ = $;
this.meteorApp = this.$.meteorApp;
this.packageJson = null;
this.version = null;
this.compatibilityVersion = null;
this.deprectatedPlugins = ['meteor-desktop-localstorage'];
}
/**
* Makes an app.asar from the skeleton app.
* @property {Array} excludeFromDel - list of paths to exclude from deleting
* @returns {Promise}
*/
packSkeletonToAsar(excludeFromDel = []) {
this.log.info('packing skeleton app and node_modules to asar archive');
return new Promise((resolve) => {
const extract = this.getModulesToExtract();
// We want to pack skeleton app and node_modules together, so we need to temporarily
// move node_modules to app dir.
this.log.debug('moving node_modules to app dir');
fs.renameSync(
this.$.env.paths.electronApp.nodeModules,
path.join(this.$.env.paths.electronApp.appRoot, 'node_modules')
);
let extracted = false;
extracted = this.extractModules(extract);
this.log.debug('packing');
asar.createPackage(
this.$.env.paths.electronApp.appRoot,
this.$.env.paths.electronApp.appAsar,
() => {
// Lets move the node_modules back.
this.log.debug('moving node_modules back from app dir');
shell.mv(
path.join(this.$.env.paths.electronApp.appRoot, 'node_modules'),
this.$.env.paths.electronApp.nodeModules
);
if (extracted) {
// We need to create a full node modules back. In other words we want
// the extracted modules back.
extract.forEach(module => shell.cp(
'-rf',
path.join(this.$.env.paths.electronApp.extractedNodeModules, module),
path.join(this.$.env.paths.electronApp.nodeModules, module)
));
// Get the .bin back.
if (this.$.utils.exists(
this.$.env.paths.electronApp.extractedNodeModulesBin
)) {
shell.cp(
path.join(this.$.env.paths.electronApp.extractedNodeModulesBin, '*'),
path.join(this.$.env.paths.electronApp.nodeModules, '.bin')
);
}
}
this.log.debug('deleting source files');
const exclude = [this.$.env.paths.electronApp.nodeModules].concat(
[
this.$.env.paths.electronApp.appAsar,
this.$.env.paths.electronApp.packageJson
],
excludeFromDel
);
del.sync(
[`${this.$.env.paths.electronApp.root}${path.sep}*`].concat(
exclude.map(pathToExclude => `!${pathToExclude}`)
),
{ force: true }
);
resolve();
}
);
});
}
/**
* Moves specified node modules to a separate directory.
* @param {Array} extract
* @returns {boolean}
*/
extractModules(extract) {
const ext = ['.js', '.bat', '.sh', '.cmd', ''];
if (extract.length > 0) {
if (this.$.utils.exists(this.$.env.paths.electronApp.extractedNodeModules)) {
shell.rm('-rf', this.$.env.paths.electronApp.extractedNodeModules);
}
fs.mkdirSync(this.$.env.paths.electronApp.extractedNodeModules);
fs.mkdirSync(this.$.env.paths.electronApp.extractedNodeModulesBin);
extract.forEach((module) => {
fs.renameSync(
path.join(this.$.env.paths.electronApp.appRoot, 'node_modules', module),
path.join(this.$.env.paths.electronApp.extractedNodeModules, module),
);
// Move bins.
this.extractBin(module, ext);
});
return true;
}
return false;
}
/**
* Extracts the bin files associated with a certain node modules.
*
* @param module
* @param ext
*/
extractBin(module, ext) {
let packageJson;
try {
packageJson = JSON.parse(
fs.readFileSync(
path.join(
this.$.env.paths.electronApp.extractedNodeModules, module, 'package.json'
),
'utf8'
)
);
} catch (e) {
packageJson = {};
}
const bins = ('bin' in packageJson && typeof packageJson.bin === 'object') ? Object.keys(packageJson.bin) : [];
if (bins.length > 0) {
bins.forEach((bin) => {
ext.forEach((extension) => {
const binFilePath = path.join(
this.$.env.paths.electronApp.appRoot,
'node_modules',
'.bin',
`${bin}${extension}`
);
if (this.$.utils.exists(binFilePath) ||
this.$.utils.symlinkExists(binFilePath)
) {
fs.renameSync(
binFilePath,
path.join(
this.$.env.paths.electronApp.extractedNodeModulesBin,
`${bin}${extension}`
)
);
}
});
});
}
}
/**
* Merges the `extract` field with automatically detected modules.
*/
getModulesToExtract() {
const binaryModulesDetector =
new BinaryModuleDetector(this.$.env.paths.electronApp.nodeModules);
const toBeExtracted = binaryModulesDetector.detect();
let { extract } = this.$.desktop.getSettings();
if (!Array.isArray(extract)) {
extract = [];
}
const merge = {};
toBeExtracted.concat(extract).forEach((module) => {
merge[module] = true;
});
extract = Object.keys(merge);
if (extract.length > 0) {
this.log.verbose(`resultant modules to extract list is: ${extract.join(', ')}`);
}
return extract;
}
/**
* Calculates a md5 from all dependencies.
*/
calculateCompatibilityVersion() {
this.log.verbose('calculating compatibility version');
const settings = this.$.desktop.getSettings();
if (('desktopHCPCompatibilityVersion' in settings)) {
this.compatibilityVersion = `${settings.desktopHCPCompatibilityVersion}`;
this.log.warn(`compatibility version overridden to ${this.compatibilityVersion}`);
return;
}
const md5 = crypto.createHash('md5');
let dependencies = this.depsManager.getDependencies();
const dependenciesSorted = Object.keys(dependencies).sort();
dependencies = dependenciesSorted.map(dependency =>
`${dependency}:${dependencies[dependency]}`);
const mainCompatibilityVersion = this.$.getVersion().split('.');
this.log.debug('meteor-desktop compatibility version is ',
`${mainCompatibilityVersion[0]}`);
dependencies.push(
`meteor-desktop:${mainCompatibilityVersion[0]}`
);
const desktopCompatibilityVersion = settings.version.split('.')[0];
this.log.debug('.desktop compatibility version is ', desktopCompatibilityVersion);
dependencies.push(
`desktop-app:${desktopCompatibilityVersion}`
);
if (process.env.METEOR_DESKTOP_DEBUG_DESKTOP_COMPATIBILITY_VERSION ||
process.env.METEOR_DESKTOP_DEBUG
) {
this.log.debug(`compatibility version calculated from ${JSON.stringify(dependencies)}`);
}
md5.update(JSON.stringify(dependencies));
this.compatibilityVersion = md5.digest('hex');
}
async init() {
try {
await this.$.electron.init();
await this.$.electronBuilder.init();
} catch (e) {
this.log.warn('error occurred while initialising electron and electron-builder integration', e);
process.exit(1);
}
}
/**
* Runs all necessary tasks to build the desktopified app.
*/
async build(run = false) {
// TODO: refactor to a task runner
this.log.info('scaffolding');
if (!this.$.desktop.check()) {
if (!this.$.env.options.scaffold) {
this.log.error('seems that you do not have a .desktop dir in your project or it is' +
' corrupted. Run \'npm run desktop -- init\' to get a new one.');
// Do not fail, so that npm will not print his error stuff to console.
process.exit(0);
} else {
this.$.desktop.scaffold();
this.$.meteorApp.updateGitIgnore();
}
}
await this.init();
try {
this.$.meteorApp.updateGitIgnore();
} catch (e) {
this.log.warn(`error occurred while adding ${this.$.env.paths.electronApp.rootName}` +
'to .gitignore: ', e);
}
try {
await this.$.meteorApp.removeDeprecatedPackages();
} catch (e) {
this.log.error('error while removing deprecated packages: ', e);
process.exit(1);
}
try {
await this.$.meteorApp.ensureDesktopHCPPackages();
} catch (e) {
this.log.error('error while checking for required packages: ', e);
process.exit(1);
}
try {
await this.scaffold.make();
} catch (e) {
this.log.error('error while scaffolding: ', e);
process.exit(1);
}
try {
const fileName = '.npmrc';
const dirName = '.meteor/desktop-build';
if (fs.existsSync(dirName) && fs.existsSync(fileName)) {
fs.copyFileSync(fileName, `${dirName}/${fileName}`);
}
} catch (e) {
this.log.warn('error while copying .npmrc', e);
}
try {
await this.exposeElectronModules();
} catch (e) {
this.log.error('error while exposing electron modules: ', e);
process.exit(1);
}
try {
this.updatePackageJsonFields();
} catch (e) {
this.log.error('error while updating package.json: ', e);
}
try {
this.updateDependenciesList();
} catch (e) {
this.log.error('error while merging dependencies list: ', e);
}
try {
this.calculateCompatibilityVersion();
} catch (e) {
this.log.error('error while calculating compatibility version: ', e);
process.exit(1);
}
try {
await this.handleTemporaryNodeModules();
} catch (e) {
this.log.error('error occurred while handling temporary node_modules: ', e);
process.exit(1);
}
let nodeModulesRemoved;
try {
nodeModulesRemoved = await this.handleStateOfNodeModules();
} catch (e) {
this.log.error('error occurred while clearing node_modules: ', e);
process.exit(1);
}
try {
await this.rebuildDeps(true);
} catch (e) {
this.log.error('error occurred while installing node_modules: ', e);
process.exit(1);
}
if (!nodeModulesRemoved) {
try {
await this.rebuildDeps();
} catch (e) {
this.log.error('error occurred while rebuilding native node modules: ', e);
process.exit(1);
}
}
try {
await this.linkNpmPackages();
} catch (e) {
this.log.error(`linking packages failed: ${e}`);
process.exit(1);
}
try {
await this.installLocalNodeModules();
} catch (e) {
this.log.error('error occurred while installing local node modules: ', e);
process.exit(1);
}
try {
await this.ensureMeteorDependencies();
} catch (e) {
this.log.error('error occurred while ensuring meteor dependencies are installed: ', e);
process.exit(1);
}
if (this.$.env.isProductionBuild()) {
try {
await this.packSkeletonToAsar();
} catch (e) {
this.log.error('error while packing skeleton to asar: ', e);
process.exit(1);
}
}
// TODO: find a way to avoid copying .desktop to a temp location
try {
this.copyDesktopToDesktopTemp();
} catch (e) {
this.log.error('error while copying .desktop to a temporary location: ', e);
process.exit(1);
}
try {
await this.updateSettingsJsonFields();
} catch (e) {
this.log.error('error while updating settings.json: ', e);
process.exit(1);
}
try {
await this.excludeFilesFromArchive();
} catch (e) {
this.log.error('error while excluding files from packing to asar: ', e);
process.exit(1);
}
try {
await this.transpileAndMinify();
} catch (e) {
this.log.error('error while transpiling or minifying: ', e);
}
try {
await this.packDesktopToAsar();
} catch (e) {
this.log.error('error occurred while packing .desktop to asar: ', e);
process.exit(1);
}
try {
await this.getMeteorClientBuild();
} catch (e) {
this.log.error('error occurred during getting meteor mobile build: ', e);
}
if (run) {
this.log.info('running');
this.$.electron.run();
} else {
this.log.info('built');
}
}
/**
* Copies the `exposedModules` setting from `settings.json` into `preload.js` modifying its code
* so that the script will have it hardcoded.
*/
exposeElectronModules() {
const { exposedModules } = this.$.desktop.getSettings();
if (exposedModules && Array.isArray(exposedModules) && exposedModules.length > 0) {
let preload = fs.readFileSync(this.$.env.paths.electronApp.preload, 'utf8');
const modules = this.$.desktop.getSettings()
.exposedModules
.reduce(
// eslint-disable-next-line no-return-assign,no-param-reassign
(prev, module) => (prev += `'${module}', `, prev), ''
);
preload = preload.replace('const exposedModules = [', `const exposedModules = [${modules}`);
fs.writeFileSync(this.$.env.paths.electronApp.preload, preload);
}
}
/**
* Ensures all required dependencies are added to the Meteor project.
* @returns {Promise.<void>}
*/
async ensureMeteorDependencies() {
let packages = [];
const packagesWithVersion = [];
let plugins = 'plugins [';
Object.keys(this.$.desktop.getDependencies().plugins).forEach((plugin) => {
// Read package.json of the plugin.
const packageJson =
JSON.parse(
fs.readFileSync(
path.join(
this.$.env.paths.electronApp.nodeModules, plugin, 'package.json'
),
'utf8'
)
);
if ('meteorDependencies' in packageJson && typeof packageJson.meteorDependencies === 'object') {
plugins += `${plugin}, `;
packages.unshift(...Object.keys(packageJson.meteorDependencies));
packagesWithVersion.unshift(...packages.map((packageName) => {
if (packageJson.meteorDependencies[packageName] === '@version') {
return `${packageName}@${packageJson.version}`;
}
return `${packageName}@${packageJson.meteorDependencies[packageName]}`;
}));
}
});
const packagesCount = packages.length;
packages = packages.filter(value => !this.deprectatedPlugins.includes(value));
if (packagesCount !== packages.length) {
this.log.warn('you have some deprecated meteor desktop plugins in your settings, please remove ' +
`them (deprecated plugins: ${this.deprectatedPlugins.join(', ')})`);
}
if (packages.length > 0) {
plugins = `${plugins.substr(0, plugins.length - 2)}]`;
try {
await this.$.meteorApp.meteorManager.ensurePackages(
packages, packagesWithVersion, plugins
);
} catch (e) {
throw new Error(e);
}
}
}
/**
* Builds meteor app.
*/
async getMeteorClientBuild() {
await this.$.meteorApp.build();
}
/**
* Removes node_modules if needed.
* @returns {Promise<void>}
*/
async handleStateOfNodeModules() {
if (this.$.env.isProductionBuild() || this.$.env.options.ia32) {
if (!this.$.env.isProductionBuild()) {
this.log.info('clearing node_modules because we need to have it clear for ia32 rebuild');
} else {
this.log.info('clearing node_modules because this is a production build');
}
try {
await this.$.utils.rmWithRetries(
'-rf', this.$.env.paths.electronApp.nodeModules
);
} catch (e) {
throw new Error(e);
}
return true;
}
return false;
}
/**
* If there is a temporary node_modules folder and no node_modules folder, we will
* restore it, as it might be a leftover from an interrupted flow.
* @returns {Promise<void>}
*/
async handleTemporaryNodeModules() {
if (this.$.utils.exists(this.$.env.paths.electronApp.tmpNodeModules)) {
if (!this.$.utils.exists(this.$.env.paths.electronApp.nodeModules)) {
this.log.debug('moving temp node_modules back');
shell.mv(
this.$.env.paths.electronApp.tmpNodeModules,
this.$.env.paths.electronApp.nodeModules
);
} else {
// If there is a node_modules folder, we should clear the temporary one.
this.log.debug('clearing temp node_modules because new one is already created');
try {
await this.$.utils.rmWithRetries(
'-rf', this.$.env.paths.electronApp.tmpNodeModules
);
} catch (e) {
throw new Error(e);
}
}
}
}
/**
* Runs npm link for every package specified in settings.json->linkPackages.
*/
async linkNpmPackages() {
if (this.$.env.isProductionBuild()) {
return;
}
const settings = this.$.desktop.getSettings();
const promises = [];
if ('linkPackages' in this.$.desktop.getSettings()) {
if (Array.isArray(settings.linkPackages)) {
settings.linkPackages.forEach(packageName =>
promises.push(
this.$.meteorApp.runNpm(
['link', packageName],
undefined,
this.$.env.paths.electronApp.root
)
)
);
}
}
await Promise.all(promises);
}
/**
* Runs npm in the electron app to get the dependencies installed.
* @returns {Promise}
*/
async ensureDeps() {
this.log.info('installing dependencies');
if (this.$.utils.exists(this.$.env.paths.electronApp.nodeModules)) {
this.log.debug('running npm prune to wipe unneeded dependencies');
try {
await this.runNpm(['prune']);
} catch (e) {
throw new Error(e);
}
}
try {
await this.runNpm(['install'], this.$.env.stdio);
} catch (e) {
throw new Error(e);
}
}
/**
* Warns if plugins version are outdated in compare to the newest scaffold.
* @param {Object} pluginsVersions - current plugins versions from settings.json
*/
checkPluginsVersion(pluginsVersions) {
const settingsJson = JSON.parse(
fs.readFileSync(path.join(this.$.env.paths.scaffold, 'settings.json'))
);
const scaffoldPluginsVersion = this.$.desktop.getDependencies(settingsJson, false).plugins;
Object.keys(pluginsVersions).forEach((pluginName) => {
if (pluginName in scaffoldPluginsVersion &&
scaffoldPluginsVersion[pluginName] !== pluginsVersions[pluginName] &&
semver.lt(pluginsVersions[pluginName], scaffoldPluginsVersion[pluginName])
) {
this.log.warn(`you are using outdated version ${pluginsVersions[pluginName]} of ` +
`${pluginName}, the suggested version to use is ` +
`${scaffoldPluginsVersion[pluginName]}`);
}
});
}
/**
* Merges core dependency list with the dependencies from .desktop.
*/
updateDependenciesList() {
this.log.info('updating list of package.json\'s dependencies');
const desktopDependencies = this.$.desktop.getDependencies();
this.checkPluginsVersion(desktopDependencies.plugins);
this.log.debug('merging settings.json[dependencies]');
this.depsManager.mergeDependencies(
'settings.json[dependencies]',
desktopDependencies.fromSettings
);
this.log.debug('merging settings.json[plugins]');
this.depsManager.mergeDependencies(
'settings.json[plugins]',
desktopDependencies.plugins
);
this.log.debug('merging dependencies from modules');
Object.keys(desktopDependencies.modules).forEach(module =>
this.depsManager.mergeDependencies(
`module[${module}]`,
desktopDependencies.modules[module]
));
this.packageJson.dependencies = this.depsManager.getRemoteDependencies();
this.packageJson.localDependencies = this.depsManager.getLocalDependencies();
this.log.debug('writing updated package.json');
fs.writeFileSync(
this.$.env.paths.electronApp.packageJson, JSON.stringify(this.packageJson, null, 2)
);
}
/**
* Install node modules from local paths using local-install.
*
* @param {string} arch
* @returns {Promise}
*/
installLocalNodeModules(arch = this.$.env.options.ia32 || process.arch === 'ia32' ? 'ia32' : 'x64') {
const localDependencies = _.values(this.packageJson.localDependencies);
if (localDependencies.length === 0) {
return Promise.resolve();
}
this.log.info('installing local node modules');
const lastRebuild = this.$.electronBuilder.prepareLastRebuildObject(arch);
const env = this.$.electronBuilder.getGypEnv(lastRebuild.frameworkInfo, lastRebuild.platform, lastRebuild.arch);
const installer = new LocalInstaller(
{ [this.$.env.paths.electronApp.root]: localDependencies },
{ npmEnv: env }
);
progress(installer);
return installer.install();
}
/**
* Rebuild binary dependencies against Electron's node headers.
* @returns {Promise}
*/
rebuildDeps(install = false) {
if (install) {
this.log.info('issuing node_modules install from electron-builder');
} else {
this.log.info('issuing native modules rebuild from electron-builder');
}
const arch = this.$.env.options.ia32 || process.arch === 'ia32' ? 'ia32' : 'x64';
if (this.$.env.options.ia32) {
this.log.verbose('forcing rebuild for 32bit');
} else {
this.log.verbose(`rebuilding for ${arch}`);
}
return this.$.electronBuilder.installOrRebuild(arch, undefined, install);
}
/**
* Update package.json fields accordingly to what is set in settings.json.
*
* packageJson.name = settings.projectName
* packageJson.version = settings.version
* packageJson.* = settings.packageJsonFields
*/
updatePackageJsonFields() {
this.log.verbose('updating package.json fields');
const settings = this.$.desktop.getSettings();
/** @type {desktopSettings} */
const packageJson = this.scaffold.getDefaultPackageJson();
packageJson.version = settings.version;
if ('packageJsonFields' in settings) {
assignIn(packageJson, settings.packageJsonFields);
}
assignIn(packageJson, { name: settings.projectName });
this.log.debug('writing updated package.json');
fs.writeFileSync(
this.$.env.paths.electronApp.packageJson, JSON.stringify(packageJson, null, 4)
);
this.packageJson = packageJson;
}
/**
* Updates settings.json with env (prod/dev) information and versions.
*/
async updateSettingsJsonFields() {
this.log.debug('updating settings.json fields');
const settings = this.$.desktop.getSettings();
// Save versions.
settings.compatibilityVersion = this.compatibilityVersion;
// Pass information about build type to the settings.json.
settings.env = (this.$.env.isProductionBuild()) ?
'prod' : 'dev';
const version = await this.$.desktop.getHashVersion();
settings.desktopVersion = `${version}_${settings.env}`;
settings.meteorDesktopVersion = this.$.getVersion();
if (this.$.env.options.prodDebug) {
settings.prodDebug = true;
}
fs.writeFileSync(
this.$.env.paths.desktopTmp.settings, JSON.stringify(settings, null, 4)
);
}
/**
* Copies files from prepared .desktop to desktop.asar in electron app.
*/
packDesktopToAsar() {
this.log.info('packing .desktop to asar');
return new Promise((resolve, reject) => {
asar.createPackage(
this.$.env.paths.desktopTmp.root,
this.$.env.paths.electronApp.desktopAsar,
() => {
this.log.verbose('clearing temporary .desktop');
this.$.utils
.rmWithRetries('-rf', this.$.env.paths.desktopTmp.root)
.then(() => {
resolve();
})
.catch((e) => {
reject(e);
});
resolve();
}
);
});
}
/**
* Makes a temporary copy of .desktop.
*/
copyDesktopToDesktopTemp() {
this.log.verbose('copying .desktop to temporary location');
shell.cp('-rf', this.$.env.paths.desktop.root, this.$.env.paths.desktopTmp.root);
// Remove test files.
del.sync([
path.join(this.$.env.paths.desktopTmp.root, '**', '*.test.js')
], { force: true });
}
/**
* Runs babel and uglify over .desktop if requested.
*/
async transpileAndMinify() {
this.log.info('transpiling and uglifying');
const settings = this.$.desktop.getSettings();
const options = 'uglifyOptions' in settings ? settings.uglifyOptions : {};
const uglifyingEnabled = 'uglify' in settings && !!settings.uglify;
const preset = presetEnv({ assertVersion: () => { } }, { targets: { node: '12' } });
const { data: files } = await this.$.utils.readDir(this.$.env.paths.desktopTmp.root);
files.forEach((file) => {
if (file.endsWith('.js')) {
let { code } = transformFileSync(file, {
presets: [preset]
});
let error;
if (settings.env === 'prod' && uglifyingEnabled) {
({ code, error } = uglify.minify(code, options));
}
if (error) {
throw new Error(error);
}
fs.writeFileSync(file, code);
}
});
}
/**
* Moves all the files that should not be packed into asar into a safe location which is the
* 'extracted' dir in the electron app.
*/
async excludeFilesFromArchive() {
this.log.info('excluding files from packing');
// Ensure empty `extracted` dir
try {
await this.$.utils.rmWithRetries('-rf', this.$.env.paths.electronApp.extracted);
} catch (e) {
throw new Error(e);
}
shell.mkdir(this.$.env.paths.electronApp.extracted);
const configs = this.$.desktop.gatherModuleConfigs();
// Move files that should not be asar'ed.
configs.forEach((config) => {
const moduleConfig = config;
if ('extract' in moduleConfig) {
if (!Array.isArray(moduleConfig.extract)) {
moduleConfig.extract = [moduleConfig.extract];
}
moduleConfig.extract.forEach((file) => {
this.log.debug(`excluding ${file} from ${config.name}`);
const filePath = path.join(
this.$.env.paths.desktopTmp.modules, moduleConfig.dirName, file
);
const destinationPath = path.join(
this.$.env.paths.electronApp.extracted, moduleConfig.dirName
);
if (!this.$.utils.exists(destinationPath)) {
shell.mkdir(destinationPath);
}
shell.mv(filePath, destinationPath);
});
}
});
}
}