Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 2 additions & 2 deletions docs/pm/cli/install.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ The migration process handles:

### Workspace Configuration

When a `pnpm-workspace.yaml` file exists, Bun migrates workspace settings to your root `package.json`:
When a `pnpm-workspace.yaml` file exists, Bun migrates workspace settings to your root `package.json`. This happens together with the lockfile migration, and also when there is no `pnpm-lock.yaml` to migrate (it was never committed, or it is too old to convert), as long as `bun.lock` does not exist yet and the root `package.json` has no `workspaces` field of its own:

```yaml pnpm-workspace.yaml icon="file-code"
packages:
Expand Down Expand Up @@ -596,7 +596,7 @@ Bun migrates the following pnpm configuration from both `pnpm-lock.yaml` and `pn
- All catalog entries referenced by dependencies must exist in the catalogs definition
- Every workspace in `pnpm-lock.yaml` must have its `package.json` on disk (in Docker, copy them in before `bun install`)
- Relative `link:` dependencies and git dependencies with a sub-directory (`resolution.path`) are not supported
- If migration fails for any of these reasons, Bun prints why and resolves from scratch instead
- If migration fails for any of these reasons, Bun prints why and resolves from scratch instead. The `pnpm-workspace.yaml` settings above are still migrated, so workspaces, catalogs and overrides are not lost

After migration, you can safely remove `pnpm-lock.yaml` and `pnpm-workspace.yaml` files.

Expand Down
6 changes: 4 additions & 2 deletions docs/pm/isolated-installs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,15 @@ bun install --linker isolated
Isolated installs are conceptually similar to pnpm, so migration is direct:

```bash terminal icon="terminal"
# Remove pnpm files
rm -rf node_modules pnpm-lock.yaml
# Remove pnpm's node_modules
rm -rf node_modules

# Install with Bun's isolated linker
bun install --linker isolated
```

Keep `pnpm-lock.yaml` around for this first install: Bun converts it to `bun.lock`, so you keep the versions pnpm had resolved. The workspace list, catalogs and overrides in `pnpm-workspace.yaml` are moved into the root `package.json` whether or not a `pnpm-lock.yaml` is present. See [pnpm migration](/pm/cli/install#pnpm-migration) for what is converted.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

The main difference is that Bun uses symlinks in `node_modules` while pnpm uses a global store with symlinks.

## When to use isolated installs
Expand Down
7 changes: 7 additions & 0 deletions src/install/PackageManager/install_with_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1937,6 +1937,13 @@ fn create_new_lockfile_and_enqueue(
Global::crash();
}

// A loaded lockfile already describes the project (a migrated
// pnpm-lock.yaml imports pnpm-workspace.yaml itself); without one, the
// package.json read below is all the install has to go on.
Comment thread
robobun marked this conversation as resolved.
Outdated
if !matches!(load_result, lockfile::LoadResult::Ok { .. }) {
crate::pnpm::migrate_pnpm_workspace_config(manager)?;
}

// SAFETY: `manager.log` is a non-null backref to the CLI log set at init().
let root_package_json_entry = match manager.workspace_package_json_cache.get_with_path(
manager.log_mut(),
Expand Down
76 changes: 36 additions & 40 deletions src/install/PackageManager/updatePackageJSONAndInstall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,12 +486,12 @@ fn update_package_json_and_install_with_manager_with_updates(
// The Smarter™ approach is you resolve ahead of time and write to disk once!
// But, turns out that's slower in any case where more than one package has to be resolved (most of the time!)
// Concurrent network requests are faster than doing one and then waiting until the next batch
let new_package_json_source: Vec<u8> = package_json_writer
.ctx
.written_without_trailing_zero()
.to_vec();
// The cache entry (`Cow<'static, [u8]>`) outlives this stack frame, so it needs its own copy.
current_package_json.source.contents = Cow::Owned(new_package_json_source.clone());
current_package_json.source.contents = Cow::Owned(
package_json_writer
.ctx
.written_without_trailing_zero()
.to_vec(),
);
// The edits above went into a promoted copy
// (`current_package_json_root`), so re-parse the
// printed source so the cached AST (consumed by `FolderResolver` for workspace
Expand Down Expand Up @@ -664,40 +664,36 @@ fn update_package_json_and_install_with_manager_with_updates(
}

if manager.options.do_.contains(Do::WRITE_PACKAGE_JSON) {
let (source, path): (&[u8], &ZStr) =
if matches!(manager.options.patch_features, PatchFeatures::Commit { .. }) {
'source_and_path: {
let root_package_json_entry = match manager
.workspace_package_json_cache
.get_with_path(
manager.log_mut(),
root_package_json_path.as_bytes(),
GetJSONOptions::default(),
)
.unwrap()
{
Ok(e) => e,
Err(err) => {
Output::err(
err,
"failed to read/parse package.json at '{s}'",
(BStr::new(root_package_json_path.as_bytes()),),
);
Global::exit(1);
}
};

break 'source_and_path (
&root_package_json_entry.source.contents,
root_package_json_path,
);
}
} else {
(
&new_package_json_source,
manager.original_package_json_path.as_zstr(),
)
};
// `bun patch --commit` records the patch in the root package.json even
// when run from a workspace member; everything else edited the cwd's.
Comment thread
robobun marked this conversation as resolved.
Outdated
let path: &ZStr = if matches!(manager.options.patch_features, PatchFeatures::Commit { .. })
{
root_package_json_path
} else {
manager.original_package_json_path.as_zstr()
};
// The cache entry, not the text printed before the install: a pnpm
// migration during `install_with_manager` edits the root entry too.
Comment thread
robobun marked this conversation as resolved.
Outdated
let entry = match manager
.workspace_package_json_cache
.get_with_path(
manager.log_mut(),
path.as_bytes(),
GetJSONOptions::default(),
)
.unwrap()
{
Ok(entry) => entry,
Err(err) => {
Output::err(
err,
"failed to read/parse package.json at '{s}'",
(BStr::new(path.as_bytes()),),
);
Global::exit(1);
}
};
let source: &[u8] = &entry.source.contents;

// Now that we've run the install step
// We can save our in-memory package.json to disk
Expand Down
Loading