Skip to content

chore: migrate to ESM package (BREAKING) #9086

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 20 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 11 additions & 0 deletions .changeset/fuzzy-shoes-fold.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"app-builder-lib": major
"builder-util": major
"dmg-builder": major
"electron-builder-squirrel-windows": major
"electron-builder": major
"electron-publish": major
"electron-updater": major
---

chore: migrate to ESM package (BREAKING)
12 changes: 12 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export default [{
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:import/recommended",
// the following lines do the trick
"plugin:import/typescript",
), {
plugins: {
"@typescript-eslint": typescriptEslint,
Expand All @@ -46,6 +49,15 @@ export default [{
},

rules: {
'import/resolver': {
typescript: {
project: './tsconfig.json',
},
},
"import/extensions": ["error", "ignorePackages", {
"ts": "never",
"js": "always"
}],
"@typescript-eslint/no-require-imports": "off",
semi: "off",
"prettier/prettier": "warn",
Expand Down
55 changes: 55 additions & 0 deletions fix-esm-imports.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// fix-esm-imports.js
const fs = require('fs');
const path = require('path');

const extensions = ['.ts', '.tsx'];

function walk(dir, callback) {
fs.readdirSync(dir).forEach(file => {
const full = path.join(dir, file);
const stat = fs.statSync(full);
if (stat.isDirectory() && !file.includes('node_modules')) {
walk(full, callback);
} else if (extensions.includes(path.extname(full))) {
callback(full);
}
});
}

function fixImports(filePath) {
let content = fs.readFileSync(filePath, 'utf8');
let changed = false;

const fixedContent = content.replace(
/(import|export)\s+(.*?\s+from\s+)?['"]([^'"]+?)['"]/g,
(match, type, specifier, modulePath) => {
const ext = path.extname(modulePath);
if (ext || modulePath.endsWith('/')) {
return match; // Already has extension or is a folder import
}
if (modulePath === "." || modulePath === "..") {
changed = true;
return modulePath + "/index.js"
}
if (modulePath.startsWith('./') || modulePath.startsWith('../') || modulePath.includes('/out/')) {
changed = true;
return match.replace(modulePath, modulePath + '.js');
}
return match;
}
);

if (changed) {
console.log(`✅ Fixed: ${filePath}`);
fs.writeFileSync(filePath, fixedContent, 'utf8');
}
}

const targetDir = process.argv[2] || 'src';
if (!fs.existsSync(targetDir)) {
console.error(`❌ Directory not found: ${targetDir}`);
process.exit(1);
}

walk(targetDir, fixImports);
console.log('✅ All imports fixed.');
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"@changesets/changelog-github": "0.4.7",
"@changesets/cli": "2.25.0",
"@stylistic/eslint-plugin": "^2.8.0",
"@types/node": "^22.7.4",
"@tsconfig/node22": "^22.0.1",
"@types/node": "^22.12.0",
"@typescript-eslint/eslint-plugin": "8.17.0",
"@typescript-eslint/parser": "8.17.0",
"@vitest/ui": "3.0.4",
Expand All @@ -60,6 +61,7 @@
"depcheck": "1.4.3",
"eslint": "9.16.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-prettier": "^5.2.1",
"fs-extra": "10.1.0",
"husky": "7.0.4",
Expand Down
8 changes: 7 additions & 1 deletion packages/app-builder-lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
"name": "app-builder-lib",
"description": "electron-builder lib",
"version": "26.0.15",
"main": "out/index.js",
"type": "module",
"exports": {
".": {
"import": "./out/index.js",
"types": "./out/index.d.ts"
}
},
"files": [
"out",
"templates",
Expand Down
4 changes: 2 additions & 2 deletions packages/app-builder-lib/src/Framework.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FileTransformer } from "builder-util"
import { AsarIntegrity } from "./asar/integrity"
import { AfterPackContext, ElectronPlatformName, Platform, PlatformPackager } from "./index"
import { AsarIntegrity } from "./asar/integrity.js"
import { AfterPackContext, ElectronPlatformName, Platform, PlatformPackager } from "./index.js"

export interface Framework {
readonly name: string
Expand Down
8 changes: 4 additions & 4 deletions packages/app-builder-lib/src/ProtonFramework.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { FileTransformer, log } from "builder-util"
import { safeStringifyJson } from "builder-util-runtime"
import { Platform } from "./core"
import { NODE_MODULES_PATTERN } from "./fileTransformer"
import { LibUiFramework } from "./frameworks/LibUiFramework"
import { getTemplatePath } from "./util/pathManager"
import { Platform } from "./core.js"
import { NODE_MODULES_PATTERN } from "./fileTransformer.js"
import { LibUiFramework } from "./frameworks/LibUiFramework.js"
import { getTemplatePath } from "./util/pathManager.js"

export class ProtonFramework extends LibUiFramework {
readonly name = "proton"
Expand Down
12 changes: 7 additions & 5 deletions packages/app-builder-lib/src/appInfo.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { isEmptyOrSpaces, log } from "builder-util"
import { Nullish } from "builder-util-runtime"
import { sanitizeFileName } from "builder-util/out/filename"
import { sanitizeFileName } from "builder-util"
import { prerelease } from "semver"
import { PlatformSpecificBuildOptions } from "./options/PlatformSpecificBuildOptions"
import { Packager } from "./packager"
import { expandMacro } from "./util/macroExpander"
import { PlatformSpecificBuildOptions } from "./options/PlatformSpecificBuildOptions.js"
import { Packager } from "./packager.js"
import { expandMacro } from "./util/macroExpander.js"

// fpm bug - rpm build --description is not escaped, well... decided to replace quite to smart quote
// http://leancrew.com/all-this/2010/11/smart-quotes-in-javascript/
Expand All @@ -21,7 +21,7 @@ export function smarten(s: string): string {
}

export class AppInfo {
readonly description = smarten(this.info.metadata.description || "")
readonly description: string
readonly version: string
readonly type: string | undefined
readonly shortVersion: string | undefined
Expand Down Expand Up @@ -75,6 +75,8 @@ export class AppInfo {

const executableName = platformSpecificOptions?.executableName ?? info.config.executableName
this.productFilename = executableName != null ? sanitizeFileName(executableName, normalizeNfd) : this.sanitizedProductName

this.description = smarten(this.info.metadata.description || "")
}

get channel(): string | null {
Expand Down
2 changes: 1 addition & 1 deletion packages/app-builder-lib/src/asar/asarFileChecker.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as asar from "@electron/asar"
import { FilesystemEntry, FilesystemFileEntry } from "@electron/asar/lib/filesystem"
import { FilesystemEntry, FilesystemFileEntry } from "@electron/asar/lib/filesystem.js"

export function checkFileInArchive(asarFile: string, relativeFile: string, messagePrefix: string) {
function error(text: string) {
Expand Down
10 changes: 5 additions & 5 deletions packages/app-builder-lib/src/asar/asarUtil.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { createPackageFromStreams, AsarStreamType, AsarDirectory } from "@electron/asar"
import { log } from "builder-util"
import { Filter } from "builder-util/out/fs"
import { Filter } from "builder-util"
import * as fs from "fs-extra"
import { readlink } from "fs-extra"
import * as path from "path"
import { AsarOptions } from "../options/PlatformSpecificBuildOptions"
import { PlatformPackager } from "../platformPackager"
import { ResolvedFileSet, getDestinationPath } from "../util/appFileCopier"
import { detectUnpackedDirs } from "./unpackDetector"
import { AsarOptions } from "../options/PlatformSpecificBuildOptions.js"
import { PlatformPackager } from "../platformPackager.js"
import { ResolvedFileSet, getDestinationPath } from "../util/appFileCopier.js"
import { detectUnpackedDirs } from "./unpackDetector.js"
import { Readable } from "stream"

/** @internal */
Expand Down
4 changes: 2 additions & 2 deletions packages/app-builder-lib/src/asar/integrity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { FilterStats, log, statOrNull, walk } from "builder-util"
import { createHash } from "crypto"
import { readdir } from "fs/promises"
import * as path from "path"
import { FileMatcher } from "../fileMatcher"
import { readAsarHeader } from "./asar"
import { FileMatcher } from "../fileMatcher.js"
import { readAsarHeader } from "./asar.js"

export interface AsarIntegrityOptions {
readonly resourcesPath: string
Expand Down
2 changes: 1 addition & 1 deletion packages/app-builder-lib/src/asar/unpackDetector.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FilterStats, log } from "builder-util"
import { isBinaryFileSync } from "isbinaryfile"
import * as path from "path"
import { ResolvedFileSet } from "../util/appFileCopier"
import { ResolvedFileSet } from "../util/appFileCopier.js"

export function isLibOrExe(file: string): boolean {
// https://github.com/electron-userland/electron-builder/issues/3038
Expand Down
2 changes: 1 addition & 1 deletion packages/app-builder-lib/src/codeSign/codesign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { outputFile } from "fs-extra"
import { homedir } from "os"
import * as path from "path"
import { TmpDir } from "temp-file"
import { download } from "../binDownload"
import { download } from "../binDownload.js"

/** @private */
export async function importCertificate(cscLink: string, tmpDir: TmpDir, currentDir: string): Promise<string> {
Expand Down
8 changes: 4 additions & 4 deletions packages/app-builder-lib/src/codeSign/macCodeSign.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { signAsync } from "@electron/osx-sign"
import { SignOptions } from "@electron/osx-sign/dist/cjs/types"
import { Identity as _Identity } from "@electron/osx-sign/dist/cjs/util-identities"
import { SignOptions } from "@electron/osx-sign/dist/cjs/types.js"
import { Identity as _Identity } from "@electron/osx-sign/dist/cjs/util-identities.js"
import { copyFile, exec, Fields, InvalidConfigurationError, isEmptyOrSpaces, isEnvTrue, isPullRequest, log, Logger, retry, TmpDir, unlinkIfExists } from "builder-util"
import { Nullish } from "builder-util-runtime"
import { createHash, randomBytes } from "crypto"
Expand All @@ -9,8 +9,8 @@ import { Lazy } from "lazy-val"
import { homedir, tmpdir } from "os"
import * as path from "path"
import { getTempName } from "temp-file"
import { isAutoDiscoveryCodeSignIdentity } from "../util/flags"
import { importCertificate } from "./codesign"
import { isAutoDiscoveryCodeSignIdentity } from "../util/flags.js"
import { importCertificate } from "./codesign.js"

export const appleCertificatePrefixes = ["Developer ID Application:", "Developer ID Installer:", "3rd Party Mac Developer Application:", "3rd Party Mac Developer Installer:"]

Expand Down
8 changes: 4 additions & 4 deletions packages/app-builder-lib/src/codeSign/signManager.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { MemoLazy, Nullish } from "builder-util-runtime"
import { Lazy } from "lazy-val"
import { Target } from "../core"
import { WindowsConfiguration } from "../options/winOptions"
import { WindowsSignOptions } from "./windowsCodeSign"
import { CertificateFromStoreInfo, FileCodeSigningInfo } from "./windowsSignToolManager"
import { Target } from "../core.js"
import { WindowsConfiguration } from "../options/winOptions.js"
import { WindowsSignOptions } from "./windowsCodeSign.js"
import { CertificateFromStoreInfo, FileCodeSigningInfo } from "./windowsSignToolManager.js"

export interface SignManager {
readonly computedPublisherName: Lazy<Array<string> | null>
Expand Down
4 changes: 2 additions & 2 deletions packages/app-builder-lib/src/codeSign/windowsCodeSign.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { log, retry } from "builder-util"
import { WindowsConfiguration } from "../options/winOptions"
import { WinPackager } from "../winPackager"
import { WindowsConfiguration } from "../options/winOptions.js"
import { WinPackager } from "../winPackager.js"

export interface WindowsSignOptions {
readonly path: string
Expand Down
10 changes: 5 additions & 5 deletions packages/app-builder-lib/src/codeSign/windowsSignAzureManager.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { asArray, InvalidConfigurationError, log } from "builder-util"
import { MemoLazy } from "builder-util-runtime"
import { Lazy } from "lazy-val"
import { WindowsAzureSigningConfiguration, WindowsConfiguration } from "../options/winOptions"
import { WinPackager } from "../winPackager"
import { SignManager } from "./signManager"
import { WindowsSignOptions } from "./windowsCodeSign"
import { CertificateFromStoreInfo, FileCodeSigningInfo } from "./windowsSignToolManager"
import { WindowsAzureSigningConfiguration, WindowsConfiguration } from "../options/winOptions.js"
import { WinPackager } from "../winPackager.js"
import { SignManager } from "./signManager.js"
import { WindowsSignOptions } from "./windowsCodeSign.js"
import { CertificateFromStoreInfo, FileCodeSigningInfo } from "./windowsSignToolManager.js"

export class WindowsSignAzureManager implements SignManager {
private readonly platformSpecificBuildOptions: WindowsConfiguration
Expand Down
26 changes: 13 additions & 13 deletions packages/app-builder-lib/src/codeSign/windowsSignToolManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ import { rename } from "fs-extra"
import { Lazy } from "lazy-val"
import * as os from "os"
import * as path from "path"
import { getBin } from "../binDownload"
import { Target } from "../core"
import { WindowsConfiguration } from "../options/winOptions"
import AppXTarget from "../targets/AppxTarget"
import { executeAppBuilderAsJson } from "../util/appBuilder"
import { computeToolEnv, ToolInfo } from "../util/bundledTool"
import { isUseSystemSigncode } from "../util/flags"
import { resolveFunction } from "../util/resolve"
import { VmManager } from "../vm/vm"
import { WinPackager } from "../winPackager"
import { importCertificate } from "./codesign"
import { SignManager } from "./signManager"
import { WindowsSignOptions } from "./windowsCodeSign"
import { getBin } from "../binDownload.js"
import { Target } from "../core.js"
import { WindowsConfiguration } from "../options/winOptions.js"
import AppXTarget from "../targets/AppxTarget.js"
import { executeAppBuilderAsJson } from "../util/appBuilder.js"
import { computeToolEnv, ToolInfo } from "../util/bundledTool.js"
import { isUseSystemSigncode } from "../util/flags.js"
import { resolveFunction } from "../util/resolve.js"
import { VmManager } from "../vm/vm.js"
import { WinPackager } from "../winPackager.js"
import { importCertificate } from "./codesign.js"
import { SignManager } from "./signManager.js"
import { WindowsSignOptions } from "./windowsCodeSign.js"

export function getSignVendorPath() {
return getBin("winCodeSign")
Expand Down
34 changes: 17 additions & 17 deletions packages/app-builder-lib/src/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { Arch } from "builder-util"
import { BeforeBuildContext, Target } from "./core"
import { ElectronBrandingOptions, ElectronDownloadOptions } from "./electron/ElectronFramework"
import { PrepareApplicationStageDirectoryOptions } from "./Framework"
import { AppXOptions } from "./options/AppXOptions"
import { AppImageOptions, DebOptions, FlatpakOptions, LinuxConfiguration, LinuxTargetSpecificOptions } from "./options/linuxOptions"
import { DmgOptions, MacConfiguration, MasConfiguration } from "./options/macOptions"
import { MsiOptions } from "./options/MsiOptions"
import { MsiWrappedOptions } from "./options/MsiWrappedOptions"
import { PkgOptions } from "./options/pkgOptions"
import { PlatformSpecificBuildOptions } from "./options/PlatformSpecificBuildOptions"
import { SnapOptions } from "./options/SnapOptions"
import { SquirrelWindowsOptions } from "./options/SquirrelWindowsOptions"
import { WindowsConfiguration } from "./options/winOptions"
import { BuildResult } from "./packager"
import { ArtifactBuildStarted, ArtifactCreated } from "./packagerApi"
import { PlatformPackager } from "./platformPackager"
import { NsisOptions, NsisWebOptions, PortableOptions } from "./targets/nsis/nsisOptions"
import { BeforeBuildContext, Target } from "./core.js"
import { ElectronBrandingOptions, ElectronDownloadOptions } from "./electron/ElectronFramework.js"
import { PrepareApplicationStageDirectoryOptions } from "./Framework.js"
import { AppXOptions } from "./options/AppXOptions.js"
import { AppImageOptions, DebOptions, FlatpakOptions, LinuxConfiguration, LinuxTargetSpecificOptions } from "./options/linuxOptions.js"
import { DmgOptions, MacConfiguration, MasConfiguration } from "./options/macOptions.js"
import { MsiOptions } from "./options/MsiOptions.js"
import { MsiWrappedOptions } from "./options/MsiWrappedOptions.js"
import { PkgOptions } from "./options/pkgOptions.js"
import { PlatformSpecificBuildOptions } from "./options/PlatformSpecificBuildOptions.js"
import { SnapOptions } from "./options/SnapOptions.js"
import { SquirrelWindowsOptions } from "./options/SquirrelWindowsOptions.js"
import { WindowsConfiguration } from "./options/winOptions.js"
import { BuildResult } from "./packager.js"
import { ArtifactBuildStarted, ArtifactCreated } from "./packagerApi.js"
import { PlatformPackager } from "./platformPackager.js"
import { NsisOptions, NsisWebOptions, PortableOptions } from "./targets/nsis/nsisOptions.js"

// duplicate appId here because it is important
/**
Expand Down
22 changes: 11 additions & 11 deletions packages/app-builder-lib/src/electron/ElectronFramework.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import { emptyDir, readdir, rename } from "fs-extra"
import * as fs from "fs/promises"
import * as path from "path"
import asyncPool from "tiny-async-pool"
import { Configuration } from "../configuration"
import { BeforeCopyExtraFilesOptions, Framework, PrepareApplicationStageDirectoryOptions } from "../Framework"
import { Packager, Platform } from "../index"
import { LinuxPackager } from "../linuxPackager"
import { MacPackager } from "../macPackager"
import { getTemplatePath } from "../util/pathManager"
import { resolveFunction } from "../util/resolve"
import { createMacApp } from "./electronMac"
import { computeElectronVersion, getElectronVersionFromInstalled } from "./electronVersion"
import { addWinAsarIntegrity } from "./electronWin"
import injectFFMPEG from "./injectFFMPEG"
import { Configuration } from "../configuration.js"
import { BeforeCopyExtraFilesOptions, Framework, PrepareApplicationStageDirectoryOptions } from "../Framework.js"
import { Packager, Platform } from "../index.js"
import { LinuxPackager } from "../linuxPackager.js"
import { MacPackager } from "../macPackager.js"
import { getTemplatePath } from "../util/pathManager.js"
import { resolveFunction } from "../util/resolve.js"
import { createMacApp } from "./electronMac.js"
import { computeElectronVersion, getElectronVersionFromInstalled } from "./electronVersion.js"
import { addWinAsarIntegrity } from "./electronWin.js"
import injectFFMPEG from "./injectFFMPEG.js"

export type ElectronPlatformName = "darwin" | "linux" | "win32" | "mas"

Expand Down
Loading
Loading