diff --git a/packages/api/core/src/api/import.ts b/packages/api/core/src/api/import.ts index 557b572b41..981788f249 100644 --- a/packages/api/core/src/api/import.ts +++ b/packages/api/core/src/api/import.ts @@ -83,9 +83,12 @@ export default async ({ let importExactDevDeps = ([] as string[]).concat(exactDevDeps); let packageJSON = await readRawPackageJson(dir); + if (!packageJSON.version) { + warn(interactive, chalk.yellow(`Please set the ${chalk.green('"version"')} in your application's package.json`)); + } if (packageJSON.config && packageJSON.config.forge) { if (packageJSON.config.forge.makers) { - warn(interactive, chalk.green('It looks like this project is already configured for Electron Forge')); + warn(interactive, chalk.green('Existing Electron Forge configuration detected')); if (typeof shouldContinueOnExisting === 'function') { if (!(await shouldContinueOnExisting())) { // TODO: figure out if we can just return early here @@ -93,7 +96,7 @@ export default async ({ process.exit(0); } } - } else if (typeof packageJSON.config.forge === 'string') { + } else if (!(typeof packageJSON.config.forge === 'object')) { warn( interactive, chalk.yellow( @@ -187,23 +190,23 @@ export default async ({ await installDepList(dir, importExactDevDeps, DepType.DEV, DepVersionRestriction.EXACT); }); - packageJSON = await readRawPackageJson(dir); - - if (!packageJSON.version) { - warn(interactive, chalk.yellow('Please set the "version" in your application\'s package.json')); - } - - packageJSON.config = packageJSON.config || {}; - const templatePackageJSON = await readRawPackageJson(baseTemplate.templateDir); - if (packageJSON.config.forge) { - if (typeof packageJSON.config.forge !== 'string') { - packageJSON.config.forge = merge(templatePackageJSON.config.forge, packageJSON.config.forge); + await asyncOra('Copying base template Forge configuration', async () => { + const pathToTemplateConfig = path.resolve(baseTemplate.templateDir, 'forge.config.js'); + + // if there's an existing config.forge object in package.json + if (packageJSON?.config?.forge && typeof packageJSON.config.forge === 'object') { + d('detected existing Forge config in package.json, merging with base template Forge config'); + // eslint-disable-next-line @typescript-eslint/no-var-requires + const templateConfig = require(path.resolve(baseTemplate.templateDir, 'forge.config.js')); + packageJSON = await readRawPackageJson(dir); + merge(templateConfig, packageJSON.config.forge); // mutates the templateConfig object + await writeChanges(); + // otherwise, write to forge.config.js + } else { + d('writing new forge.config.js'); + await fs.copyFile(pathToTemplateConfig, path.resolve(dir, 'forge.config.js')); } - } else { - packageJSON.config.forge = templatePackageJSON.config.forge; - } - - await writeChanges(); + }); await asyncOra('Fixing .gitignore', async () => { if (await fs.pathExists(path.resolve(dir, '.gitignore'))) { @@ -218,8 +221,8 @@ export default async ({ interactive, ` -We have ATTEMPTED to convert your app to be in a format that electron-forge understands. +We have attempted to convert your app to be in a format that Electron Forge understands. -Thanks for using ${chalk.green('Electron Forge')}!!!` +Thanks for using ${chalk.green('Electron Forge')}!` ); }; diff --git a/packages/api/core/src/api/init-scripts/init-git.ts b/packages/api/core/src/api/init-scripts/init-git.ts index 2af5096978..c18163c1ee 100644 --- a/packages/api/core/src/api/init-scripts/init-git.ts +++ b/packages/api/core/src/api/init-scripts/init-git.ts @@ -6,7 +6,7 @@ import debug from 'debug'; const d = debug('electron-forge:init:git'); export default async (dir: string): Promise => { - await asyncOra('Initializing Git Repository', async () => { + await asyncOra('Initializing Git repository', async () => { await new Promise((resolve, reject) => { exec( 'git rev-parse --show-toplevel', diff --git a/packages/api/core/src/util/forge-config.ts b/packages/api/core/src/util/forge-config.ts index 99e87b92e6..842a27dd04 100644 --- a/packages/api/core/src/util/forge-config.ts +++ b/packages/api/core/src/util/forge-config.ts @@ -1,6 +1,6 @@ import path from 'path'; -import { ForgeConfig, IForgeResolvableMaker, ResolvedForgeConfig } from '@electron-forge/shared-types'; +import { ForgeConfig, ResolvedForgeConfig } from '@electron-forge/shared-types'; import fs from 'fs-extra'; import * as interpret from 'interpret'; import { template } from 'lodash'; @@ -16,15 +16,6 @@ const underscoreCase = (str: string) => .replace(/([a-z0-9])([A-Z])/g, '$1_$2') .toUpperCase(); -export type PackageJSONForInitialForgeConfig = { - name?: string; - config: { - forge: { - makers: Pick[]; - }; - }; -}; - // Why: needs access to Object methods and also needs to be able to match any interface. // eslint-disable-next-line @typescript-eslint/ban-types type ProxiedObject = object; diff --git a/packages/api/core/test/slow/api_spec_slow.ts b/packages/api/core/test/slow/api_spec_slow.ts index 51ec63ae58..f29abf6619 100644 --- a/packages/api/core/test/slow/api_spec_slow.ts +++ b/packages/api/core/test/slow/api_spec_slow.ts @@ -79,6 +79,10 @@ for (const nodeInstaller of ['npm', 'yarn']) { expect(await fs.pathExists(path.resolve(dir, 'node_modules/@electron-forge/cli')), '@electron-forge/cli should exist').to.equal(true); }); + it('should create a forge.config.js', async () => { + await expectProjectPathExists(dir, 'forge.config.js', 'file'); + }); + describe('lint', () => { it('should initially pass the linting process', () => expectLintToPass(dir)); }); @@ -230,13 +234,21 @@ describe('Electron Forge API', () => { packageJSON.name = 'testapp'; packageJSON.version = '1.0.0-beta.1'; packageJSON.productName = 'Test-App'; - assert(packageJSON.config.forge.packagerConfig); - packageJSON.config.forge.packagerConfig.asar = false; + packageJSON.config = packageJSON.config || {}; + packageJSON.config.forge = { + ...packageJSON.config.forge, + packagerConfig: { + asar: false, + }, + }; if (process.platform === 'win32') { await fs.copy(path.join(__dirname, '..', 'fixture', 'bogus-private-key.pvk'), path.join(dir, 'default.pvk')); devCert = await createDefaultCertificate('CN=Test Author', { certFilePath: dir }); } else if (process.platform === 'linux') { - packageJSON.config.forge.packagerConfig.executableName = 'testapp'; + packageJSON.config.forge.packagerConfig = { + ...packageJSON.config.forge.packagerConfig, + executableName: 'testapp', + }; } packageJSON.homepage = 'http://www.example.com/'; packageJSON.author = 'Test Author'; diff --git a/packages/template/base/src/BaseTemplate.ts b/packages/template/base/src/BaseTemplate.ts index 4a8bb07655..15e6ac59cc 100644 --- a/packages/template/base/src/BaseTemplate.ts +++ b/packages/template/base/src/BaseTemplate.ts @@ -39,7 +39,7 @@ export class BaseTemplate implements ForgeTemplate { await asyncOra('Copying Starter Files', async () => { d('creating directory:', path.resolve(directory, 'src')); await fs.mkdirs(path.resolve(directory, 'src')); - const rootFiles = ['_gitignore']; + const rootFiles = ['_gitignore', 'forge.config.js']; if (copyCIFiles) rootFiles.push(...['_travis.yml', '_appveyor.yml']); const srcFiles = ['index.css', 'index.js', 'index.html', 'preload.js']; diff --git a/packages/template/base/tmpl/forge.config.js b/packages/template/base/tmpl/forge.config.js new file mode 100644 index 0000000000..9a4060f97e --- /dev/null +++ b/packages/template/base/tmpl/forge.config.js @@ -0,0 +1,22 @@ +module.exports = { + packagerConfig: {}, + rebuildConfig: {}, + makers: [ + { + name: '@electron-forge/maker-squirrel', + config: {}, + }, + { + name: '@electron-forge/maker-zip', + platforms: ['darwin'], + }, + { + name: '@electron-forge/maker-deb', + config: {}, + }, + { + name: '@electron-forge/maker-rpm', + config: {}, + }, + ], +}; diff --git a/packages/template/base/tmpl/package.json b/packages/template/base/tmpl/package.json index 850feab7fe..ec4b7f596b 100644 --- a/packages/template/base/tmpl/package.json +++ b/packages/template/base/tmpl/package.json @@ -12,30 +12,5 @@ }, "keywords": [], "author": "", - "license": "MIT", - "config": { - "forge": { - "packagerConfig": {}, - "makers": [ - { - "name": "@electron-forge/maker-squirrel", - "config": {} - }, - { - "name": "@electron-forge/maker-zip", - "platforms": [ - "darwin" - ] - }, - { - "name": "@electron-forge/maker-deb", - "config": {} - }, - { - "name": "@electron-forge/maker-rpm", - "config": {} - } - ] - } - } + "license": "MIT" } diff --git a/packages/template/typescript-webpack/src/TypeScriptWebpackTemplate.ts b/packages/template/typescript-webpack/src/TypeScriptWebpackTemplate.ts index 622852cb69..efc5bf344b 100644 --- a/packages/template/typescript-webpack/src/TypeScriptWebpackTemplate.ts +++ b/packages/template/typescript-webpack/src/TypeScriptWebpackTemplate.ts @@ -11,37 +11,8 @@ class TypeScriptWebpackTemplate extends BaseTemplate { async initializeTemplate(directory: string, options: InitTemplateOptions) { await super.initializeTemplate(directory, options); await asyncOra('Setting up Forge configuration', async () => { - const packageJSONPath = path.resolve(directory, 'package.json'); - const packageJSON = await fs.readJson(packageJSONPath); - - packageJSON.main = '.webpack/main'; - packageJSON.config.forge.plugins = packageJSON.config.forge.plugins || []; - packageJSON.config.forge.plugins.push({ - name: '@electron-forge/plugin-webpack', - config: { - mainConfig: './webpack.main.config.js', - renderer: { - config: './webpack.renderer.config.js', - entryPoints: [ - { - html: './src/index.html', - js: './src/renderer.ts', - name: 'main_window', - preload: { - js: './src/preload.ts', - }, - }, - ], - }, - }, - }); - - // Configure scripts for TS template - packageJSON.scripts.lint = 'eslint --ext .ts,.tsx .'; - - await fs.writeJson(packageJSONPath, packageJSON, { spaces: 2 }); + await this.copyTemplateFile(directory, 'forge.config.ts'); }); - await asyncOra('Setting up TypeScript configuration', async () => { const filePath = (fileName: string) => path.join(directory, 'src', fileName); @@ -71,6 +42,18 @@ class TypeScriptWebpackTemplate extends BaseTemplate { // Remove preload.js and replace with preload.ts await fs.remove(filePath('preload.js')); await this.copyTemplateFile(path.join(directory, 'src'), 'preload.ts'); + + // update package.json + const packageJSONPath = path.resolve(directory, 'package.json'); + const packageJSON = await fs.readJson(packageJSONPath); + packageJSON.main = '.webpack/main'; + // Configure scripts for TS template + packageJSON.scripts.lint = 'eslint --ext .ts,.tsx .'; + await fs.writeJson(packageJSONPath, packageJSON, { + spaces: 2, + }); + + await fs.writeJson(packageJSONPath, packageJSON, { spaces: 2 }); }); } } diff --git a/packages/template/typescript-webpack/tmpl/forge.config.ts b/packages/template/typescript-webpack/tmpl/forge.config.ts new file mode 100644 index 0000000000..e034b75d3c --- /dev/null +++ b/packages/template/typescript-webpack/tmpl/forge.config.ts @@ -0,0 +1,43 @@ +module.exports = { + packagerConfig: {}, + rebuildConfig: {}, + makers: [ + { + name: '@electron-forge/maker-squirrel', + config: {}, + }, + { + name: '@electron-forge/maker-zip', + platforms: ['darwin'], + }, + { + name: '@electron-forge/maker-deb', + config: {}, + }, + { + name: '@electron-forge/maker-rpm', + config: {}, + }, + ], + plugins: [ + { + name: '@electron-forge/plugin-webpack', + config: { + mainConfig: './webpack.main.config.js', + renderer: { + config: './webpack.renderer.config.js', + entryPoints: [ + { + html: './src/index.html', + js: './src/renderer.js', + name: 'main_window', + preload: { + js: './src/preload.js', + }, + }, + ], + }, + }, + }, + ], +}; diff --git a/packages/template/webpack/src/WebpackTemplate.ts b/packages/template/webpack/src/WebpackTemplate.ts index f23d78a49b..8136b5b243 100644 --- a/packages/template/webpack/src/WebpackTemplate.ts +++ b/packages/template/webpack/src/WebpackTemplate.ts @@ -11,32 +11,7 @@ class WebpackTemplate extends BaseTemplate { public async initializeTemplate(directory: string, options: InitTemplateOptions) { await super.initializeTemplate(directory, options); await asyncOra('Setting up Forge configuration', async () => { - const pjPath = path.resolve(directory, 'package.json'); - const currentPJ = await fs.readJson(pjPath); - currentPJ.main = '.webpack/main'; - currentPJ.config.forge.plugins = currentPJ.config.forge.plugins || []; - currentPJ.config.forge.plugins.push({ - name: '@electron-forge/plugin-webpack', - config: { - mainConfig: './webpack.main.config.js', - renderer: { - config: './webpack.renderer.config.js', - entryPoints: [ - { - html: './src/index.html', - js: './src/renderer.js', - name: 'main_window', - preload: { - js: './src/preload.js', - }, - }, - ], - }, - }, - }); - await fs.writeJson(pjPath, currentPJ, { - spaces: 2, - }); + await this.copyTemplateFile(directory, 'forge.config.js'); }); await asyncOra('Setting up webpack configuration', async () => { await this.copyTemplateFile(directory, 'webpack.main.config.js'); @@ -59,6 +34,14 @@ class WebpackTemplate extends BaseTemplate { if (line.includes('link rel="stylesheet"')) return ''; return line; }); + + // update package.json entry point + const pjPath = path.resolve(directory, 'package.json'); + const currentPJ = await fs.readJson(pjPath); + currentPJ.main = '.webpack/main'; + await fs.writeJson(pjPath, currentPJ, { + spaces: 2, + }); }); } } diff --git a/packages/template/webpack/tmpl/forge.config.js b/packages/template/webpack/tmpl/forge.config.js new file mode 100644 index 0000000000..e034b75d3c --- /dev/null +++ b/packages/template/webpack/tmpl/forge.config.js @@ -0,0 +1,43 @@ +module.exports = { + packagerConfig: {}, + rebuildConfig: {}, + makers: [ + { + name: '@electron-forge/maker-squirrel', + config: {}, + }, + { + name: '@electron-forge/maker-zip', + platforms: ['darwin'], + }, + { + name: '@electron-forge/maker-deb', + config: {}, + }, + { + name: '@electron-forge/maker-rpm', + config: {}, + }, + ], + plugins: [ + { + name: '@electron-forge/plugin-webpack', + config: { + mainConfig: './webpack.main.config.js', + renderer: { + config: './webpack.renderer.config.js', + entryPoints: [ + { + html: './src/index.html', + js: './src/renderer.js', + name: 'main_window', + preload: { + js: './src/preload.js', + }, + }, + ], + }, + }, + }, + ], +};