Skip to content
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

feat(core): add bun package manager #19113

Closed
Closed
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
2 changes: 1 addition & 1 deletion docs/generated/devkit/PackageManager.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Type alias: PackageManager

Ƭ **PackageManager**: `"yarn"` \| `"pnpm"` \| `"npm"`
Ƭ **PackageManager**: `"yarn"` \| `"pnpm"` \| `"npm"` \| `"bun"`
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
npm: 'package-lock.json',
yarn: 'yarn.lock',
pnpm: 'pnpm-lock.yaml',
bun: 'bun.lockb',
};
const packageManager = detectPackageManager(host.root);
const packageLockFile = packageManagerLockFile[packageManager];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default function update(tree: Tree) {
npm: 'package-lock.json',
yarn: 'yarn.lock',
pnpm: 'pnpm-lock.yaml',
bun: 'bun.lockb',
};

for (const [name, config] of projects.entries()) {
Expand Down
2 changes: 1 addition & 1 deletion packages/nx/schemas/nx-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@
"packageManager": {
"type": "string",
"description": "The default package manager to use.",
"enum": ["yarn", "pnpm", "npm"]
"enum": ["yarn", "pnpm", "npm", "bun"]
},
"defaultCollection": {
"type": "string",
Expand Down
11 changes: 9 additions & 2 deletions packages/nx/src/plugins/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { hashArray } from '../../hasher/file-hasher';
import { detectPackageManager } from '../../utils/package-manager';
import { workspaceRoot } from '../../utils/workspace-root';
import { nxVersion } from '../../utils/versions';
import { execSync } from 'child_process';

export const name = 'nx-js-graph-plugin';

Expand All @@ -50,7 +51,10 @@ export const createNodes: CreateNodes = [
}

const lockFilePath = join(workspaceRoot, lockFile);
const lockFileContents = readFileSync(lockFilePath).toString();
const lockFileContents =
packageManager !== 'bun'
? readFileSync(lockFilePath).toString()
: execSync(lockFilePath).toString();
const lockFileHash = getLockFileHash(lockFileContents);

if (!lockFileNeedsReprocessing(lockFileHash)) {
Expand Down Expand Up @@ -88,7 +92,10 @@ export const createDependencies: CreateDependencies = (
parsedLockFile
) {
const lockFilePath = join(workspaceRoot, getLockFileName(packageManager));
const lockFileContents = readFileSync(lockFilePath).toString();
const lockFileContents =
packageManager !== 'bun'
? readFileSync(lockFilePath).toString()
: execSync(lockFilePath).toString();
const lockFileHash = getLockFileHash(lockFileContents);

if (!lockFileNeedsReprocessing(lockFileHash)) {
Expand Down
30 changes: 29 additions & 1 deletion packages/nx/src/plugins/js/lock-file/lock-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,18 @@ import { CreateDependenciesContext } from '../../../utils/nx-plugin';
const YARN_LOCK_FILE = 'yarn.lock';
const NPM_LOCK_FILE = 'package-lock.json';
const PNPM_LOCK_FILE = 'pnpm-lock.yaml';
export const LOCKFILES = [YARN_LOCK_FILE, NPM_LOCK_FILE, PNPM_LOCK_FILE];
const BUN_LOCK_FILE = 'bun.lockb';
export const LOCKFILES = [
YARN_LOCK_FILE,
NPM_LOCK_FILE,
PNPM_LOCK_FILE,
BUN_LOCK_FILE,
];

const YARN_LOCK_PATH = join(workspaceRoot, YARN_LOCK_FILE);
const NPM_LOCK_PATH = join(workspaceRoot, NPM_LOCK_FILE);
const PNPM_LOCK_PATH = join(workspaceRoot, PNPM_LOCK_FILE);
const BUN_LOCK_PATH = join(workspaceRoot, BUN_LOCK_FILE);

/**
* Parses lock file and maps dependencies and metadata to {@link LockFileGraph}
Expand All @@ -67,6 +74,11 @@ export function getLockFileNodes(
if (packageManager === 'npm') {
return getNpmLockfileNodes(contents, lockFileHash);
}
if (packageManager === 'bun') {
// bun uses yarn v1 for the file format
const packageJson = readJsonFile('package.json');
return getYarnLockfileNodes(contents, lockFileHash, packageJson);
}
} catch (e) {
if (!isPostInstallProcess()) {
output.error({
Expand Down Expand Up @@ -98,6 +110,10 @@ export function getLockFileDependencies(
if (packageManager === 'npm') {
return getNpmLockfileDependencies(contents, lockFileHash, context);
}
if (packageManager === 'bun') {
// bun uses yarn v1 for the file format
return getYarnLockfileDependencies(contents, lockFileHash, context);
}
} catch (e) {
if (!isPostInstallProcess()) {
output.error({
Expand All @@ -120,6 +136,9 @@ export function lockFileExists(packageManager: PackageManager): boolean {
if (packageManager === 'npm') {
return existsSync(NPM_LOCK_PATH);
}
if (packageManager === 'bun') {
return existsSync(BUN_LOCK_PATH);
}
throw new Error(
`Unknown package manager ${packageManager} or lock file missing`
);
Expand All @@ -140,6 +159,9 @@ export function getLockFileName(packageManager: PackageManager): string {
if (packageManager === 'npm') {
return NPM_LOCK_FILE;
}
if (packageManager === 'bun') {
return BUN_LOCK_FILE;
}
throw new Error(`Unknown package manager: ${packageManager}`);
}

Expand Down Expand Up @@ -172,6 +194,12 @@ export function createLockFile(
const prunedGraph = pruneProjectGraph(graph, packageJson);
return stringifyNpmLockfile(prunedGraph, content, normalizedPackageJson);
}
if (packageManager === 'bun') {
output.log({
title:
"Unable to create bun lock files. Run bun install it's just as quick",
});
}
} catch (e) {
if (!isPostInstallProcess()) {
const additionalInfo = [
Expand Down
4 changes: 3 additions & 1 deletion packages/nx/src/utils/package-manager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,15 @@ describe('package-manager', () => {
return false;
case 'package-lock.json':
return false;
case 'bun.lockb':
return false;
default:
return jest.requireActual('fs').existsSync(p);
}
});
const packageManager = detectPackageManager();
expect(packageManager).toEqual('npm');
expect(fs.existsSync).toHaveBeenCalledTimes(5);
expect(fs.existsSync).toHaveBeenCalledTimes(6);
});
});

Expand Down
26 changes: 23 additions & 3 deletions packages/nx/src/utils/package-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { readNxJson } from '../config/configuration';

const execAsync = promisify(exec);

export type PackageManager = 'yarn' | 'pnpm' | 'npm';
export type PackageManager = 'yarn' | 'pnpm' | 'npm' | 'bun';

export interface PackageManagerCommands {
preInstall?: string;
Expand All @@ -37,6 +37,8 @@ export function detectPackageManager(dir: string = ''): PackageManager {
? 'yarn'
: existsSync(join(dir, 'pnpm-lock.yaml'))
? 'pnpm'
: existsSync(join(dir, 'bun.lockb'))
? 'bun'
: 'npm')
);
}
Expand Down Expand Up @@ -113,6 +115,18 @@ export function getPackageManagerCommand(
list: 'npm ls',
};
},
bun: () => {
return {
install: 'bun install',
ciInstall: 'bun install --frozen-lockfile',
add: 'bun add',
addDev: 'bun add -D',
rm: 'bun remove',
exec: 'bunx',
run: (script: string, args: string) => `bun ${script} ${args}`,
list: 'bun pm ls',
};
},
};

return commands[packageManager]();
Expand Down Expand Up @@ -314,12 +328,16 @@ export async function packageRegistryView(
args: string
): Promise<string> {
let pm = detectPackageManager();
if (pm === 'yarn') {
if (pm === 'yarn' || pm === 'bun') {
/**
* yarn has `yarn info` but it behaves differently than (p)npm,
* which makes it's usage unreliable
*
* @see https://github.com/nrwl/nx/pull/9667#discussion_r842553994
*
* Bun has a pm ls function but it only relates to it's lockfile
* and acts differently from all other package managers
* from Jarred"it probably would be bun pm view <package-name>"
*/
pm = 'npm';
}
Expand All @@ -334,13 +352,15 @@ export async function packageRegistryPack(
version: string
): Promise<{ tarballPath: string }> {
let pm = detectPackageManager();
if (pm === 'yarn') {
if (pm === 'yarn' || pm === 'bun') {
/**
* `(p)npm pack` will download a tarball of the specified version,
* whereas `yarn` pack creates a tarball of the active workspace, so it
* does not work for getting the content of a library.
*
* @see https://github.com/nrwl/nx/pull/9667#discussion_r842553994
*
* bun doesn't current support pack
*/
pm = 'npm';
}
Expand Down