From c14274f87024b582dcb26a0f76b008fe22381396 Mon Sep 17 00:00:00 2001 From: johnpyp Date: Fri, 10 Oct 2025 15:54:25 -0400 Subject: [PATCH 1/2] feat: bun package manager support for electron-builder --- .changeset/long-keys-smile.md | 5 + package.json | 10 +- packages/app-builder-lib/package.json | 2 + .../src/electron/search-module.ts | 2 +- packages/app-builder-lib/src/fileMatcher.ts | 2 +- .../bunNodeModulesCollector.ts | 163 +++++ .../src/node-module-collector/index.ts | 6 +- .../nodeModulesCollector.ts | 4 +- .../src/node-module-collector/types.ts | 7 + .../app-builder-lib/src/util/appFileCopier.ts | 33 +- pnpm-lock.yaml | 114 ++-- test/fixtures/test-app-bun-workspace/bun.lock | 24 + .../test-app-bun-workspace/package.json | 8 + .../packages/app/index.js | 1 + .../packages/app/node_modules/lib | 1 + .../packages/app/package.json | 24 + .../packages/lib/index.js | 1 + .../packages/lib/package.json | 6 + test/snapshots/HoistedNodeModuleTest.js.snap | 556 ++++++++++++++++++ test/src/HoistedNodeModuleTest.ts | 187 ++++++ 20 files changed, 1096 insertions(+), 60 deletions(-) create mode 100644 .changeset/long-keys-smile.md create mode 100644 packages/app-builder-lib/src/node-module-collector/bunNodeModulesCollector.ts create mode 100644 test/fixtures/test-app-bun-workspace/bun.lock create mode 100644 test/fixtures/test-app-bun-workspace/package.json create mode 100644 test/fixtures/test-app-bun-workspace/packages/app/index.js create mode 120000 test/fixtures/test-app-bun-workspace/packages/app/node_modules/lib create mode 100644 test/fixtures/test-app-bun-workspace/packages/app/package.json create mode 100644 test/fixtures/test-app-bun-workspace/packages/lib/index.js create mode 100644 test/fixtures/test-app-bun-workspace/packages/lib/package.json diff --git a/.changeset/long-keys-smile.md b/.changeset/long-keys-smile.md new file mode 100644 index 00000000000..6b1719886c8 --- /dev/null +++ b/.changeset/long-keys-smile.md @@ -0,0 +1,5 @@ +--- +"app-builder-lib": minor +--- + +add support for bundling with bun package manager diff --git a/package.json b/package.json index 7f1e883a3b4..0ed1dd34a0c 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@types/node": "^22.7.4", "@typescript-eslint/eslint-plugin": "8.17.0", "@typescript-eslint/parser": "8.17.0", - "@vitest/ui": "3.0.4", + "@vitest/ui": "^3.2.2", "chalk": "^4.1.2", "conventional-changelog-cli": "5.0.0", "depcheck": "1.4.3", @@ -80,6 +80,12 @@ "patchedDependencies": { "@changesets/cli@2.29.7": "patches/@changesets__cli@2.29.7.patch", "@changesets/assemble-release-plan@6.0.9": "patches/@changesets__assemble-release-plan@6.0.9.patch" - } + }, + "onlyBuiltDependencies": [ + "@parcel/watcher", + "electron", + "electron-winstaller", + "esbuild" + ] } } diff --git a/packages/app-builder-lib/package.json b/packages/app-builder-lib/package.json index 57943645b30..9979265cc48 100644 --- a/packages/app-builder-lib/package.json +++ b/packages/app-builder-lib/package.json @@ -76,6 +76,7 @@ "minimatch": "^10.0.3", "plist": "3.1.0", "resedit": "^1.7.0", + "resolve": "^1.22.10", "semver": "7.7.2", "tar": "^6.1.12", "temp-file": "^3.4.0", @@ -108,6 +109,7 @@ "@types/hosted-git-info": "3.0.2", "@types/js-yaml": "4.0.3", "@types/plist": "3.0.5", + "@types/resolve": "^1.20.6", "@types/semver": "7.7.1", "@types/tar": "^6.1.3", "@types/tiny-async-pool": "^1", diff --git a/packages/app-builder-lib/src/electron/search-module.ts b/packages/app-builder-lib/src/electron/search-module.ts index f8034abe8e4..8e263cae4bc 100644 --- a/packages/app-builder-lib/src/electron/search-module.ts +++ b/packages/app-builder-lib/src/electron/search-module.ts @@ -70,7 +70,7 @@ export async function searchForNodeModules(cwd: string, rootPath?: string): Prom * @param cwd the initial directory to traverse */ export async function getProjectRootPath(cwd: string): Promise { - for (const lockFilename of ["yarn.lock", "package-lock.json", "pnpm-lock.yaml"]) { + for (const lockFilename of ["yarn.lock", "package-lock.json", "pnpm-lock.yaml", "bun.lock", "bun.lockb"]) { const pathGenerator: PathGeneratorFunction = traversedPath => path.join(traversedPath, lockFilename) const lockPaths = await traverseAncestorDirectories(cwd, pathGenerator, undefined, 1) if (lockPaths.length > 0) { diff --git a/packages/app-builder-lib/src/fileMatcher.ts b/packages/app-builder-lib/src/fileMatcher.ts index 9b740cc7e57..90d9e863728 100644 --- a/packages/app-builder-lib/src/fileMatcher.ts +++ b/packages/app-builder-lib/src/fileMatcher.ts @@ -15,7 +15,7 @@ export const excludedNames = ".git,.hg,.svn,CVS,RCS,SCCS," + "__pycache__,.DS_Store,thumbs.db,.gitignore,.gitkeep,.gitattributes,.npmignore," + ".idea,.vs,.flowconfig,.jshintrc,.eslintrc,.circleci," + - ".yarn-integrity,.yarn-metadata.json,yarn-error.log,yarn.lock,package-lock.json,npm-debug.log,pnpm-lock.yaml," + + ".yarn-integrity,.yarn-metadata.json,yarn-error.log,yarn.lock,package-lock.json,npm-debug.log,pnpm-lock.yaml,bun.lock,bun.lockb" + "appveyor.yml,.travis.yml,circle.yml,.nyc_output,.husky,.github,electron-builder.env" export const excludedExts = diff --git a/packages/app-builder-lib/src/node-module-collector/bunNodeModulesCollector.ts b/packages/app-builder-lib/src/node-module-collector/bunNodeModulesCollector.ts new file mode 100644 index 00000000000..2fe0c889bfe --- /dev/null +++ b/packages/app-builder-lib/src/node-module-collector/bunNodeModulesCollector.ts @@ -0,0 +1,163 @@ +import { log } from "builder-util" +import * as path from "path" +import { sync as resolveSync } from "resolve" +import { NodeModulesCollector } from "./nodeModulesCollector" +import { PM } from "./packageManager" +import { BunDependency, BunManifest, Dependencies } from "./types" + +export class BunNodeModulesCollector extends NodeModulesCollector { + public readonly installOptions = { manager: PM.BUN, lockfile: "bun.lock" } + + private readonly dependencyCacheByPath = new Map() + + protected async getDependenciesTree(): Promise { + const rootManifest = require(path.join(this.rootDir, "package.json")) + const rootName = rootManifest.name ?? "." + + const childMaps = await this.resolveChildren(this.rootDir, { + manifestDependencies: rootManifest.dependencies ?? {}, + manifestOptionalDependencies: rootManifest.optionalDependencies ?? {}, + }) + return { + name: rootName, + version: rootManifest.version ?? "0.0.0", + path: this.rootDir, + manifestDependencies: rootManifest.dependencies ?? {}, + manifestOptionalDependencies: rootManifest.optionalDependencies ?? {}, + dependencies: Object.keys(childMaps.dependencies ?? {}).length > 0 ? childMaps.dependencies : undefined, + optionalDependencies: Object.keys(childMaps.optionalDependencies ?? {}).length > 0 ? childMaps.optionalDependencies : undefined, + } + } + + protected getArgs(): string[] { + return [] + } + + protected collectAllDependencies(tree: BunDependency): void { + const allDeps = [...Object.values(tree.dependencies || {}), ...Object.values(tree.optionalDependencies || {})] + + for (const dependency of allDeps) { + const key = `${dependency.name}@${dependency.version}` + if (!this.allDependencies.has(key)) { + this.allDependencies.set(key, dependency) + this.collectAllDependencies(dependency) + } + } + } + + protected extractProductionDependencyGraph(tree: BunDependency, dependencyId: string): void { + if (this.productionGraph[dependencyId]) { + return + } + + const dependencies: string[] = [] + + const processDeps = [ + { entries: tree.dependencies, manifest: tree.manifestDependencies }, + { entries: tree.optionalDependencies, manifest: tree.manifestOptionalDependencies }, + ] + + for (const { entries, manifest } of processDeps) { + if (!entries) { + continue + } + + for (const [alias, dep] of Object.entries(entries)) { + if (manifest[alias]) { + const childId = `${dep.name}@${dep.version}` + dependencies.push(childId) + this.extractProductionDependencyGraph(dep, childId) + } + } + } + + this.productionGraph[dependencyId] = { dependencies } + } + + protected parseDependenciesTree(jsonBlob: string): BunDependency { + return JSON.parse(jsonBlob) + } + + private async resolveChildren(requesterDir: string, manifest: BunManifest): Promise> { + const dependencies: Record = {} + const optionalDependencies: Record = {} + + for (const alias of Object.keys(manifest.manifestDependencies)) { + const dependency = await this.loadDependency(alias, requesterDir, false) + if (dependency) { + dependencies[alias] = dependency + } + } + + for (const alias of Object.keys(manifest.manifestOptionalDependencies)) { + const dependency = await this.loadDependency(alias, requesterDir, true) + if (dependency) { + optionalDependencies[alias] = dependency + } + } + + return { dependencies, optionalDependencies } + } + + private async loadDependency(alias: string, requesterDir: string, isOptional: boolean): Promise { + const installedPath = this.findInstalledDependency(requesterDir, alias) + if (!installedPath) { + if (!isOptional) { + log.debug({ alias, requesterDir }, "bun collector could not locate dependency") + } + return null + } + + // Use resolved path directly - resolve.sync already handles symlinks with preserveSymlinks: false + const cached = this.dependencyCacheByPath.get(installedPath) + if (cached) { + return cached + } + + const manifest = require(path.join(installedPath, "package.json")) + const packageName = manifest.name ?? alias + const manifestDependencies = manifest.dependencies ?? {} + const manifestOptionalDependencies = manifest.optionalDependencies ?? {} + + // Create a temporary placeholder to prevent infinite recursion + const placeholder: BunDependency = { + name: packageName, + version: manifest.version ?? "0.0.0", + path: installedPath, + manifestDependencies, + manifestOptionalDependencies, + } + this.dependencyCacheByPath.set(installedPath, placeholder) + + const childMaps = await this.resolveChildren(installedPath, { manifestDependencies, manifestOptionalDependencies }) + + const dependency: BunDependency = { + name: packageName, + version: manifest.version ?? "0.0.0", + path: installedPath, + manifestDependencies, + manifestOptionalDependencies, + dependencies: Object.keys(childMaps.dependencies ?? {}).length > 0 ? childMaps.dependencies : undefined, + optionalDependencies: Object.keys(childMaps.optionalDependencies ?? {}).length > 0 ? childMaps.optionalDependencies : undefined, + } + + this.dependencyCacheByPath.set(installedPath, dependency) + return dependency + } + + private findInstalledDependency(basedir: string, dependencyName: string): string | null { + try { + const packageJsonPath = resolveSync(path.join(dependencyName, "package.json"), { + basedir, + preserveSymlinks: false, + includeCoreModules: false, + }) + return path.dirname(packageJsonPath) + } catch (e: any) { + if (e?.code === "MODULE_NOT_FOUND") { + return null + } + throw e + } + } +} diff --git a/packages/app-builder-lib/src/node-module-collector/index.ts b/packages/app-builder-lib/src/node-module-collector/index.ts index 8666751fa85..c6be1ac0723 100644 --- a/packages/app-builder-lib/src/node-module-collector/index.ts +++ b/packages/app-builder-lib/src/node-module-collector/index.ts @@ -1,3 +1,4 @@ +import { BunNodeModulesCollector } from "./bunNodeModulesCollector" import { NpmNodeModulesCollector } from "./npmNodeModulesCollector" import { PnpmNodeModulesCollector } from "./pnpmNodeModulesCollector" import { YarnNodeModulesCollector } from "./yarnNodeModulesCollector" @@ -13,8 +14,9 @@ export async function getCollectorByPackageManager(pm: PM, rootDir: string, temp } return new PnpmNodeModulesCollector(rootDir, tempDirManager) case PM.NPM: - case PM.BUN: return new NpmNodeModulesCollector(rootDir, tempDirManager) + case PM.BUN: + return new BunNodeModulesCollector(rootDir, tempDirManager) case PM.YARN: return new YarnNodeModulesCollector(rootDir, tempDirManager) default: @@ -53,4 +55,4 @@ export function detectPackageManager(dirs: string[]): PM { return PM.NPM } -export { PM, getPackageManagerCommand } +export { PM, getPackageManagerCommand, BunNodeModulesCollector } diff --git a/packages/app-builder-lib/src/node-module-collector/nodeModulesCollector.ts b/packages/app-builder-lib/src/node-module-collector/nodeModulesCollector.ts index 184b4edcd04..9a431f787f7 100644 --- a/packages/app-builder-lib/src/node-module-collector/nodeModulesCollector.ts +++ b/packages/app-builder-lib/src/node-module-collector/nodeModulesCollector.ts @@ -16,8 +16,8 @@ export abstract class NodeModulesCollector { diff --git a/packages/app-builder-lib/src/node-module-collector/types.ts b/packages/app-builder-lib/src/node-module-collector/types.ts index c91242aefb8..a8b6660f3df 100644 --- a/packages/app-builder-lib/src/node-module-collector/types.ts +++ b/packages/app-builder-lib/src/node-module-collector/types.ts @@ -26,6 +26,13 @@ export interface NpmDependency extends Dependency { } } +export interface BunManifest { + manifestDependencies: Record + manifestOptionalDependencies: Record +} + +export interface BunDependency extends Dependency, BunManifest {} + export type Dependency = Dependencies & ParsedDependencyTree export type Dependencies = { diff --git a/packages/app-builder-lib/src/util/appFileCopier.ts b/packages/app-builder-lib/src/util/appFileCopier.ts index 38f1fe4a850..0aea3a96aa4 100644 --- a/packages/app-builder-lib/src/util/appFileCopier.ts +++ b/packages/app-builder-lib/src/util/appFileCopier.ts @@ -14,6 +14,7 @@ import { AppFileWalker } from "./AppFileWalker" import { NodeModuleCopyHelper } from "./NodeModuleCopyHelper" import { NodeModuleInfo } from "./packageDependencies" import { getNodeModules, detectPackageManager } from "../node-module-collector" +import { getProjectRootPath } from "../electron/search-module" const BOWER_COMPONENTS_PATTERN = `${path.sep}bower_components${path.sep}` /** @internal */ @@ -176,12 +177,42 @@ function validateFileSet(fileSet: ResolvedFileSet): ResolvedFileSet { return fileSet } +async function getGitRootDir(baseDir: string): Promise { + try { + const { promisify } = require("util") + const { exec } = require("child_process") + const execAsync = promisify(exec) + + const { stdout } = await execAsync("git rev-parse --show-toplevel", { + cwd: baseDir, + timeout: 5000, + }) + return stdout.trim() + } catch (_error) { + // Git not installed, not in a git repo, or other error + return null + } +} + /** @internal */ export async function computeNodeModuleFileSets(platformPackager: PlatformPackager, mainMatcher: FileMatcher): Promise> { const projectDir = platformPackager.info.projectDir const appDir = platformPackager.info.appDir - const pm = detectPackageManager(appDir === projectDir ? [appDir] : [appDir, projectDir]) + const lockfileRootPath = await getProjectRootPath(appDir) + const gitRootDir = await getGitRootDir(appDir) + + const dirsToCheck = appDir === projectDir ? [appDir] : [appDir, projectDir] + + if (lockfileRootPath && !dirsToCheck.includes(lockfileRootPath)) { + dirsToCheck.push(lockfileRootPath) + } + + if (gitRootDir && !dirsToCheck.includes(gitRootDir)) { + dirsToCheck.push(gitRootDir) + } + + const pm = detectPackageManager(dirsToCheck) let deps = await getNodeModules(pm, appDir, platformPackager.info.tempDirManager) if (projectDir !== appDir && deps.length === 0) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eabce802525..56371d85ffa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,8 +51,8 @@ importers: specifier: 8.17.0 version: 8.17.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.8.2) '@vitest/ui': - specifier: 3.0.4 - version: 3.0.4(vitest@3.2.3) + specifier: ^3.2.2 + version: 3.2.4(vitest@3.2.3) chalk: specifier: ^4.1.2 version: 4.1.2 @@ -100,7 +100,7 @@ importers: version: 0.64.0 vitest: specifier: ^3.2.2 - version: 3.2.3(@types/node@22.13.17)(@vitest/ui@3.0.4)(jiti@2.4.2)(sass@1.86.1)(yaml@2.7.1) + version: 3.2.3(@types/node@22.13.17)(@vitest/ui@3.2.4)(jiti@2.4.2)(sass@1.86.1)(yaml@2.7.1) packages/app-builder-lib: dependencies: @@ -191,6 +191,9 @@ importers: resedit: specifier: ^1.7.0 version: 1.7.0 + resolve: + specifier: ^1.22.10 + version: 1.22.10 semver: specifier: 7.7.2 version: 7.7.2 @@ -279,6 +282,9 @@ importers: '@types/plist': specifier: 3.0.5 version: 3.0.5 + '@types/resolve': + specifier: ^1.20.6 + version: 1.20.6 '@types/semver': specifier: 7.7.1 version: 7.7.1 @@ -695,7 +701,7 @@ importers: version: 1.6.3 vitest: specifier: ^3.0.4 - version: 3.1.1(@types/node@22.13.17)(@vitest/ui@3.0.4(vitest@3.2.3))(jiti@2.4.2)(sass@1.86.1)(yaml@2.7.1) + version: 3.1.1(@types/node@22.13.17)(@vitest/ui@3.2.4(vitest@3.2.3))(jiti@2.4.2)(sass@1.86.1)(yaml@2.7.1) vitest-mock-commonjs: specifier: ^1.0.2 version: 1.0.2 @@ -2027,36 +2033,42 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.1': resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.1': resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.1': resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.1': resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.1': resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-win32-arm64@2.5.1': resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} @@ -2125,56 +2137,67 @@ packages: resolution: {integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.39.0': resolution: {integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.39.0': resolution: {integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.39.0': resolution: {integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.39.0': resolution: {integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-powerpc64le-gnu@4.39.0': resolution: {integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.39.0': resolution: {integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.39.0': resolution: {integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.39.0': resolution: {integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.39.0': resolution: {integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.39.0': resolution: {integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.39.0': resolution: {integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==} @@ -2367,6 +2390,9 @@ packages: '@types/request@2.48.12': resolution: {integrity: sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==} + '@types/resolve@1.20.6': + resolution: {integrity: sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==} + '@types/responselike@1.0.3': resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} @@ -2530,15 +2556,15 @@ packages: vite: optional: true - '@vitest/pretty-format@3.0.4': - resolution: {integrity: sha512-ts0fba+dEhK2aC9PFuZ9LTpULHpY/nd6jhAQ5IMU7Gaj7crPCTdCFfgvXxruRBLFS+MLraicCuFXxISEq8C93g==} - '@vitest/pretty-format@3.1.1': resolution: {integrity: sha512-dg0CIzNx+hMMYfNmSqJlLSXEmnNhMswcn3sXO7Tpldr0LiGmg3eXdLLhwkv2ZqgHb/d5xg5F7ezNFRA1fA13yA==} '@vitest/pretty-format@3.2.3': resolution: {integrity: sha512-yFglXGkr9hW/yEXngO+IKMhP0jxyFw2/qys/CK4fFUZnSltD+MU7dVYGrH8rvPcK/O6feXQA+EU33gjaBBbAng==} + '@vitest/pretty-format@3.2.4': + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + '@vitest/runner@3.1.1': resolution: {integrity: sha512-X/d46qzJuEDO8ueyjtKfxffiXraPRfmYasoC4i5+mlLEJ10UvPb0XH5M9C3gWuxd7BAQhpK42cJgJtq53YnWVA==} @@ -2557,13 +2583,10 @@ packages: '@vitest/spy@3.2.3': resolution: {integrity: sha512-JHu9Wl+7bf6FEejTCREy+DmgWe+rQKbK+y32C/k5f4TBIAlijhJbRBIRIOCEpVevgRsCQR2iHRUH2/qKVM/plw==} - '@vitest/ui@3.0.4': - resolution: {integrity: sha512-e+s2F9e9FUURkZ5aFIe1Fi3Y8M7UF6gEuShcaV/ur7y/Ldri+1tzWQ1TJq9Vas42NXnXvCAIrU39Z4U2RyET6g==} + '@vitest/ui@3.2.4': + resolution: {integrity: sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==} peerDependencies: - vitest: 3.0.4 - - '@vitest/utils@3.0.4': - resolution: {integrity: sha512-8BqC1ksYsHtbWH+DfpOAKrFw3jl3Uf9J7yeFh85Pz52IWuh1hBBtyfEbRNNZNjl8H8A5yMLH9/t+k7HIKzQcZQ==} + vitest: 3.2.4 '@vitest/utils@3.1.1': resolution: {integrity: sha512-1XIjflyaU2k3HMArJ50bwSh3wKWPD6Q47wz/NUSmRV0zNywPc4w79ARjg/i/aNINHwA+mIALhUVqD9/aUvZNgg==} @@ -2571,6 +2594,9 @@ packages: '@vitest/utils@3.2.3': resolution: {integrity: sha512-4zFBCU5Pf+4Z6v+rwnZ1HU1yzOKKvDkMXZrymE2PBlbjKJRlrOxbvpfPSvJTGRIwGoahaOGvp+kbCoxifhzJ1Q==} + '@vitest/utils@3.2.4': + resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@vue/compiler-core@3.5.13': resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} @@ -3448,14 +3474,6 @@ packages: fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - fdir@6.4.3: - resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - fdir@6.4.5: resolution: {integrity: sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==} peerDependencies: @@ -4057,6 +4075,9 @@ packages: loupe@3.1.3: resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lowercase-keys@2.0.0: resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} engines: {node: '>=8'} @@ -4992,10 +5013,6 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyglobby@0.2.12: - resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} - engines: {node: '>=12.0.0'} - tinyglobby@0.2.14: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} @@ -7508,6 +7525,8 @@ snapshots: '@types/tough-cookie': 4.0.5 form-data: 2.5.5 + '@types/resolve@1.20.6': {} + '@types/responselike@1.0.3': dependencies: '@types/node': 22.13.17 @@ -7706,15 +7725,15 @@ snapshots: optionalDependencies: vite: 6.2.4(@types/node@22.13.17)(jiti@2.4.2)(sass@1.86.1)(yaml@2.7.1) - '@vitest/pretty-format@3.0.4': + '@vitest/pretty-format@3.1.1': dependencies: tinyrainbow: 2.0.0 - '@vitest/pretty-format@3.1.1': + '@vitest/pretty-format@3.2.3': dependencies: tinyrainbow: 2.0.0 - '@vitest/pretty-format@3.2.3': + '@vitest/pretty-format@3.2.4': dependencies: tinyrainbow: 2.0.0 @@ -7749,22 +7768,16 @@ snapshots: dependencies: tinyspy: 4.0.3 - '@vitest/ui@3.0.4(vitest@3.2.3)': + '@vitest/ui@3.2.4(vitest@3.2.3)': dependencies: - '@vitest/utils': 3.0.4 + '@vitest/utils': 3.2.4 fflate: 0.8.2 flatted: 3.3.3 pathe: 2.0.3 sirv: 3.0.1 - tinyglobby: 0.2.12 - tinyrainbow: 2.0.0 - vitest: 3.2.3(@types/node@22.13.17)(@vitest/ui@3.0.4)(jiti@2.4.2)(sass@1.86.1)(yaml@2.7.1) - - '@vitest/utils@3.0.4': - dependencies: - '@vitest/pretty-format': 3.0.4 - loupe: 3.1.3 + tinyglobby: 0.2.14 tinyrainbow: 2.0.0 + vitest: 3.2.3(@types/node@22.13.17)(@vitest/ui@3.2.4)(jiti@2.4.2)(sass@1.86.1)(yaml@2.7.1) '@vitest/utils@3.1.1': dependencies: @@ -7778,6 +7791,12 @@ snapshots: loupe: 3.1.3 tinyrainbow: 2.0.0 + '@vitest/utils@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + '@vue/compiler-core@3.5.13': dependencies: '@babel/parser': 7.27.0 @@ -8726,10 +8745,6 @@ snapshots: dependencies: pend: 1.2.0 - fdir@6.4.3(picomatch@4.0.2): - optionalDependencies: - picomatch: 4.0.2 - fdir@6.4.5(picomatch@4.0.2): optionalDependencies: picomatch: 4.0.2 @@ -9414,6 +9429,8 @@ snapshots: loupe@3.1.3: {} + loupe@3.2.1: {} + lowercase-keys@2.0.0: {} lru-cache@10.4.3: {} @@ -10384,11 +10401,6 @@ snapshots: tinyexec@0.3.2: {} - tinyglobby@0.2.12: - dependencies: - fdir: 6.4.3(picomatch@4.0.2) - picomatch: 4.0.2 - tinyglobby@0.2.14: dependencies: fdir: 6.4.5(picomatch@4.0.2) @@ -10693,7 +10705,7 @@ snapshots: vitest-mock-commonjs@1.0.2: {} - vitest@3.1.1(@types/node@22.13.17)(@vitest/ui@3.0.4(vitest@3.2.3))(jiti@2.4.2)(sass@1.86.1)(yaml@2.7.1): + vitest@3.1.1(@types/node@22.13.17)(@vitest/ui@3.2.4(vitest@3.2.3))(jiti@2.4.2)(sass@1.86.1)(yaml@2.7.1): dependencies: '@vitest/expect': 3.1.1 '@vitest/mocker': 3.1.1(vite@6.2.4(@types/node@22.13.17)(jiti@2.4.2)(sass@1.86.1)(yaml@2.7.1)) @@ -10717,7 +10729,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.13.17 - '@vitest/ui': 3.0.4(vitest@3.2.3) + '@vitest/ui': 3.2.4(vitest@3.2.3) transitivePeerDependencies: - jiti - less @@ -10732,7 +10744,7 @@ snapshots: - tsx - yaml - vitest@3.2.3(@types/node@22.13.17)(@vitest/ui@3.0.4)(jiti@2.4.2)(sass@1.86.1)(yaml@2.7.1): + vitest@3.2.3(@types/node@22.13.17)(@vitest/ui@3.2.4)(jiti@2.4.2)(sass@1.86.1)(yaml@2.7.1): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.3 @@ -10759,7 +10771,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.13.17 - '@vitest/ui': 3.0.4(vitest@3.2.3) + '@vitest/ui': 3.2.4(vitest@3.2.3) transitivePeerDependencies: - jiti - less diff --git a/test/fixtures/test-app-bun-workspace/bun.lock b/test/fixtures/test-app-bun-workspace/bun.lock new file mode 100644 index 00000000000..3737663df9c --- /dev/null +++ b/test/fixtures/test-app-bun-workspace/bun.lock @@ -0,0 +1,24 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "test-app-bun-isolated", + }, + "packages/app": { + "name": "bun-app", + "version": "1.1.0", + "dependencies": { + "lib": "workspace:*", + }, + }, + "packages/lib": { + "name": "lib", + "version": "1.0.0", + }, + }, + "packages": { + "bun-app": ["bun-app@workspace:packages/app"], + + "lib": ["lib@workspace:packages/lib"], + } +} diff --git a/test/fixtures/test-app-bun-workspace/package.json b/test/fixtures/test-app-bun-workspace/package.json new file mode 100644 index 00000000000..37d7654f60b --- /dev/null +++ b/test/fixtures/test-app-bun-workspace/package.json @@ -0,0 +1,8 @@ +{ + "name": "test-app-bun-workspace", + "private": true, + "version": "1.0.0", + "workspaces": [ + "packages/*" + ] +} diff --git a/test/fixtures/test-app-bun-workspace/packages/app/index.js b/test/fixtures/test-app-bun-workspace/packages/app/index.js new file mode 100644 index 00000000000..b6256ec2090 --- /dev/null +++ b/test/fixtures/test-app-bun-workspace/packages/app/index.js @@ -0,0 +1 @@ +module.exports = require("lib") diff --git a/test/fixtures/test-app-bun-workspace/packages/app/node_modules/lib b/test/fixtures/test-app-bun-workspace/packages/app/node_modules/lib new file mode 120000 index 00000000000..58677ddb4ee --- /dev/null +++ b/test/fixtures/test-app-bun-workspace/packages/app/node_modules/lib @@ -0,0 +1 @@ +../../lib \ No newline at end of file diff --git a/test/fixtures/test-app-bun-workspace/packages/app/package.json b/test/fixtures/test-app-bun-workspace/packages/app/package.json new file mode 100644 index 00000000000..64ce1d72ed4 --- /dev/null +++ b/test/fixtures/test-app-bun-workspace/packages/app/package.json @@ -0,0 +1,24 @@ +{ + "name": "bun-app", + "productName": "Test App ßW", + "version": "1.1.0", + "description": "Test application for Bun isolated linker", + "main": "index.js", + "author": "Foo Bar ", + "license": "MIT", + "dependencies": { + "lib": "workspace:*" + }, + "build": { + "electronVersion": "23.3.10", + "appId": "org.electron-builder.testApp", + "compression": "store", + "npmRebuild": false, + "mac": { + "category": "your.app.category.type" + }, + "linux": { + "category": "Development" + } + } +} diff --git a/test/fixtures/test-app-bun-workspace/packages/lib/index.js b/test/fixtures/test-app-bun-workspace/packages/lib/index.js new file mode 100644 index 00000000000..edff5115848 --- /dev/null +++ b/test/fixtures/test-app-bun-workspace/packages/lib/index.js @@ -0,0 +1 @@ +module.exports = { pad: require("left-pad") } diff --git a/test/fixtures/test-app-bun-workspace/packages/lib/package.json b/test/fixtures/test-app-bun-workspace/packages/lib/package.json new file mode 100644 index 00000000000..de49ea05e75 --- /dev/null +++ b/test/fixtures/test-app-bun-workspace/packages/lib/package.json @@ -0,0 +1,6 @@ +{ + "name": "lib", + "version": "1.0.0", + "main": "index.js", + "dependencies": {} +} diff --git a/test/snapshots/HoistedNodeModuleTest.js.snap b/test/snapshots/HoistedNodeModuleTest.js.snap index c9ec44bc938..d60955c0231 100644 --- a/test/snapshots/HoistedNodeModuleTest.js.snap +++ b/test/snapshots/HoistedNodeModuleTest.js.snap @@ -25,6 +25,562 @@ exports[`conflict versions 2`] = ` } `; +exports[`isInstallDepsBefore=true > bun workspace --linker=hoisted - multiple conflicting versions 1`] = ` +{ + "linux": [], +} +`; + +exports[`isInstallDepsBefore=true > bun workspace --linker=hoisted - multiple conflicting versions 2`] = ` +{ + "files": { + "index.js": { + "offset": "17868", + "size": 32, + }, + "node_modules": { + "files": { + "has-bigints": { + "files": { + ".nycrc": { + "offset": "0", + "size": 139, + }, + "LICENSE": { + "offset": "139", + "size": 1071, + }, + "index.js": { + "offset": "1210", + "size": 374, + }, + "package.json": { + "offset": "1584", + "size": 1166, + }, + "tsconfig.json": { + "offset": "2750", + "size": 123, + }, + }, + }, + "is-bigint": { + "files": { + ".nycrc": { + "offset": "2873", + "size": 139, + }, + "LICENSE": { + "offset": "3012", + "size": 1071, + }, + "index.js": { + "offset": "4083", + "size": 844, + }, + "package.json": { + "offset": "4927", + "size": 1397, + }, + "tsconfig.json": { + "offset": "6324", + "size": 114, + }, + }, + }, + "left-pad": { + "files": { + "COPYING": { + "offset": "6438", + "size": 502, + }, + "index.js": { + "offset": "6940", + "size": 1469, + }, + "package.json": { + "offset": "8409", + "size": 466, + }, + "perf": { + "files": { + "O(n).js": { + "offset": "8875", + "size": 241, + }, + "es6Repeat.js": { + "offset": "9116", + "size": 216, + }, + "perf.js": { + "offset": "9332", + "size": 1442, + }, + }, + }, + "test.js": { + "offset": "10774", + "size": 4005, + }, + }, + }, + "lib": { + "files": { + ".yarnrc.yml": { + "offset": "14779", + "size": 24, + }, + "index.js": { + "offset": "14803", + "size": 46, + }, + "node_modules": { + "files": { + "is-bigint": { + "files": { + ".eslintignore": { + "offset": "14956", + "size": 10, + }, + ".nycrc": { + "offset": "14966", + "size": 139, + }, + "LICENSE": { + "offset": "15105", + "size": 1071, + }, + "index.js": { + "offset": "16176", + "size": 737, + }, + "package.json": { + "offset": "16913", + "size": 955, + }, + }, + }, + }, + }, + "package.json": { + "offset": "14849", + "size": 107, + }, + }, + }, + }, + }, + "package.json": { + "offset": "17900", + "size": 298, + }, + }, +} +`; + +exports[`isInstallDepsBefore=true > bun workspace --linker=hoisted 1`] = ` +{ + "linux": [], +} +`; + +exports[`isInstallDepsBefore=true > bun workspace --linker=hoisted 2`] = ` +{ + "files": { + "index.js": { + "offset": "14936", + "size": 32, + }, + "node_modules": { + "files": { + "has-bigints": { + "files": { + ".nycrc": { + "offset": "0", + "size": 139, + }, + "LICENSE": { + "offset": "139", + "size": 1071, + }, + "index.js": { + "offset": "1210", + "size": 374, + }, + "package.json": { + "offset": "1584", + "size": 1166, + }, + "tsconfig.json": { + "offset": "2750", + "size": 123, + }, + }, + }, + "is-bigint": { + "files": { + ".nycrc": { + "offset": "2873", + "size": 139, + }, + "LICENSE": { + "offset": "3012", + "size": 1071, + }, + "index.js": { + "offset": "4083", + "size": 844, + }, + "package.json": { + "offset": "4927", + "size": 1397, + }, + "tsconfig.json": { + "offset": "6324", + "size": 114, + }, + }, + }, + "left-pad": { + "files": { + "COPYING": { + "offset": "6438", + "size": 502, + }, + "index.js": { + "offset": "6940", + "size": 1469, + }, + "package.json": { + "offset": "8409", + "size": 466, + }, + "perf": { + "files": { + "O(n).js": { + "offset": "8875", + "size": 241, + }, + "es6Repeat.js": { + "offset": "9116", + "size": 216, + }, + "perf.js": { + "offset": "9332", + "size": 1442, + }, + }, + }, + "test.js": { + "offset": "10774", + "size": 4005, + }, + }, + }, + "lib": { + "files": { + ".yarnrc.yml": { + "offset": "14779", + "size": 24, + }, + "index.js": { + "offset": "14803", + "size": 46, + }, + "package.json": { + "offset": "14849", + "size": 87, + }, + }, + }, + }, + }, + "package.json": { + "offset": "14968", + "size": 298, + }, + }, +} +`; + +exports[`isInstallDepsBefore=true > bun workspace --linker=isolated - multiple conflicting versions 1`] = ` +{ + "linux": [], +} +`; + +exports[`isInstallDepsBefore=true > bun workspace --linker=isolated - multiple conflicting versions 2`] = ` +{ + "files": { + "index.js": { + "offset": "17868", + "size": 32, + }, + "node_modules": { + "files": { + "has-bigints": { + "files": { + ".nycrc": { + "offset": "0", + "size": 139, + }, + "LICENSE": { + "offset": "139", + "size": 1071, + }, + "index.js": { + "offset": "1210", + "size": 374, + }, + "package.json": { + "offset": "1584", + "size": 1166, + }, + "tsconfig.json": { + "offset": "2750", + "size": 123, + }, + }, + }, + "is-bigint": { + "files": { + ".nycrc": { + "offset": "2873", + "size": 139, + }, + "LICENSE": { + "offset": "3012", + "size": 1071, + }, + "index.js": { + "offset": "4083", + "size": 844, + }, + "package.json": { + "offset": "4927", + "size": 1397, + }, + "tsconfig.json": { + "offset": "6324", + "size": 114, + }, + }, + }, + "left-pad": { + "files": { + "COPYING": { + "offset": "6438", + "size": 502, + }, + "index.js": { + "offset": "6940", + "size": 1469, + }, + "package.json": { + "offset": "8409", + "size": 466, + }, + "perf": { + "files": { + "O(n).js": { + "offset": "8875", + "size": 241, + }, + "es6Repeat.js": { + "offset": "9116", + "size": 216, + }, + "perf.js": { + "offset": "9332", + "size": 1442, + }, + }, + }, + "test.js": { + "offset": "10774", + "size": 4005, + }, + }, + }, + "lib": { + "files": { + ".yarnrc.yml": { + "offset": "14779", + "size": 24, + }, + "index.js": { + "offset": "14803", + "size": 46, + }, + "node_modules": { + "files": { + "is-bigint": { + "files": { + ".eslintignore": { + "offset": "14956", + "size": 10, + }, + ".nycrc": { + "offset": "14966", + "size": 139, + }, + "LICENSE": { + "offset": "15105", + "size": 1071, + }, + "index.js": { + "offset": "16176", + "size": 737, + }, + "package.json": { + "offset": "16913", + "size": 955, + }, + }, + }, + }, + }, + "package.json": { + "offset": "14849", + "size": 107, + }, + }, + }, + }, + }, + "package.json": { + "offset": "17900", + "size": 298, + }, + }, +} +`; + +exports[`isInstallDepsBefore=true > bun workspace --linker=isolated 1`] = ` +{ + "linux": [], +} +`; + +exports[`isInstallDepsBefore=true > bun workspace --linker=isolated 2`] = ` +{ + "files": { + "index.js": { + "offset": "14936", + "size": 32, + }, + "node_modules": { + "files": { + "has-bigints": { + "files": { + ".nycrc": { + "offset": "0", + "size": 139, + }, + "LICENSE": { + "offset": "139", + "size": 1071, + }, + "index.js": { + "offset": "1210", + "size": 374, + }, + "package.json": { + "offset": "1584", + "size": 1166, + }, + "tsconfig.json": { + "offset": "2750", + "size": 123, + }, + }, + }, + "is-bigint": { + "files": { + ".nycrc": { + "offset": "2873", + "size": 139, + }, + "LICENSE": { + "offset": "3012", + "size": 1071, + }, + "index.js": { + "offset": "4083", + "size": 844, + }, + "package.json": { + "offset": "4927", + "size": 1397, + }, + "tsconfig.json": { + "offset": "6324", + "size": 114, + }, + }, + }, + "left-pad": { + "files": { + "COPYING": { + "offset": "6438", + "size": 502, + }, + "index.js": { + "offset": "6940", + "size": 1469, + }, + "package.json": { + "offset": "8409", + "size": 466, + }, + "perf": { + "files": { + "O(n).js": { + "offset": "8875", + "size": 241, + }, + "es6Repeat.js": { + "offset": "9116", + "size": 216, + }, + "perf.js": { + "offset": "9332", + "size": 1442, + }, + }, + }, + "test.js": { + "offset": "10774", + "size": 4005, + }, + }, + }, + "lib": { + "files": { + ".yarnrc.yml": { + "offset": "14779", + "size": 24, + }, + "index.js": { + "offset": "14803", + "size": 46, + }, + "package.json": { + "offset": "14849", + "size": 87, + }, + }, + }, + }, + }, + "package.json": { + "offset": "14968", + "size": 298, + }, + }, +} +`; + exports[`isInstallDepsBefore=true > npm electron-clear-data 1`] = ` { "win": [], diff --git a/test/src/HoistedNodeModuleTest.ts b/test/src/HoistedNodeModuleTest.ts index bf806fff67f..811e8639ca4 100644 --- a/test/src/HoistedNodeModuleTest.ts +++ b/test/src/HoistedNodeModuleTest.ts @@ -3,6 +3,18 @@ import { Platform, Arch, DIR_TARGET } from "electron-builder" import { outputFile, copySync, rmSync, readJsonSync, writeJsonSync, mkdirSync } from "fs-extra" import * as path from "path" import { spawn } from "builder-util/out/util" +import { execSync } from "child_process" + +const hasBun = (() => { + try { + execSync("bun --version", { stdio: "ignore" }) + return true + } catch { + return false + } +})() + +const testIfBun = hasBun ? test : test.skip test("yarn workspace", ({ expect }) => assertPack( @@ -490,6 +502,181 @@ describe("isInstallDepsBefore=true", { sequential: true }, () => { packed: context => verifyAsarFileTree(expect, context.getResources(Platform.LINUX)), } )) + + testIfBun("bun workspace --linker=isolated", ({ expect }) => + assertPack( + expect, + "test-app-bun-workspace", + { + targets: linuxDirTarget, + projectDir: "packages/app", + }, + { + isInstallDepsBefore: true, + projectDirCreated: projectDir => { + + const appPkg = path.join(projectDir, "packages", "app") + const libPkg = path.join(projectDir, "packages", "lib") + + return Promise.all([ + // root pkgs should not be included + modifyPackageJson(projectDir, data => { + data.dependencies = { + "is-plain-obj": "3.0.0", + } + }), + modifyPackageJson(appPkg, data => { + data.dependencies = { + lib: "workspace:*", + "is-bigint": "1.1.0", + } + }), + modifyPackageJson(libPkg, data => { + data.dependencies = { + "left-pad": "1.3.0" + } + }), + outputFile( + path.join(projectDir, "bunfig.toml"), + "[install]\nlinker = \"isolated\"\n" + ), + ]) + }, + packed: context => verifyAsarFileTree(expect, context.getResources(Platform.LINUX)), + } + )) + + testIfBun("bun workspace --linker=isolated - multiple conflicting versions", ({ expect }) => + assertPack( + expect, + "test-app-bun-workspace", + { + targets: linuxDirTarget, + projectDir: "packages/app", + }, + { + isInstallDepsBefore: true, + projectDirCreated: projectDir => { + + const appPkg = path.join(projectDir, "packages", "app") + const libPkg = path.join(projectDir, "packages", "lib") + + return Promise.all([ + // root pkgs should not be included + modifyPackageJson(projectDir, data => { + data.dependencies = { + "is-plain-obj": "3.0.0", + } + }), + modifyPackageJson(appPkg, data => { + data.dependencies = { + lib: "workspace:*", + "is-bigint": "1.1.0", + } + }), + modifyPackageJson(libPkg, data => { + data.dependencies = { + "left-pad": "1.3.0", + // should include this in a nested node_modules directory + "is-bigint": "1.0.4" + } + }), + outputFile( + path.join(projectDir, "bunfig.toml"), + "[install]\nlinker = \"isolated\"\n" + ), + ]) + }, + packed: context => verifyAsarFileTree(expect, context.getResources(Platform.LINUX)), + } + )) + + testIfBun("bun workspace --linker=hoisted", ({ expect }) => + assertPack( + expect, + "test-app-bun-workspace", + { + targets: linuxDirTarget, + projectDir: "packages/app", + }, + { + isInstallDepsBefore: true, + projectDirCreated: projectDir => { + const appPkg = path.join(projectDir, "packages", "app") + const libPkg = path.join(projectDir, "packages", "lib") + + return Promise.all([ + // root pkgs should not be included + modifyPackageJson(projectDir, data => { + data.dependencies = { + "is-plain-obj": "3.0.0", + } + }), + modifyPackageJson(appPkg, data => { + data.dependencies = { + lib: "workspace:*", + "is-bigint": "1.1.0", + } + }), + modifyPackageJson(libPkg, data => { + data.dependencies = { + "left-pad": "1.3.0" + } + }), + outputFile( + path.join(projectDir, "bunfig.toml"), + "[install]\nlinker = \"hoisted\"\n" + ), + ]) + }, + packed: context => verifyAsarFileTree(expect, context.getResources(Platform.LINUX)), + } + )) + + testIfBun("bun workspace --linker=hoisted - multiple conflicting versions", ({ expect }) => + assertPack( + expect, + "test-app-bun-workspace", + { + targets: linuxDirTarget, + projectDir: "packages/app", + }, + { + isInstallDepsBefore: true, + projectDirCreated: projectDir => { + const appPkg = path.join(projectDir, "packages", "app") + const libPkg = path.join(projectDir, "packages", "lib") + + return Promise.all([ + // root pkgs should not be included + modifyPackageJson(projectDir, data => { + data.dependencies = { + "is-plain-obj": "3.0.0", + } + }), + modifyPackageJson(appPkg, data => { + data.dependencies = { + lib: "workspace:*", + "is-bigint": "1.1.0", + } + }), + modifyPackageJson(libPkg, data => { + data.dependencies = { + "left-pad": "1.3.0", + // should include this in a nested node_modules directory, since it's a conflicting package version + "is-bigint": "1.0.4" + } + }), + outputFile( + path.join(projectDir, "bunfig.toml"), + "[install]\nlinker = \"hoisted\"\n" + ), + ]) + }, + packed: context => verifyAsarFileTree(expect, context.getResources(Platform.LINUX)), + } + )) + test("pnpm shamefully-hoist=true", ({ expect }) => assertPack( expect, From f508b9fe6b9376f2516c912ca0af356176f2bcde Mon Sep 17 00:00:00 2001 From: johnpyp Date: Fri, 31 Oct 2025 18:48:07 -0400 Subject: [PATCH 2/2] refactor: use manual `createRequire` instead of `resolve` --- packages/app-builder-lib/package.json | 1 - .../bunNodeModulesCollector.ts | 16 ++- pnpm-lock.yaml | 3 - test/snapshots/HoistedNodeModuleTest.js.snap | 120 ++++++++++++++++-- test/src/HoistedNodeModuleTest.ts | 4 + 5 files changed, 122 insertions(+), 22 deletions(-) diff --git a/packages/app-builder-lib/package.json b/packages/app-builder-lib/package.json index 9979265cc48..b5c34a84779 100644 --- a/packages/app-builder-lib/package.json +++ b/packages/app-builder-lib/package.json @@ -76,7 +76,6 @@ "minimatch": "^10.0.3", "plist": "3.1.0", "resedit": "^1.7.0", - "resolve": "^1.22.10", "semver": "7.7.2", "tar": "^6.1.12", "temp-file": "^3.4.0", diff --git a/packages/app-builder-lib/src/node-module-collector/bunNodeModulesCollector.ts b/packages/app-builder-lib/src/node-module-collector/bunNodeModulesCollector.ts index 2fe0c889bfe..8fe9197a1d6 100644 --- a/packages/app-builder-lib/src/node-module-collector/bunNodeModulesCollector.ts +++ b/packages/app-builder-lib/src/node-module-collector/bunNodeModulesCollector.ts @@ -1,9 +1,9 @@ import { log } from "builder-util" import * as path from "path" -import { sync as resolveSync } from "resolve" import { NodeModulesCollector } from "./nodeModulesCollector" import { PM } from "./packageManager" import { BunDependency, BunManifest, Dependencies } from "./types" +import { createRequire } from "module" export class BunNodeModulesCollector extends NodeModulesCollector { public readonly installOptions = { manager: PM.BUN, lockfile: "bun.lock" } @@ -147,11 +147,15 @@ export class BunNodeModulesCollector extends NodeModulesCollector bun workspace --linker=hoisted - multiple co { "files": { "index.js": { - "offset": "17868", + "offset": "31239", "size": 32, }, "node_modules": { @@ -168,11 +168,35 @@ exports[`isInstallDepsBefore=true > bun workspace --linker=hoisted - multiple co }, }, }, + "process": { + "files": { + "LICENSE": { + "offset": "17868", + "size": 1098, + }, + "browser.js": { + "offset": "18966", + "size": 5418, + }, + "index.js": { + "offset": "24384", + "size": 96, + }, + "package.json": { + "offset": "24480", + "size": 449, + }, + "test.js": { + "offset": "24929", + "size": 6310, + }, + }, + }, }, }, "package.json": { - "offset": "17900", - "size": 298, + "offset": "31271", + "size": 325, }, }, } @@ -188,7 +212,7 @@ exports[`isInstallDepsBefore=true > bun workspace --linker=hoisted 2`] = ` { "files": { "index.js": { - "offset": "14936", + "offset": "28307", "size": 32, }, "node_modules": { @@ -293,11 +317,35 @@ exports[`isInstallDepsBefore=true > bun workspace --linker=hoisted 2`] = ` }, }, }, + "process": { + "files": { + "LICENSE": { + "offset": "14936", + "size": 1098, + }, + "browser.js": { + "offset": "16034", + "size": 5418, + }, + "index.js": { + "offset": "21452", + "size": 96, + }, + "package.json": { + "offset": "21548", + "size": 449, + }, + "test.js": { + "offset": "21997", + "size": 6310, + }, + }, + }, }, }, "package.json": { - "offset": "14968", - "size": 298, + "offset": "28339", + "size": 325, }, }, } @@ -313,7 +361,7 @@ exports[`isInstallDepsBefore=true > bun workspace --linker=isolated - multiple c { "files": { "index.js": { - "offset": "17868", + "offset": "31239", "size": 32, }, "node_modules": { @@ -446,11 +494,35 @@ exports[`isInstallDepsBefore=true > bun workspace --linker=isolated - multiple c }, }, }, + "process": { + "files": { + "LICENSE": { + "offset": "17868", + "size": 1098, + }, + "browser.js": { + "offset": "18966", + "size": 5418, + }, + "index.js": { + "offset": "24384", + "size": 96, + }, + "package.json": { + "offset": "24480", + "size": 449, + }, + "test.js": { + "offset": "24929", + "size": 6310, + }, + }, + }, }, }, "package.json": { - "offset": "17900", - "size": 298, + "offset": "31271", + "size": 325, }, }, } @@ -466,7 +538,7 @@ exports[`isInstallDepsBefore=true > bun workspace --linker=isolated 2`] = ` { "files": { "index.js": { - "offset": "14936", + "offset": "28307", "size": 32, }, "node_modules": { @@ -571,11 +643,35 @@ exports[`isInstallDepsBefore=true > bun workspace --linker=isolated 2`] = ` }, }, }, + "process": { + "files": { + "LICENSE": { + "offset": "14936", + "size": 1098, + }, + "browser.js": { + "offset": "16034", + "size": 5418, + }, + "index.js": { + "offset": "21452", + "size": 96, + }, + "package.json": { + "offset": "21548", + "size": 449, + }, + "test.js": { + "offset": "21997", + "size": 6310, + }, + }, + }, }, }, "package.json": { - "offset": "14968", - "size": 298, + "offset": "28339", + "size": 325, }, }, } diff --git a/test/src/HoistedNodeModuleTest.ts b/test/src/HoistedNodeModuleTest.ts index 811e8639ca4..a1e1581cc94 100644 --- a/test/src/HoistedNodeModuleTest.ts +++ b/test/src/HoistedNodeModuleTest.ts @@ -529,6 +529,7 @@ describe("isInstallDepsBefore=true", { sequential: true }, () => { data.dependencies = { lib: "workspace:*", "is-bigint": "1.1.0", + process: "^0.11.10", } }), modifyPackageJson(libPkg, data => { @@ -572,6 +573,7 @@ describe("isInstallDepsBefore=true", { sequential: true }, () => { data.dependencies = { lib: "workspace:*", "is-bigint": "1.1.0", + process: "^0.11.10", } }), modifyPackageJson(libPkg, data => { @@ -616,6 +618,7 @@ describe("isInstallDepsBefore=true", { sequential: true }, () => { data.dependencies = { lib: "workspace:*", "is-bigint": "1.1.0", + process: "^0.11.10", } }), modifyPackageJson(libPkg, data => { @@ -658,6 +661,7 @@ describe("isInstallDepsBefore=true", { sequential: true }, () => { data.dependencies = { lib: "workspace:*", "is-bigint": "1.1.0", + process: "^0.11.10", } }), modifyPackageJson(libPkg, data => {