Skip to content
Merged
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
6 changes: 6 additions & 0 deletions .changeset/scaffold-pnpm-polish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@marko/create": patch
"create-marko": patch
---

When scaffolding with pnpm, approve esbuild's build script (only if esbuild is actually installed) so vite-based templates install cleanly instead of erroring with `ERR_PNPM_IGNORED_BUILDS`. The "next steps" run command now uses the package manager you ran with (e.g. `pnpm run dev`) instead of always printing `npm`.
6 changes: 4 additions & 2 deletions packages/create/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,13 @@ export async function run(options: CliOptions): Promise<void> {
const { projectPath, installer, installed, scripts } = await result;
if (spinning) spin.stop("Downloaded app");

// `<pm> run <script>` is valid for npm/pnpm/yarn/bun alike.
const script = scripts.dev ? "dev" : scripts.start ? "start" : undefined;
const steps = [
`cd ${relative(process.cwd(), projectPath) || "."}`,
...(installed ? [] : [`${installer} install`]),
scripts.dev ? "npm run dev" : scripts.start ? "npm start" : "",
].filter(Boolean);
...(script ? [`${installer} run ${script}`] : []),
];

p.outro(
`Project created! Next steps:\n${steps
Expand Down
19 changes: 16 additions & 3 deletions packages/create/src/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,22 @@ async function install(installer: string, cwd: string): Promise<boolean> {
await exec(cwd, installer, ["install"], { shell: true });
return true;
} catch {
// Some package managers exit non-zero even on a usable install (e.g. pnpm's
// ignored-build-scripts warning). Don't fail the whole scaffold for it.
return false;
// pnpm exits non-zero when it blocks a dependency's build scripts. The
// vite-based templates rely on esbuild's, so approve just esbuild — pnpm
// writes nothing and no-ops if esbuild wasn't actually installed — then
// re-install to confirm that was the only problem. Any other package
// manager (or a genuine pnpm failure) is a real error.
if (installer !== "pnpm") return false;

try {
await exec(cwd, installer, ["approve-builds", "esbuild"], {
shell: true,
});
await exec(cwd, installer, ["install"], { shell: true });
return true;
} catch {
return false;
}
Comment on lines +199 to +214

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Gate the retry on the actual esbuild ignored-build error.

packages/create/src/exec.ts rejects with only a generic exit-code error, so this catch cannot distinguish ERR_PNPM_IGNORED_BUILDS from network, authentication, lockfile, or unrelated dependency failures. Every pnpm failure therefore runs approve-builds esbuild, potentially persisting build configuration in templates without esbuild, before retrying. Preserve the diagnostic output and only approve/retry when the ignored-build report names esbuild; otherwise return false.

Suggested gating shape
-  } catch {
-    if (installer !== "pnpm") return false;
+  } catch (err) {
+    if (
+      installer !== "pnpm" ||
+      !isEsbuildIgnoredBuildError(err)
+    ) {
+      return false;
+    }
🧰 Tools
🪛 OpenGrep (1.25.0)

[ERROR] 207-209: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)


[ERROR] 210-210: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/create/src/create.ts` around lines 199 - 214, Update the retry logic
around the pnpm fallback and the error produced by exec so the catch can inspect
preserved diagnostic output, proceed only when the failure is
ERR_PNPM_IGNORED_BUILDS and the report names esbuild, and otherwise return false
immediately. Keep the existing approve-builds esbuild and install retry
unchanged for the qualifying case, while retaining the original error output for
diagnostics.

}
}

Expand Down