cloudflare / cloudflare/vinext

create-vinext-app leaves pnpm 12 project with an outdated lockfile after ERR_PNPM_IGNORED_BUILDS

Open
#3,198 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
8.8k
Forks
406
Avg merge
2d 6h
Merged PRs (30d)
120

Description

## Description

`create-vinext-app` can leave a newly created pnpm 12 project in an inconsistent state when dependency build scripts require approval.

The generated `pnpm-lock.yaml` contains the required Vite and Cloudflare dev dependencies, but those dependencies are missing from `package.json`. As a result, a clean or frozen install fails with `ERR_PNPM_OUTDATED_LOCKFILE`.

The initializer still prints `vinext init complete!` and `Success! Created ...`, even though the generated project cannot be installed in a clean environment.

## Versions

- `create-vinext-app`: `1.0.0-beta.2`
- `vinext`: `1.0.0-beta.9`
- `pnpm`: `12.0.0`
- Node.js: `24.21.0`
- Platform: macOS arm64
- Deployment target: Cloudflare Workers

## Reproduction

```bash
pnpm dlx create-vinext-app@1.0.0-beta.2 \
/tmp/vinext-repro \
--use-pnpm \
--yes \
--disable-git \
--platform=cloudflare

cd /tmp/vinext-repro
pnpm install --frozen-lockfile
```

## Actual behavior

While adding the Cloudflare/Vite dev dependencies, pnpm reports:

```text
Error: ERR_PNPM_IGNORED_BUILDS

Ignored build scripts: esbuild@0.28.1, workerd@1.20260907.1
Run "pnpm approve-builds" to pick which dependencies should be allowed
to run scripts.
```

`create-vinext-app` catches this error and continues:

```text
vinext init complete!

! Dependency installation is waiting for build-script approval

Success! Created vinext-repro at /tmp/vinext-repro
```

However, the resulting `package.json` does not contain:

```json
{
"devDependencies": {
"@cloudflare/vite-plugin": "^1.54.5",
"@vitejs/plugin-react": "^6.1.1",
"@vitejs/plugin-rsc": "^0.5.34",
"vite": "^8.2.2",
"wrangler": "^4.129.1"
}
}
```

The generated `pnpm-lock.yaml` does contain those dependencies.

Therefore, the suggested recovery command is also blocked:

```bash
pnpm approve-builds esbuild workerd
```

```text
Error: ERR_PNPM_OUTDATED_LOCKFILE

Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not
up to date with package.json.

5 dependencies were removed:
@cloudflare/vite-plugin
@vitejs/plugin-react
@vitejs/plugin-rsc
vite
wrangler
```

pnpm also generates unresolved entries in `pnpm-workspace.yaml`:

```yaml
allowBuilds:
esbuild: set this to true or false
workerd: set this to true or false
```

## Expected behavior

When build-script approval is required, `create-vinext-app` should leave the project in a recoverable and internally consistent state:

- `package.json` and `pnpm-lock.yaml` should contain matching dependency declarations.
- `pnpm approve-builds` should be runnable immediately.
- The initializer should not print an unconditional success message if the generated project requires manual recovery.
- Build scripts should not be automatically trusted; the user should still explicitly approve or deny them.

## Why local builds can appear to work

The failed `pnpm add` has already materialized the packages in `node_modules`, so `vinext build` may work in the original directory.

A clean environment, such as a Cloudflare build using `pnpm install --frozen-lockfile`, does not have that existing `node_modules` state and fails before the build starts.

## Suspected cause

The initializer installs runtime dependencies and dev dependencies in separate commands.

The runtime dependency installation succeeds. The dev dependency installation then reaches `esbuild` and `workerd`, updates the lockfile and local installation state, but exits with `ERR_PNPM_IGNORED_BUILDS` before the five requested dev dependencies are persisted to `package.json`.

The error is treated as recoverable here:

https://github.com/cloudflare/vinext/blob/86afc110511c99eb4f654d5b9e3f90c5ff3b8f14/packages/vinext/src/init.ts#L653-L705

The expected dev dependencies are defined here:

https://github.com/cloudflare/vinext/blob/86afc110511c99eb4f654d5b9e3f90c5ff3b8f14/packages/vinext/src/init.ts#L219-L233

pnpm has a related open issue about automatically generated `allowBuilds` placeholders:

https://github.com/pnpm/pnpm/issues/11574

## Workaround

Restore the missing dev dependencies in `package.json` and explicitly resolve the build permissions:

```yaml
# pnpm-workspace.yaml
allowBuilds:
esbuild: true
workerd: true
```

Then run:

```bash
pnpm install --frozen-lockfile
```

Another way to avoid the broken intermediate state is to scaffold with `--skip-install`, configure `allowBuilds`, and then run `pnpm install` separately.

## Suggested regression test

Create a pnpm project where adding the Cloudflare dev dependencies reports `ERR_PNPM_IGNORED_BUILDS`, then verify that:

1. `package.json` and `pnpm-lock.yaml` remain consistent.
2. `pnpm install --frozen-lockfile --ignore-scripts` does not report `ERR_PNPM_OUTDATED_LOCKFILE`.
3. The user can complete the documented build-script approval flow.

Contributor guide

Open the contributing guide

Research direction

Start in packages/vinext/src/init.ts, especially the dependency installation handling at lines 653-705 and the Cloudflare dev dependency list at lines 219-233. Reproduce the pnpm 12 flow with --platform=cloudflare, then add a regression test covering ERR_PNPM_IGNORED_BUILDS. Done means package.json and pnpm-lock.yaml stay consistent, frozen install succeeds, and the approval flow remains explicit without an unconditional success message.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript, vite
Domain
build-system, cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.