Skip to content

Commit 48c9f88

Browse files
authored
feat: allow usage of .cjs, .mjs, and type=module custom publishers. Adds AsyncEventEmitter. (electron-userland#8868)
1 parent c006890 commit 48c9f88

30 files changed

+501
-178
lines changed

.changeset/hip-weeks-allow.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"app-builder-lib": patch
3+
---
4+
5+
fix: allow usage of .cjs, .mjs, and type=module custom/generic publishers

.github/workflows/test.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ jobs:
7373
testFiles:
7474
- ArtifactPublisherTest,BuildTest,ExtraBuildTest,RepoSlugTest,binDownloadTest,configurationValidationTest,filenameUtilTest,filesTest,globTest,ignoreTest,macroExpanderTest,mainEntryTest,urlUtilTest,extraMetadataTest,linuxArchiveTest,linuxPackagerTest,HoistedNodeModuleTest,MemoLazyTest,HoistTest
7575
- snapTest,debTest,fpmTest,protonTest
76-
- winPackagerTest,BuildTest,winCodeSignTest,webInstallerTest
76+
- winPackagerTest,winCodeSignTest,webInstallerTest
7777
- oneClickInstallerTest,assistedInstallerTest
7878
steps:
7979
- name: Checkout code repository

packages/app-builder-lib/src/configuration.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -288,36 +288,36 @@ File `myBeforePackHook.js` in the project root directory:
288288
}
289289
```
290290
*/
291-
readonly beforePack?: Hook<BeforePackContext, any> | string | null
291+
readonly beforePack?: Hook<BeforePackContext, void> | string | null
292292

293293
/**
294294
* The function (or path to file or module id) to be [run after the prebuilt Electron binary has been extracted to the output directory](#afterextract)
295295
* Same setup as {@link beforePack}
296296
*/
297-
readonly afterExtract?: Hook<AfterExtractContext, any> | string | null
297+
readonly afterExtract?: Hook<AfterExtractContext, void> | string | null
298298

299299
/**
300300
* The function (or path to file or module id) to be [run after pack](#afterpack) (but before pack into distributable format and sign).
301301
* Same setup as {@link beforePack}
302302
*/
303-
readonly afterPack?: Hook<AfterPackContext, any> | string | null
303+
readonly afterPack?: Hook<AfterPackContext, void> | string | null
304304

305305
/**
306306
* The function (or path to file or module id) to be [run after pack and sign](#aftersign) (but before pack into distributable format).
307307
* Same setup as {@link beforePack}
308308
*/
309-
readonly afterSign?: Hook<AfterPackContext, any> | string | null
309+
readonly afterSign?: Hook<AfterPackContext, void> | string | null
310310

311311
/**
312312
* The function (or path to file or module id) to be run on artifact build start.
313313
* Same setup as {@link beforePack}
314314
*/
315-
readonly artifactBuildStarted?: Hook<ArtifactBuildStarted, any> | string | null
315+
readonly artifactBuildStarted?: Hook<ArtifactBuildStarted, void> | string | null
316316
/**
317317
* The function (or path to file or module id) to be run on artifact build completed.
318318
* Same setup as {@link beforePack}
319319
*/
320-
readonly artifactBuildCompleted?: Hook<ArtifactCreated, any> | string | null
320+
readonly artifactBuildCompleted?: Hook<ArtifactCreated, void> | string | null
321321
/**
322322
* The function (or path to file or module id) to be run after all artifacts are built.
323323
@@ -339,11 +339,11 @@ Configuration in the same way as `afterPack` (see above).
339339
/**
340340
* The function (or path to file or module id) to be run after MSI project created on disk - not packed into .msi package yet.
341341
*/
342-
readonly msiProjectCreated?: Hook<string, any> | string | null
342+
readonly msiProjectCreated?: Hook<string, void> | string | null
343343
/**
344344
* The function (or path to file or module id) to be run after Appx manifest created on disk - not packed into .appx package yet.
345345
*/
346-
readonly appxManifestCreated?: Hook<string, any> | string | null
346+
readonly appxManifestCreated?: Hook<string, void> | string | null
347347
/**
348348
* The function (or path to file or module id) to be [run on each node module](#onnodemodulefile) file. Returning `true`/`false` will determine whether to force include or to use the default copier logic
349349
*/

packages/app-builder-lib/src/index.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export function build(options: PackagerOptions & PublishOptions, packager: Packa
109109
}
110110
buildResult.artifactPaths.push(newArtifact)
111111
for (const publishConfiguration of publishConfigurations) {
112-
publishManager.scheduleUpload(
112+
await publishManager.scheduleUpload(
113113
publishConfiguration,
114114
{
115115
file: newArtifact,
@@ -132,6 +132,9 @@ export function build(options: PackagerOptions & PublishOptions, packager: Packa
132132
promise = publishManager.awaitTasks()
133133
}
134134

135-
return promise.then(() => process.removeListener("SIGINT", sigIntHandler))
135+
return promise.then(() => {
136+
packager.clearPackagerEventListeners()
137+
process.removeListener("SIGINT", sigIntHandler)
138+
})
136139
})
137140
}

packages/app-builder-lib/src/macPackager.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ export class MacPackager extends PlatformPackager<MacConfiguration> {
173173
packager: this,
174174
electronPlatformName: platformName,
175175
}
176-
await this.info.afterPack(packContext)
176+
await this.info.emitAfterPack(packContext)
177177

178178
if (this.info.cancellationToken.cancelled) {
179179
return

packages/app-builder-lib/src/packager.ts

+77-58
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,14 @@ import {
1515
TmpDir,
1616
} from "builder-util"
1717
import { CancellationToken } from "builder-util-runtime"
18-
import { EventEmitter } from "events"
1918
import { chmod, mkdirs, outputFile } from "fs-extra"
2019
import * as isCI from "is-ci"
2120
import { Lazy } from "lazy-val"
2221
import { release as getOsRelease } from "os"
2322
import * as path from "path"
2423
import { AppInfo } from "./appInfo"
2524
import { readAsarJson } from "./asar/asar"
26-
import { AfterPackContext, Configuration } from "./configuration"
25+
import { AfterExtractContext, AfterPackContext, BeforePackContext, Configuration, Hook } from "./configuration"
2726
import { Platform, SourceRepositoryInfo, Target } from "./core"
2827
import { createElectronFrameworkSupport } from "./electron/ElectronFramework"
2928
import { Framework } from "./Framework"
@@ -41,10 +40,7 @@ import { getRepositoryInfo } from "./util/repositoryInfo"
4140
import { resolveFunction } from "./util/resolve"
4241
import { installOrRebuild, nodeGypRebuild } from "./util/yarn"
4342
import { PACKAGE_VERSION } from "./version"
44-
45-
function addHandler(emitter: EventEmitter, event: string, handler: (...args: Array<any>) => void) {
46-
emitter.on(event, handler)
47-
}
43+
import { AsyncEventEmitter, HandlerType } from "./util/asyncEventEmitter"
4844

4945
async function createFrameworkInfo(configuration: Configuration, packager: Packager): Promise<Framework> {
5046
let framework = configuration.framework
@@ -72,6 +68,23 @@ async function createFrameworkInfo(configuration: Configuration, packager: Packa
7268
}
7369
}
7470

71+
type PackagerEvents = {
72+
artifactBuildStarted: Hook<ArtifactBuildStarted, void>
73+
74+
beforePack: Hook<BeforePackContext, void>
75+
afterExtract: Hook<AfterExtractContext, void>
76+
afterPack: Hook<AfterPackContext, void>
77+
afterSign: Hook<AfterPackContext, void>
78+
79+
artifactBuildCompleted: Hook<ArtifactCreated, void>
80+
81+
msiProjectCreated: Hook<string, void>
82+
appxManifestCreated: Hook<string, void>
83+
84+
// internal-use only, prefer usage of `artifactBuildCompleted`
85+
artifactCreated: Hook<ArtifactCreated, void>
86+
}
87+
7588
export class Packager {
7689
readonly projectDir: string
7790

@@ -110,7 +123,7 @@ export class Packager {
110123

111124
isTwoPackageJsonProjectLayoutUsed = false
112125

113-
readonly eventEmitter = new EventEmitter()
126+
private readonly eventEmitter = new AsyncEventEmitter<PackagerEvents>()
114127

115128
_appInfo: AppInfo | null = null
116129
get appInfo(): AppInfo {
@@ -121,8 +134,6 @@ export class Packager {
121134

122135
private _repositoryInfo = new Lazy<SourceRepositoryInfo | null>(() => getRepositoryInfo(this.projectDir, this.metadata, this.devMetadata))
123136

124-
private readonly afterPackHandlers: Array<(context: AfterPackContext) => Promise<any> | null> = []
125-
126137
readonly options: PackagerOptions
127138

128139
readonly debugLogger = new DebugLogger(log.isDebugEnabled)
@@ -246,26 +257,42 @@ export class Packager {
246257
prepackaged: options.prepackaged == null ? null : path.resolve(this.projectDir, options.prepackaged),
247258
}
248259

249-
try {
250-
log.info({ version: PACKAGE_VERSION, os: getOsRelease() }, "electron-builder")
251-
} catch (e: any) {
252-
// error in dev mode without babel
253-
if (!(e instanceof ReferenceError)) {
254-
throw e
255-
}
256-
}
260+
log.info({ version: PACKAGE_VERSION, os: getOsRelease() }, "electron-builder")
257261
}
258262

259-
addAfterPackHandler(handler: (context: AfterPackContext) => Promise<any> | null) {
260-
this.afterPackHandlers.push(handler)
263+
addPackagerEventHandlers() {
264+
const { type } = this.appInfo
265+
this.eventEmitter.on("artifactBuildStarted", resolveFunction(type, this.config.artifactBuildStarted, "artifactBuildStarted"), "user")
266+
this.eventEmitter.on("artifactBuildCompleted", resolveFunction(type, this.config.artifactBuildCompleted, "artifactBuildCompleted"), "user")
267+
268+
this.eventEmitter.on("appxManifestCreated", resolveFunction(type, this.config.appxManifestCreated, "appxManifestCreated"), "user")
269+
this.eventEmitter.on("msiProjectCreated", resolveFunction(type, this.config.msiProjectCreated, "msiProjectCreated"), "user")
270+
271+
this.eventEmitter.on("beforePack", resolveFunction(type, this.config.beforePack, "beforePack"), "user")
272+
this.eventEmitter.on("afterExtract", resolveFunction(type, this.config.afterExtract, "afterExtract"), "user")
273+
this.eventEmitter.on("afterPack", resolveFunction(type, this.config.afterPack, "afterPack"), "user")
274+
this.eventEmitter.on("afterSign", resolveFunction(type, this.config.afterSign, "afterSign"), "user")
261275
}
262276

263-
artifactCreated(handler: (event: ArtifactCreated) => void): Packager {
264-
addHandler(this.eventEmitter, "artifactCreated", handler)
277+
onAfterPack(handler: PackagerEvents["afterPack"]): Packager {
278+
this.eventEmitter.on("afterPack", handler)
265279
return this
266280
}
267281

268-
async callArtifactBuildStarted(event: ArtifactBuildStarted, logFields?: any): Promise<void> {
282+
onArtifactCreated(handler: PackagerEvents["artifactCreated"]): Packager {
283+
this.eventEmitter.on("artifactCreated", handler)
284+
return this
285+
}
286+
287+
filterPackagerEventListeners(event: keyof PackagerEvents, type: HandlerType | undefined) {
288+
return this.eventEmitter.filterListeners(event, type)
289+
}
290+
291+
clearPackagerEventListeners() {
292+
this.eventEmitter.clear()
293+
}
294+
295+
async emitArtifactBuildStarted(event: ArtifactBuildStarted, logFields?: any) {
269296
log.info(
270297
logFields || {
271298
target: event.targetPresentableName,
@@ -274,40 +301,43 @@ export class Packager {
274301
},
275302
"building"
276303
)
277-
const handler = await resolveFunction(this.appInfo.type, this.config.artifactBuildStarted, "artifactBuildStarted")
278-
if (handler != null) {
279-
await Promise.resolve(handler(event))
280-
}
304+
await this.eventEmitter.emit("artifactBuildStarted", event)
281305
}
282306

283307
/**
284308
* Only for sub artifacts (update info), for main artifacts use `callArtifactBuildCompleted`.
285309
*/
286-
dispatchArtifactCreated(event: ArtifactCreated): void {
287-
this.eventEmitter.emit("artifactCreated", event)
310+
async emitArtifactCreated(event: ArtifactCreated) {
311+
await this.eventEmitter.emit("artifactCreated", event)
288312
}
289313

290-
async callArtifactBuildCompleted(event: ArtifactCreated): Promise<void> {
291-
const handler = await resolveFunction(this.appInfo.type, this.config.artifactBuildCompleted, "artifactBuildCompleted")
292-
if (handler != null) {
293-
await Promise.resolve(handler(event))
294-
}
314+
async emitArtifactBuildCompleted(event: ArtifactCreated) {
315+
await this.eventEmitter.emit("artifactBuildCompleted", event)
316+
await this.emitArtifactCreated(event)
317+
}
295318

296-
this.dispatchArtifactCreated(event)
319+
async emitAppxManifestCreated(path: string) {
320+
await this.eventEmitter.emit("appxManifestCreated", path)
297321
}
298322

299-
async callAppxManifestCreated(path: string): Promise<void> {
300-
const handler = await resolveFunction(this.appInfo.type, this.config.appxManifestCreated, "appxManifestCreated")
301-
if (handler != null) {
302-
await Promise.resolve(handler(path))
303-
}
323+
async emitMsiProjectCreated(path: string) {
324+
await this.eventEmitter.emit("msiProjectCreated", path)
304325
}
305326

306-
async callMsiProjectCreated(path: string): Promise<void> {
307-
const handler = await resolveFunction(this.appInfo.type, this.config.msiProjectCreated, "msiProjectCreated")
308-
if (handler != null) {
309-
await Promise.resolve(handler(path))
310-
}
327+
async emitBeforePack(context: BeforePackContext) {
328+
await this.eventEmitter.emit("beforePack", context)
329+
}
330+
331+
async emitAfterPack(context: AfterPackContext) {
332+
await this.eventEmitter.emit("afterPack", context)
333+
}
334+
335+
async emitAfterSign(context: AfterPackContext) {
336+
await this.eventEmitter.emit("afterSign", context)
337+
}
338+
339+
async emitAfterExtract(context: AfterPackContext) {
340+
await this.eventEmitter.emit("afterExtract", context)
311341
}
312342

313343
async validateConfig(): Promise<void> {
@@ -366,6 +396,8 @@ export class Packager {
366396
}
367397

368398
this._appInfo = new AppInfo(this, null)
399+
this.addPackagerEventHandlers()
400+
369401
this._framework = await createFrameworkInfo(this.config, this)
370402

371403
const commonOutDirWithoutPossibleOsMacro = path.resolve(
@@ -383,7 +415,7 @@ export class Packager {
383415

384416
// because artifact event maybe dispatched several times for different publish providers
385417
const artifactPaths = new Set<string>()
386-
this.artifactCreated(event => {
418+
this.onArtifactCreated(event => {
387419
if (event.file != null) {
388420
artifactPaths.add(event.file)
389421
}
@@ -547,19 +579,6 @@ export class Packager {
547579
})
548580
}
549581
}
550-
551-
async afterPack(context: AfterPackContext): Promise<any> {
552-
const afterPack = await resolveFunction(this.appInfo.type, this.config.afterPack, "afterPack")
553-
const handlers = this.afterPackHandlers.slice()
554-
if (afterPack != null) {
555-
// user handler should be last
556-
handlers.push(afterPack)
557-
}
558-
559-
for (const handler of handlers) {
560-
await Promise.resolve(handler(context))
561-
}
562-
}
563582
}
564583

565584
function createOutDirIfNeed(targetList: Array<Target>, createdOutDirs: Set<string>): Promise<any> {

0 commit comments

Comments
 (0)