Skip to content
Permalink
Browse files

feat(generic): remove electron-compile, make forge less opinionated a…

…nd quite vanilla

BREAKING CHANGE
  • Loading branch information
MarshallOfSound committed Feb 14, 2018
1 parent f2094ca commit d59695ecdb47a8a0865bc34c77c4bcc0c4302a32
@@ -62,9 +62,6 @@ npm start

With these goals in mind, under the hood this project uses, among others:

* [`electron-compile`](https://github.com/electron/electron-compile): a tool
that lets you use modern and futuristic languages inside Electron without
worrying about transpiling or build tooling.
* [`electron-rebuild`](https://github.com/electron/electron-rebuild):
Automatically recompiles native Node.js modules against the correct
Electron version.
@@ -197,15 +194,15 @@ You can set `electronPackagerConfig` with any of the options from
* `arch` (use the `--arch` Forge command line argument instead, so it's available to all of Forge)
* `asar.unpack` (use `asar.unpackDir` instead)
* `dir` (use the `cwd` Forge command line argument instead, so it's available to all of Forge)
* `electronVersion` (uses the exact version specified for `electron-prebuilt-compile` in your `devDependencies`)
* `electronVersion` (uses the exact version specified for `electron` in your `devDependencies`)
* `out`
* `platform` (use the `--platform` Forge command line argument instead, so it's available to all of Forge)
* `quiet`

You can set `electronRebuildConfig` with any of the options from
[Electron Rebuild](https://github.com/electron/electron-rebuild#how-can-i-integrate-this-into-grunt--gulp--whatever), except:

* `electronVersion`/`--version` (uses the exact version specified for `electron-prebuilt-compile` in your `devDependencies`)
* `electronVersion`/`--version` (uses the exact version specified for `electron` in your `devDependencies`)
* `arch`/`--arch` (use the `--arch` Forge command line argument instead, so it's available to all of Forge)
* `buildPath`/`--module-dir` (uses your project's `node_modules`)

@@ -10,7 +10,6 @@ running `electron-forge`. This will print debug information from the specified m
value of the environment variable is a comma-separated list of modules which support this logging
feature. Known modules include:

* `electron-compile:*`
* `electron-download`
* `electron-forge:*` (always use this one before filing an issue)
* `electron-installer-debian`
@@ -1,6 +1,5 @@
import debug from 'debug';
import fs from 'fs-extra';
import inquirer from 'inquirer';
import path from 'path';

import initGit from '../init/init-git';
@@ -12,7 +11,6 @@ import { info, warn } from '../util/messages';
import installDepList from '../util/install-dependencies';
import readPackageJSON from '../util/read-package-json';
import confirmIfInteractive from '../util/confirm-if-interactive';
import { yarnOrNpmSpawn, hasYarn } from '../util/yarn-or-npm';

const d = debug('electron-forge:import');

@@ -27,7 +25,6 @@ const d = debug('electron-forge:import');
/**
* Attempt to import a given module directory to the Electron Forge standard.
*
* - Replaces the prebuilt electron package with the one that integrates with `electron-compile`
* - Sets up `git` and the correct NPM dependencies
* - Adds a template forge config to `package.json`
*
@@ -68,18 +65,6 @@ export default async (providedOptions = {}) => {
}
}

// eslint-disable-next-line max-len
const shouldChangeMain = await confirmIfInteractive(interactive, 'Do you want us to change the "main" attribute of your package.json? If you are currently using babel and pointing to a "build" directory say yes.', false);
if (shouldChangeMain) {
const { newMain } = await inquirer.createPromptModule()({
type: 'input',
name: 'newMain',
default: packageJSON.main,
message: 'Enter the relative path to your uncompiled main file',
});
packageJSON.main = newMain;
}

packageJSON.dependencies = packageJSON.dependencies || {};
packageJSON.devDependencies = packageJSON.devDependencies || {};

@@ -96,13 +81,8 @@ export default async (providedOptions = {}) => {
'electron-winstaller': 'already uses this module as a transitive dependency',
};

let electronName;
for (const key of keys) {
if (key === 'electron' || key === 'electron-prebuilt') {
delete packageJSON.dependencies[key];
delete packageJSON.devDependencies[key];
electronName = key;
} else if (buildToolPackages[key]) {
if (buildToolPackages[key]) {
const explanation = buildToolPackages[key];
// eslint-disable-next-line max-len
const shouldRemoveDependency = await confirmIfInteractive(interactive, `Do you want us to remove the "${key}" dependency in package.json? Electron Forge ${explanation}.`);
@@ -139,48 +119,21 @@ export default async (providedOptions = {}) => {
});
};

let electronVersion;
if (electronName) {
const electronPackageJSON = await readPackageJSON(path.resolve(dir, 'node_modules', electronName));
electronVersion = electronPackageJSON.version;
packageJSON.devDependencies['electron-prebuilt-compile'] = electronVersion;
}

await writeChanges();

if (electronName) {
await asyncOra('Pruning deleted modules', async () => {
d('attempting to prune node_modules in:', dir);
await yarnOrNpmSpawn(hasYarn() ? [] : ['prune'], {
cwd: dir,
stdio: 'ignore',
});
});
}

await asyncOra('Installing dependencies', async () => {
d('deleting old dependencies forcefully');
await fs.remove(path.resolve(dir, 'node_modules/.bin/electron'));
await fs.remove(path.resolve(dir, 'node_modules/.bin/electron.cmd'));

if (electronName) {
await fs.remove(path.resolve(dir, 'node_modules', electronName));
}

d('installing dependencies');
await installDepList(dir, deps);

d('installing devDependencies');
await installDepList(dir, devDeps, true);

d('installing exactDevDependencies');
await installDepList(dir, exactDevDeps.map((dep) => {
if (dep === 'electron-prebuilt-compile') {
return `${dep}@${electronVersion || 'latest'}`;
}

return dep;
}), true, true);
await installDepList(dir, exactDevDeps, true, true);
});

packageJSON = await readPackageJSON(dir);
@@ -205,39 +158,9 @@ export default async (providedOptions = {}) => {
}
});

let babelConfig = packageJSON.babel;
const babelPath = path.resolve(dir, '.babelrc');
if (!babelConfig && await fs.pathExists(babelPath)) {
babelConfig = await fs.readJson(babelPath, 'utf8');
}

if (babelConfig) {
await asyncOra('Porting original babel config', async () => {
let compileConfig = {};
const compilePath = path.resolve(dir, '.compilerc');
if (await fs.pathExists(compilePath)) {
compileConfig = await fs.readJson(compilePath, 'utf8');
}

await fs.writeJson(compilePath, Object.assign(compileConfig, {
'application/javascript': babelConfig,
}), { spaces: 2 });
});

info(interactive, 'NOTE: You might be able to remove your `.compilerc` file completely if you are only using the `es2016` and `react` presets'.yellow);
}

info(interactive, `
We have ATTEMPTED to convert your app to be in a format that electron-forge understands.
Nothing much will have changed but we added the ${'"electron-prebuilt-compile"'.cyan} dependency. This is \
the dependency you must version bump to get newer versions of Electron.
We also tried to import any build tooling you already had but we can't get everything. You might need to convert any CLI/gulp/grunt tasks yourself.
Also please note if you are using \`preload\` scripts you need to follow the steps outlined \
at https://github.com/electron-userland/electron-forge/wiki/Using-%27preload%27-scripts
Thanks for using ${'"electron-forge"'.green}!!!`);
};
@@ -4,7 +4,6 @@ import initCustom from '../init/init-custom';
import initDirectory from '../init/init-directory';
import initGit from '../init/init-git';
import initNPM from '../init/init-npm';
import initStandardFix from '../init/init-standard-fix';
import initStarter from '../init/init-starter-files';

import asyncOra from '../util/ora-handler';
@@ -15,7 +14,6 @@ const d = debug('electron-forge:init');
* @typedef {Object} InitOptions
* @property {string} [dir=process.cwd()] The path to the app to be initialized
* @property {boolean} [interactive=false] Whether to use sensible defaults or prompt the user visually
* @property {string} [lintStyle=airbnb] The lintStyle to pass through to the template creator
* @property {boolean} [copyCIFiles=false] Whether to copy Travis and AppVeyor CI files
* @property {string} [template] The custom template to use. If left empty, the default template is used
*/
@@ -28,34 +26,21 @@ const d = debug('electron-forge:init');
*/
export default async (providedOptions = {}) => {
// eslint-disable-next-line prefer-const, no-unused-vars
let { dir, interactive, lintStyle, copyCIFiles, template } = Object.assign({
let { dir, interactive, copyCIFiles, template } = Object.assign({
dir: process.cwd(),
interactive: false,
lintStyle: 'airbnb',
copyCIFiles: false,
template: null,
}, providedOptions);
asyncOra.interactive = interactive;

d(`Initializing in: ${dir}`);

if (!template) {
lintStyle = lintStyle.toLowerCase();
if (!['airbnb', 'standard'].includes(lintStyle)) {
d(`Unrecognized lintStyle argument: '${lintStyle}' -- defaulting to 'airbnb'`);
lintStyle = 'airbnb';
}
}

await initDirectory(dir, interactive);
await initGit(dir);
await initStarter(dir, { lintStyle: template ? undefined : lintStyle, copyCIFiles });
await initNPM(dir, template ? undefined : lintStyle);
if (!template) {
if (lintStyle === 'standard') {
await initStandardFix(dir);
}
} else {
await initCustom(dir, template, lintStyle);
await initStarter(dir, { copyCIFiles });
await initNPM(dir);
if (template) {
await initCustom(dir, template);
}
};
@@ -12,6 +12,7 @@ import readPackageJSON from '../util/read-package-json';
import { requireSearchRaw } from '../util/require-search';
import resolveDir from '../util/resolve-dir';
import getCurrentOutDir from '../util/out-dir';
import getElectronVersion from '../util/electron-version';

import packager from './package';

@@ -129,7 +130,7 @@ export default async (providedOptions = {}) => {

await runHook(forgeConfig, 'preMake');

for (const targetArch of parseArchs(platform, arch, packageJSON.devDependencies['electron-prebuilt-compile'])) {
for (const targetArch of parseArchs(platform, arch, getElectronVersion(packageJSON))) {
const packageDir = path.resolve(outDir, `${appName}-${actualTargetPlatform}-${targetArch}`);
if (!(await fs.pathExists(packageDir))) {
throw new Error(`Couldn't find packaged app at: ${packageDir}`);
@@ -11,12 +11,12 @@ import getForgeConfig from '../util/forge-config';
import runHook from '../util/hook';
import { warn } from '../util/messages';
import realOra, { fakeOra } from '../util/ora';
import packagerCompileHook from '../util/compile-hook';
import readPackageJSON from '../util/read-package-json';
import rebuildHook from '../util/rebuild';
import requireSearch from '../util/require-search';
import resolveDir from '../util/resolve-dir';
import getCurrentOutDir from '../util/out-dir';
import getElectronVersion from '../util/electron-version';

const d = debug('electron-forge:packager');

@@ -102,15 +102,15 @@ export default async (providedOptions = {}) => {
prepareCounter += 1;
prepareSpinner = ora(`Preparing to Package Application for arch: ${(prepareCounter === 2 ? 'armv7l' : 'x64').cyan}`).start();
}
await fs.remove(path.resolve(buildPath, 'node_modules/electron-compile/test'));
const bins = await pify(glob)(path.join(buildPath, '**/.bin/**/*'));
for (const bin of bins) {
await fs.remove(bin);
}
done();
}, async (...args) => {
}, async (buildPath, electronVersion, pPlatform, pArch, done) => {
prepareSpinner.succeed();
await packagerCompileHook(dir, ...args);
await runHook(forgeConfig, 'packageAfterCopy', buildPath, electronVersion, pPlatform, pArch);
done();
},
];

@@ -136,6 +136,11 @@ export default async (providedOptions = {}) => {
afterPruneHooks.push(...resolveHooks(forgeConfig.electronPackagerConfig.afterPrune, dir));
}

afterPruneHooks.push(async (buildPath, electronVersion, pPlatform, pArch, done) => {
await runHook(forgeConfig, 'packageAfterPrune', buildPath, electronVersion, pPlatform, pArch);
done();
});

const packageOpts = Object.assign({
asar: false,
overwrite: true,
@@ -147,12 +152,9 @@ export default async (providedOptions = {}) => {
arch,
platform,
out: outDir,
electronVersion: packageJSON.devDependencies['electron-prebuilt-compile'],
electronVersion: getElectronVersion(packageJSON),
});
packageOpts.quiet = true;
if (typeof packageOpts.asar === 'object' && packageOpts.asar.unpack) {
throw new Error('electron-compile does not support asar.unpack yet. Please use asar.unpackDir');
}

if (!packageJSON.version && !packageOpts.appVersion) {
// eslint-disable-next-line max-len
@@ -8,6 +8,7 @@ import rebuild from '../util/rebuild';
import resolveDir from '../util/resolve-dir';
import getForgeConfig from '../util/forge-config';
import runHook from '../util/hook';
import getElectronVersion from '../util/electron-version';

/**
* @typedef {Object} StartOptions
@@ -52,7 +53,21 @@ export default async (providedOptions = {}) => {

const forgeConfig = await getForgeConfig(dir);

await rebuild(dir, packageJSON.devDependencies['electron-prebuilt-compile'], process.platform, process.arch, forgeConfig.electronRebuildConfig);
await rebuild(dir, getElectronVersion(packageJSON), process.platform, process.arch, forgeConfig.electronRebuildConfig);

await runHook(forgeConfig, 'generateAssets');

// If a plugin has taken over the start command let's stop here
const spawnedPluginChild = await forgeConfig.pluginInterface.overrideStartLogic({
dir,
appPath,
interactive,
enableLogging,
args,
runAsNode,
inspect,
});
if (spawnedPluginChild) return spawnedPluginChild;

const spawnOpts = {
cwd: dir,
@@ -75,10 +90,8 @@ export default async (providedOptions = {}) => {

let spawned;

await runHook(forgeConfig, 'generateAssets');

await asyncOra('Launching Application', async () => {
spawned = spawn(process.execPath, [path.resolve(dir, 'node_modules/electron-prebuilt-compile/lib/cli'), appPath].concat(args), spawnOpts);
spawned = spawn(process.execPath, [path.resolve(dir, 'node_modules/electron/cli'), appPath].concat(args), spawnOpts);
});

return spawned;
@@ -10,7 +10,6 @@ import { init } from './api';
.version(require('../package.json').version)
.arguments('[name]')
.option('-t, --template [name]', 'Name of the forge template to use')
.option('-l, --lintStyle [style]', 'Linting standard to follow. For the default template it can be "airbnb" or "standard"', 'airbnb')
.option('-c, --copy-ci-files', 'Whether to copy the templated CI files (defaults to false)', false)
.action((name) => {
if (!name) return;
@@ -25,7 +24,6 @@ import { init } from './api';
const initOpts = {
dir,
interactive: true,
lintStyle: program.lintStyle,
copyCIFiles: !!program.copyCiFiles,
};
if (program.template) initOpts.template = program.template;
@@ -11,7 +11,7 @@ import ora from '../util/ora';

const d = debug('electron-forge:init:custom');

export default async (dir, template, lintStyle) => {
export default async (dir, template) => {
let templateModulePath;
await asyncOra(`Locating custom template: "${template}"`, async () => {
try {
@@ -57,6 +57,6 @@ export default async (dir, template, lintStyle) => {
});

if (typeof templateModule.postCopy === 'function') {
await Promise.resolve(templateModule.postCopy(dir, ora, lintStyle));
await Promise.resolve(templateModule.postCopy(dir, ora));
}
};

0 comments on commit d59695e

Please sign in to comment.
You can’t perform that action at this time.