create-apollo-suite-monorepo 1.0.1469 → 1.0.1470

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -238,12 +238,23 @@ them, after `pnpm backend:update` has brought in a backend with
238
238
 
239
239
  ## Deploying to production
240
240
 
241
- The scaffold pins `packageManager: "pnpm@11.0.0"` so Corepack picks the right
242
- pnpm. If your CI / deploy host installs pnpm separately, **make sure it's
243
- pnpm 11+** — pnpm 11 sets `strictDepBuilds: true` by default and reads the
244
- allow-list from `allowBuilds` in `pnpm-workspace.yaml`. pnpm 10 silently
245
- ignores `allowBuilds`; pnpm 11 silently ignores the deprecated
246
- `onlyBuiltDependencies`. Mixing the two leads to `sharp` (and `esbuild`,
241
+ The scaffold pins `packageManager: "pnpm@12.15.0"` (the version lives in
242
+ `pnpm-policy.mjs`), so Corepack or pnpm itself switches to it. If your CI /
243
+ deploy host installs pnpm separately, **make sure it's pnpm 12+** — pnpm sets
244
+ `strictDepBuilds: true` by default and reads the allow-list from `allowBuilds`
245
+ in `pnpm-workspace.yaml`; pnpm 10 silently ignores `allowBuilds`, and pnpm 11+
246
+ silently ignores the deprecated `onlyBuiltDependencies`. Once the version is
247
+ pinned, pnpm 12 fails (`ERR_PNPM_UNRECOGNIZED_WORKSPACE_SETTINGS`) on any key
248
+ in `pnpm-workspace.yaml` it does not know. No `.npmrc` is generated: pnpm 11+
249
+ reads it only for auth and registry, so the install settings it used to carry
250
+ (`engineStrict`, `autoInstallPeers`, `strictPeerDependencies`,
251
+ `publicHoistPattern`, `shellEmulator`) live in `pnpm-workspace.yaml`.
252
+ ⚠️ pnpm 12 also ignores a registry token written as an environment variable
253
+ in a **project** `.npmrc`. It warns `environment variables are not expanded in
254
+ repository-controlled registry credentials` and installs without the token.
255
+ On a CI or deploy host that installs from a private registry, put the token in
256
+ the user-level `~/.npmrc` or pnpm's global config instead.
257
+ Mixing up the build allow-list leads to `sharp` (and `esbuild`,
247
258
  `@swc/core`, …) skipping their postinstalls, which surfaces at runtime as:
248
259
 
249
260
  ```
package/index.mjs CHANGED
@@ -20,6 +20,7 @@ import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync, symli
20
20
  import { resolve, basename } from "node:path";
21
21
  import { fileURLToPath } from "node:url";
22
22
  import { NODE_VERSION, NODE_RANGE, assertSupportedNode } from "./node-policy.mjs";
23
+ import { PNPM_VERSION, PNPM_RANGE } from "./pnpm-policy.mjs";
23
24
  import { createInterface } from "node:readline";
24
25
  import {
25
26
  APPS_FILE_ENV_VALUE,
@@ -244,7 +245,7 @@ function preflight(flags) {
244
245
  // `pnpm backend:setup`, and `pnpm backend:upgrade` will fail without it.
245
246
  const TOOLS = [
246
247
  { cmd: "git", required: true, missing: "git is required but not found.\n Install: https://git-scm.com/" },
247
- { cmd: "pnpm", required: false, missing: "pnpm not found — install with: npm i -g pnpm (required for workspaces)" },
248
+ { cmd: "pnpm", required: false, missing: `pnpm not found — install with: npm i -g pnpm@${PNPM_VERSION} (required for workspaces)` },
248
249
  { cmd: "bun", required: false, missing:
249
250
  "bun not found — required by apps/backend for db:push, db:seed,\n" +
250
251
  " plugins:build, and the upgrade pipeline.\n" +
@@ -416,13 +417,14 @@ export function writeRootPackageJson(targetDir, dirName) {
416
417
  // never hits this; pnpm skips them, so the monorepo must ask for it.
417
418
  "@opentelemetry/api": "^1.9.0",
418
419
  },
419
- // Pin to pnpm 11 because `pnpm-workspace.yaml` uses the `allowBuilds`
420
- // map format introduced in v11 (deprecated `onlyBuiltDependencies` is
421
- // silently ignored on v11 — sharp/esbuild postinstalls then no-op and
422
- // /admin/media crashes at runtime with "Cannot find module sharp-…").
423
- // Corepack uses this field to auto-fetch the right pnpm.
424
- packageManager: "pnpm@11.0.0",
425
- engines: { node: NODE_RANGE, pnpm: ">=11" },
420
+ // Pinned exactly so Corepack / pnpm's own version switching fetch it;
421
+ // the version lives in pnpm-policy.mjs. `pnpm-workspace.yaml` uses the
422
+ // `allowBuilds` map, which needs pnpm >= 11 (older pnpm ignores it —
423
+ // sharp/esbuild postinstalls then no-op and /admin/media crashes at
424
+ // runtime with "Cannot find module sharp-…"). pnpm 12 also rejects any
425
+ // unknown pnpm-workspace.yaml key once the project pins it.
426
+ packageManager: `pnpm@${PNPM_VERSION}`,
427
+ engines: { node: NODE_RANGE, pnpm: PNPM_RANGE },
426
428
  };
427
429
  // Copy the policy into the new project: it must work before the backend exists.
428
430
  const scriptsDir = resolve(targetDir, "scripts");
@@ -437,21 +439,8 @@ export function writeRootPackageJson(targetDir, dirName) {
437
439
  pkg.scripts.preinstall = "node scripts/require-supported-node.mjs";
438
440
  writeFileSync(resolve(targetDir, "package.json"), JSON.stringify(pkg, null, 2) + "\n");
439
441
 
440
- // .npmrc — keep peer-deps lenient and hoist esbuild's platform binaries so
441
- // its postinstall version check resolves the correct one across nested
442
- // dependency trees.
443
- writeFileSync(
444
- resolve(targetDir, ".npmrc"),
445
- [
446
- "engine-strict=true",
447
- "auto-install-peers=true",
448
- "strict-peer-dependencies=false",
449
- "public-hoist-pattern[]=*esbuild*",
450
- "public-hoist-pattern[]=*types*",
451
- "shell-emulator=true",
452
- "",
453
- ].join("\n"),
454
- );
442
+ // No .npmrc: pnpm >= 11 reads it only for auth and registry, so the install
443
+ // settings it used to carry live in pnpm-workspace.yaml (writePnpmWorkspace).
455
444
  }
456
445
 
457
446
  // Link an app's .env.local to the monorepo root .env.local so the root file
@@ -476,14 +465,15 @@ function linkRootEnvLocal(targetDir, appRelPath, fallbackLines) {
476
465
  }
477
466
  }
478
467
 
479
- function writePnpmWorkspace(targetDir) {
468
+ export function writePnpmWorkspace(targetDir) {
480
469
  // pnpm 11 replaced `onlyBuiltDependencies` (list) with `allowBuilds`
481
- // (map of package -> bool). apollo-cms transitively pulls multiple
482
- // esbuild versions (0.18, 0.25, 0.27); pnpm's binary symlink can pick
483
- // the wrong platform binary for esbuild's postinstall version check,
484
- // failing with "Expected X.Y.Z but got A.B.C". Allow listed packages
470
+ // (map of package -> bool); pnpm 12 still ignores the old key silently.
471
+ // apollo-cms transitively pulls multiple esbuild versions (0.18, 0.25,
472
+ // 0.27); pnpm's binary symlink can pick the wrong platform binary for
473
+ // esbuild's postinstall version check, failing with
474
+ // "Expected X.Y.Z but got A.B.C". Allow listed packages
485
475
  // to run their build/postinstall scripts; the rest are skipped
486
- // (pnpm 11 default is `strictDepBuilds: true`, empty allow-map).
476
+ // (default is `strictDepBuilds: true`, empty allow-map).
487
477
  // See https://pnpm.io/blog/releases/11.0.
488
478
  const yaml = [
489
479
  "packages:",
@@ -515,6 +505,18 @@ function writePnpmWorkspace(targetDir) {
515
505
  " 'sharp': true",
516
506
  " 'unrs-resolver': true",
517
507
  "",
508
+ "# Moved from .npmrc, which pnpm >= 11 reads only for auth/registry.",
509
+ "# Peers stay lenient; esbuild's platform binaries are hoisted so its",
510
+ "# postinstall version check resolves the right one; *types* hoisted;",
511
+ "# the engines check is enforced; scripts run in a cross-platform shell.",
512
+ "engineStrict: true",
513
+ "autoInstallPeers: true",
514
+ "strictPeerDependencies: false",
515
+ "publicHoistPattern:",
516
+ " - '*esbuild*'",
517
+ " - '*types*'",
518
+ "shellEmulator: true",
519
+ "",
518
520
  ].join("\n");
519
521
  writeFileSync(resolve(targetDir, "pnpm-workspace.yaml"), yaml);
520
522
  }
@@ -2179,7 +2181,7 @@ async function main() {
2179
2181
  warn(`Run later:\n cd ${dirName} && pnpm install`);
2180
2182
  } else if (!commandExists("pnpm")) {
2181
2183
  step(7, "Skipping dependency installation (pnpm not installed)");
2182
- warn(`Install pnpm and run:\n npm i -g pnpm && cd ${dirName} && pnpm install`);
2184
+ warn(`Install pnpm and run:\n npm i -g pnpm@${PNPM_VERSION} && cd ${dirName} && pnpm install`);
2183
2185
  } else {
2184
2186
  step(7, "Installing dependencies (pnpm)");
2185
2187
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-apollo-suite-monorepo",
3
- "version": "1.0.1469",
3
+ "version": "1.0.1470",
4
4
  "description": "Scaffold a monorepo with a frontend app and Apollo CMS as a git submodule backend (single-origin via Next.js rewrites + assetPrefix)",
5
5
  "bin": {
6
6
  "create-apollo-suite-monorepo": "index.mjs"
@@ -0,0 +1,11 @@
1
+ /**
2
+ * pnpm 12 is the package manager a scaffolded monorepo pins. The scaffold
3
+ * (index.mjs) writes it into a new project's package.json, and the backend's
4
+ * scripts/sync-root-workspace.mjs moves an existing project up to it on the
5
+ * next `pnpm backend:update`. Update the version here only.
6
+ *
7
+ * Exact, because Corepack and pnpm's own version switching need one.
8
+ */
9
+ export const PNPM_VERSION = '12.15.0';
10
+ export const PNPM_MAJOR = Number(PNPM_VERSION.split('.')[0]);
11
+ export const PNPM_RANGE = `>=${PNPM_MAJOR}`;