Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/hip-weeks-allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"app-builder-lib": patch
---

fix: allow usage of .cjs, .mjs, and type=module custom/generic publishers
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ jobs:
testFiles:
- ArtifactPublisherTest,BuildTest,ExtraBuildTest,RepoSlugTest,binDownloadTest,configurationValidationTest,filenameUtilTest,filesTest,globTest,ignoreTest,macroExpanderTest,mainEntryTest,urlUtilTest,extraMetadataTest,linuxArchiveTest,linuxPackagerTest,HoistedNodeModuleTest,MemoLazyTest,HoistTest
- snapTest,debTest,fpmTest,protonTest
- winPackagerTest,BuildTest,winCodeSignTest,webInstallerTest
- winPackagerTest,winCodeSignTest,webInstallerTest
- oneClickInstallerTest,assistedInstallerTest
steps:
- name: Checkout code repository
Expand Down
16 changes: 8 additions & 8 deletions packages/app-builder-lib/src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,36 +288,36 @@ File `myBeforePackHook.js` in the project root directory:
}
```
*/
readonly beforePack?: Hook<BeforePackContext, any> | string | null
readonly beforePack?: Hook<BeforePackContext, void> | string | null

/**
* 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)
* Same setup as {@link beforePack}
*/
readonly afterExtract?: Hook<AfterExtractContext, any> | string | null
readonly afterExtract?: Hook<AfterExtractContext, void> | string | null

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

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

/**
* The function (or path to file or module id) to be run on artifact build start.
* Same setup as {@link beforePack}
*/
readonly artifactBuildStarted?: Hook<ArtifactBuildStarted, any> | string | null
readonly artifactBuildStarted?: Hook<ArtifactBuildStarted, void> | string | null
/**
* The function (or path to file or module id) to be run on artifact build completed.
* Same setup as {@link beforePack}
*/
readonly artifactBuildCompleted?: Hook<ArtifactCreated, any> | string | null
readonly artifactBuildCompleted?: Hook<ArtifactCreated, void> | string | null
/**
* The function (or path to file or module id) to be run after all artifacts are built.

Expand All @@ -339,11 +339,11 @@ Configuration in the same way as `afterPack` (see above).
/**
* The function (or path to file or module id) to be run after MSI project created on disk - not packed into .msi package yet.
*/
readonly msiProjectCreated?: Hook<string, any> | string | null
readonly msiProjectCreated?: Hook<string, void> | string | null
/**
* The function (or path to file or module id) to be run after Appx manifest created on disk - not packed into .appx package yet.
*/
readonly appxManifestCreated?: Hook<string, any> | string | null
readonly appxManifestCreated?: Hook<string, void> | string | null
/**
* 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
*/
Expand Down
7 changes: 5 additions & 2 deletions packages/app-builder-lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export function build(options: PackagerOptions & PublishOptions, packager: Packa
}
buildResult.artifactPaths.push(newArtifact)
for (const publishConfiguration of publishConfigurations) {
publishManager.scheduleUpload(
await publishManager.scheduleUpload(
publishConfiguration,
{
file: newArtifact,
Expand All @@ -132,6 +132,9 @@ export function build(options: PackagerOptions & PublishOptions, packager: Packa
promise = publishManager.awaitTasks()
}

return promise.then(() => process.removeListener("SIGINT", sigIntHandler))
return promise.then(() => {
packager.clearPackagerEventListeners()
process.removeListener("SIGINT", sigIntHandler)
})
})
}
2 changes: 1 addition & 1 deletion packages/app-builder-lib/src/macPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export class MacPackager extends PlatformPackager<MacConfiguration> {
packager: this,
electronPlatformName: platformName,
}
await this.info.afterPack(packContext)
await this.info.emitAfterPack(packContext)

if (this.info.cancellationToken.cancelled) {
return
Expand Down
135 changes: 77 additions & 58 deletions packages/app-builder-lib/src/packager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@ import {
TmpDir,
} from "builder-util"
import { CancellationToken } from "builder-util-runtime"
import { EventEmitter } from "events"
import { chmod, mkdirs, outputFile } from "fs-extra"
import * as isCI from "is-ci"
import { Lazy } from "lazy-val"
import { release as getOsRelease } from "os"
import * as path from "path"
import { AppInfo } from "./appInfo"
import { readAsarJson } from "./asar/asar"
import { AfterPackContext, Configuration } from "./configuration"
import { AfterExtractContext, AfterPackContext, BeforePackContext, Configuration, Hook } from "./configuration"
import { Platform, SourceRepositoryInfo, Target } from "./core"
import { createElectronFrameworkSupport } from "./electron/ElectronFramework"
import { Framework } from "./Framework"
Expand All @@ -41,10 +40,7 @@ import { getRepositoryInfo } from "./util/repositoryInfo"
import { resolveFunction } from "./util/resolve"
import { installOrRebuild, nodeGypRebuild } from "./util/yarn"
import { PACKAGE_VERSION } from "./version"

function addHandler(emitter: EventEmitter, event: string, handler: (...args: Array<any>) => void) {
emitter.on(event, handler)
}
import { AsyncEventEmitter, HandlerType } from "./util/asyncEventEmitter"

async function createFrameworkInfo(configuration: Configuration, packager: Packager): Promise<Framework> {
let framework = configuration.framework
Expand Down Expand Up @@ -72,6 +68,23 @@ async function createFrameworkInfo(configuration: Configuration, packager: Packa
}
}

type PackagerEvents = {
artifactBuildStarted: Hook<ArtifactBuildStarted, void>

beforePack: Hook<BeforePackContext, void>
afterExtract: Hook<AfterExtractContext, void>
afterPack: Hook<AfterPackContext, void>
afterSign: Hook<AfterPackContext, void>

artifactBuildCompleted: Hook<ArtifactCreated, void>

msiProjectCreated: Hook<string, void>
appxManifestCreated: Hook<string, void>

// internal-use only, prefer usage of `artifactBuildCompleted`
artifactCreated: Hook<ArtifactCreated, void>
}

export class Packager {
readonly projectDir: string

Expand Down Expand Up @@ -110,7 +123,7 @@ export class Packager {

isTwoPackageJsonProjectLayoutUsed = false

readonly eventEmitter = new EventEmitter()
private readonly eventEmitter = new AsyncEventEmitter<PackagerEvents>()

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

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

private readonly afterPackHandlers: Array<(context: AfterPackContext) => Promise<any> | null> = []

readonly options: PackagerOptions

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

try {
log.info({ version: PACKAGE_VERSION, os: getOsRelease() }, "electron-builder")
} catch (e: any) {
// error in dev mode without babel
if (!(e instanceof ReferenceError)) {
throw e
}
}
log.info({ version: PACKAGE_VERSION, os: getOsRelease() }, "electron-builder")
}

addAfterPackHandler(handler: (context: AfterPackContext) => Promise<any> | null) {
this.afterPackHandlers.push(handler)
addPackagerEventHandlers() {
const { type } = this.appInfo
this.eventEmitter.on("artifactBuildStarted", resolveFunction(type, this.config.artifactBuildStarted, "artifactBuildStarted"), "user")
this.eventEmitter.on("artifactBuildCompleted", resolveFunction(type, this.config.artifactBuildCompleted, "artifactBuildCompleted"), "user")

this.eventEmitter.on("appxManifestCreated", resolveFunction(type, this.config.appxManifestCreated, "appxManifestCreated"), "user")
this.eventEmitter.on("msiProjectCreated", resolveFunction(type, this.config.msiProjectCreated, "msiProjectCreated"), "user")

this.eventEmitter.on("beforePack", resolveFunction(type, this.config.beforePack, "beforePack"), "user")
this.eventEmitter.on("afterExtract", resolveFunction(type, this.config.afterExtract, "afterExtract"), "user")
this.eventEmitter.on("afterPack", resolveFunction(type, this.config.afterPack, "afterPack"), "user")
this.eventEmitter.on("afterSign", resolveFunction(type, this.config.afterSign, "afterSign"), "user")
}

artifactCreated(handler: (event: ArtifactCreated) => void): Packager {
addHandler(this.eventEmitter, "artifactCreated", handler)
onAfterPack(handler: PackagerEvents["afterPack"]): Packager {
this.eventEmitter.on("afterPack", handler)
return this
}

async callArtifactBuildStarted(event: ArtifactBuildStarted, logFields?: any): Promise<void> {
onArtifactCreated(handler: PackagerEvents["artifactCreated"]): Packager {
this.eventEmitter.on("artifactCreated", handler)
return this
}

filterPackagerEventListeners(event: keyof PackagerEvents, type: HandlerType | undefined) {
return this.eventEmitter.filterListeners(event, type)
}

clearPackagerEventListeners() {
this.eventEmitter.clear()
}

async emitArtifactBuildStarted(event: ArtifactBuildStarted, logFields?: any) {
log.info(
logFields || {
target: event.targetPresentableName,
Expand All @@ -274,40 +301,43 @@ export class Packager {
},
"building"
)
const handler = await resolveFunction(this.appInfo.type, this.config.artifactBuildStarted, "artifactBuildStarted")
if (handler != null) {
await Promise.resolve(handler(event))
}
await this.eventEmitter.emit("artifactBuildStarted", event)
}

/**
* Only for sub artifacts (update info), for main artifacts use `callArtifactBuildCompleted`.
*/
dispatchArtifactCreated(event: ArtifactCreated): void {
this.eventEmitter.emit("artifactCreated", event)
async emitArtifactCreated(event: ArtifactCreated) {
await this.eventEmitter.emit("artifactCreated", event)
}

async callArtifactBuildCompleted(event: ArtifactCreated): Promise<void> {
const handler = await resolveFunction(this.appInfo.type, this.config.artifactBuildCompleted, "artifactBuildCompleted")
if (handler != null) {
await Promise.resolve(handler(event))
}
async emitArtifactBuildCompleted(event: ArtifactCreated) {
await this.eventEmitter.emit("artifactBuildCompleted", event)
await this.emitArtifactCreated(event)
}

this.dispatchArtifactCreated(event)
async emitAppxManifestCreated(path: string) {
await this.eventEmitter.emit("appxManifestCreated", path)
}

async callAppxManifestCreated(path: string): Promise<void> {
const handler = await resolveFunction(this.appInfo.type, this.config.appxManifestCreated, "appxManifestCreated")
if (handler != null) {
await Promise.resolve(handler(path))
}
async emitMsiProjectCreated(path: string) {
await this.eventEmitter.emit("msiProjectCreated", path)
}

async callMsiProjectCreated(path: string): Promise<void> {
const handler = await resolveFunction(this.appInfo.type, this.config.msiProjectCreated, "msiProjectCreated")
if (handler != null) {
await Promise.resolve(handler(path))
}
async emitBeforePack(context: BeforePackContext) {
await this.eventEmitter.emit("beforePack", context)
}

async emitAfterPack(context: AfterPackContext) {
await this.eventEmitter.emit("afterPack", context)
}

async emitAfterSign(context: AfterPackContext) {
await this.eventEmitter.emit("afterSign", context)
}

async emitAfterExtract(context: AfterPackContext) {
await this.eventEmitter.emit("afterExtract", context)
}

async validateConfig(): Promise<void> {
Expand Down Expand Up @@ -366,6 +396,8 @@ export class Packager {
}

this._appInfo = new AppInfo(this, null)
this.addPackagerEventHandlers()

this._framework = await createFrameworkInfo(this.config, this)

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

// because artifact event maybe dispatched several times for different publish providers
const artifactPaths = new Set<string>()
this.artifactCreated(event => {
this.onArtifactCreated(event => {
if (event.file != null) {
artifactPaths.add(event.file)
}
Expand Down Expand Up @@ -547,19 +579,6 @@ export class Packager {
})
}
}

async afterPack(context: AfterPackContext): Promise<any> {
const afterPack = await resolveFunction(this.appInfo.type, this.config.afterPack, "afterPack")
const handlers = this.afterPackHandlers.slice()
if (afterPack != null) {
// user handler should be last
handlers.push(afterPack)
}

for (const handler of handlers) {
await Promise.resolve(handler(context))
}
}
}

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