Files
apf_portal/package.json
T
julien bba1703622
CI / check (push) Successful in 3m15s
CI / commits (push) Has been skipped
CI / scan (push) Successful in 1m25s
CI / a11y (push) Successful in 2m31s
Docs site / build (push) Successful in 4m2s
CI / perf (push) Successful in 5m0s
fix(deps): scope the vite < 7 override to vitepress so @angular/build keeps vite 8 (#163)
## Summary

Hotfix on the override added in [#161](#161). The unconditional `"vite": ">=6.4.2 <7"` was too broad — it downgraded **every** vite consumer in the workspace to vite 6.4.2, including `@angular/build@21.2.11`. Angular's dev-server plugin (`angular-memory-plugin.js > loadViteClientCode`) monkey-patches Vite's client error-overlay code; the patch targets vite 8.x's internal layout, fails against vite 6, and the home page blank-screens with:

```
[vite] Internal server error: Failed to update Vite client error overlay text.
  at loadViteClientCode (angular-memory-plugin.js:140:31)
```

…on the very first request to `pnpm nx serve portal-shell`.

## Fix

One-line change in [`package.json`](package.json) → `pnpm.overrides`:

```diff
- "vite":          ">=6.4.2 <7",
+ "vitepress>vite": ">=6.4.2 <7",
```

pnpm's `parent>child` selector syntax scopes the override to vitepress's transitive resolution only. Other vite consumers (Angular, Nx, Vitest, the analog plugin) follow their own peer constraints and resolve to vite 8.0.13 again.

## Resolution after the fix

| Consumer | vite version | Why |
| --- | --- | --- |
| `vitepress 1.6.4` | **6.4.2** | Override target — keeps VitePress 1.x off rolldown-vite |
| `@angular/build 21.2.11` | **8.0.13** | Restored; its dev-server plugin needs vite 8's client layout |
| `@nx/vite`, `@analogjs/vite-plugin-angular`, Vitest | **8.0.13** | Restored |
| `@vitejs/plugin-basic-ssl` (analog transitive) | 7.3.2 | Its own peer range; HTTPS-cert helper only, not the dev-server host. Doesn't affect us. |

## Why this regression didn't surface in #161's CI

The `docs-site.yml` workflow and `pnpm exec nx run-many -t lint test build` exercise the **production build** paths. Vite 6 ↔ Angular-build 21.2's monkey-patch incompatibility is a **dev-server-only** failure (the prod Rollup pipeline doesn't go through `loadViteClientCode`). CI couldn't have caught it; manual `nx serve portal-shell` is the only repro path. Lesson logged.

## Test plan

- [x] `pnpm install` — clean. Lockfile diff confirms: vite 6.4.2 only under vitepress, vite 8.0.13 restored everywhere else.
- [x] `pnpm audit --audit-level=moderate` — no known vulnerabilities.
- [x] `pnpm docs:build` — ~9.5 s, Mermaid still renders in ADR-0009's HTML (regression fence passes).
- [x] `pnpm exec nx run-many -t lint test build --projects=portal-shell,portal-admin,portal-bff,shared-ui,shared-state,feature-auth` — green.
- [x] **`pnpm nx serve portal-shell`** — boots cleanly, `curl http://localhost:4200/` returns HTTP 200 with the SPA shell, no `loadViteClientCode` error in the dev log. (This is the path that broke.)
- [ ] **Manual smoke (the user's repro)** — `pnpm nx serve portal-shell`, open the home page in a browser, confirm:
  - No "Failed to update Vite client error overlay text" in the browser DevTools console.
  - Page renders; navigating to `/accessibility`, `/profile` works.
  - Theme switcher in the footer toggles light / dark / system; locale switcher likewise.

## Notes for the reviewer

- **Lesson on override scoping**: the version-selector form (`"package@<vuln-range>": "patched"`) is the safest default — it only kicks in for the vulnerable range. The unconditional form (`"package": "<range>"`) is a sledgehammer and should be reserved for cases where the version-selector form genuinely can't express the intent (as was the case in #161 where the resolved version was already past the vulnerable range, so the selector was a no-op). When the unconditional form is needed, **always scope to a parent** (`"parent>package": …`) to avoid the workspace-wide blast radius.
- **No documentation change in this PR**: development.md's "Transitive vulnerabilities — `pnpm.overrides`" subsection (from #160) is still accurate. A follow-up edit could add a "scope to a parent when possible" sentence; not blocking.

---------

Co-authored-by: Julien Gautier <julien.gautier@apf.asso.fr>
Reviewed-on: #163
2026-05-16 02:07:43 +02:00

185 lines
5.9 KiB
JSON

{
"name": "apf-portal",
"version": "0.0.0",
"license": "MIT",
"packageManager": "pnpm@10.33.4",
"scripts": {
"prepare": "husky",
"ci:check": "pnpm exec nx affected -t format:check lint test build",
"ci:audit": "pnpm audit --audit-level=moderate",
"ci:commits": "pnpm exec commitlint --from ${COMMIT_LINT_FROM:-origin/main} --to HEAD --verbose",
"ci:gzip-budgets": "node scripts/check-gzip-budgets.mjs",
"ci:perf": "pnpm exec nx build portal-shell --configuration=production && pnpm ci:gzip-budgets && pnpm exec lhci autorun --config=./lighthouserc.js",
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
},
"private": true,
"lint-staged": {
"!(pnpm-lock).{ts,tsx,js,jsx,html,scss,css,md,json,yml,yaml}": [
"prettier --write"
]
},
"pnpm": {
"onlyBuiltDependencies": [
"@nestjs/core",
"@parcel/watcher",
"@prisma/client",
"@prisma/engines",
"@swc/core",
"esbuild",
"less",
"lmdb",
"msgpackr-extract",
"nx",
"prisma",
"unrs-resolver"
],
"overrides": {
"axios@<1.15.2": ">=1.15.2",
"@angular-devkit/core>ajv@<8.18.0": ">=8.18.0",
"brace-expansion@<5.0.5": ">=5.0.5",
"esbuild@<0.25.0": ">=0.25.0",
"follow-redirects@<1.16.0": ">=1.16.0",
"ip-address@<10.1.1": ">=10.1.1",
"protobufjs@<8.0.2": ">=8.0.2",
"tmp@<0.2.4": ">=0.2.4",
"vitepress>vite": ">=6.4.2 <7",
"yaml@<2.8.3": ">=2.8.3",
"@types/express": "^5.0.6"
}
},
"prisma": {
"schema": "apps/portal-bff/prisma/schema.prisma"
},
"devDependencies": {
"@analogjs/vite-plugin-angular": "~2.5.0",
"@analogjs/vitest-angular": "~2.5.0",
"@angular-devkit/core": "~21.2.0",
"@angular-devkit/schematics": "~21.2.0",
"@angular/build": "~21.2.0",
"@angular/cli": "~21.2.0",
"@angular/compiler-cli": "~21.2.0",
"@angular/language-service": "~21.2.0",
"@braintree/sanitize-url": "^7.1.2",
"@commitlint/cli": "^20.5.3",
"@commitlint/config-conventional": "^20.5.3",
"@eslint/js": "^9.8.0",
"@lhci/cli": "^0.15.1",
"@nestjs/schematics": "^11.0.0",
"@nestjs/testing": "^11.0.0",
"@nx/angular": "^22.7.1",
"@nx/devkit": "22.7.1",
"@nx/eslint": "^22.7.1",
"@nx/eslint-plugin": "22.7.1",
"@nx/jest": "22.7.1",
"@nx/js": "22.7.1",
"@nx/nest": "^22.7.1",
"@nx/node": "22.7.1",
"@nx/playwright": "22.7.1",
"@nx/vite": "^22.7.1",
"@nx/vitest": "22.7.1",
"@nx/web": "22.7.1",
"@nx/webpack": "22.7.1",
"@oxc-project/runtime": "^0.129.0",
"@playwright/test": "^1.36.0",
"@schematics/angular": "~21.2.0",
"@swc-node/register": "1.11.1",
"@swc/core": "1.15.33",
"@swc/helpers": "0.5.21",
"@tailwindcss/postcss": "^4.2.4",
"@types/cookie-parser": "^1.4.10",
"@types/express": "^5.0.6",
"@types/express-session": "^1.19.0",
"@types/jest": "^30.0.0",
"@types/node": "24.12.4",
"@typescript-eslint/utils": "^8.40.0",
"@vitest/coverage-v8": "~4.1.0",
"@vitest/ui": "~4.1.0",
"angular-eslint": "^21.2.0",
"cytoscape": "^3.33.3",
"cytoscape-cose-bilkent": "^4.1.0",
"dayjs": "^1.11.20",
"debug": "^4.4.3",
"eslint": "^9.8.0",
"eslint-config-prettier": "^10.0.0",
"eslint-plugin-playwright": "^1.6.2",
"husky": "^9.1.7",
"jest": "^30.0.2",
"jest-environment-node": "^30.0.2",
"jest-util": "^30.0.2",
"jsdom": "^29.0.0",
"jsonc-eslint-parser": "^2.1.0",
"lint-staged": "^17.0.0",
"mermaid": "^11.15.0",
"nx": "22.7.1",
"pino-pretty": "^13.1.3",
"postcss": "^8.5.12",
"prettier": "^3.8.1",
"prisma": "^6.19.3",
"tailwindcss": "^4.2.4",
"ts-jest": "^29.4.0",
"ts-node": "10.9.2",
"tslib": "^2.3.0",
"typescript": "~5.9.2",
"typescript-eslint": "^8.40.0",
"vite": "^8.0.0",
"vitepress": "^1.6.4",
"vitepress-plugin-mermaid": "^2.0.17",
"vitest": "^4.0.8",
"webpack-cli": "^5.1.4"
},
"dependencies": {
"@angular/cdk": "~21.2.10",
"@angular/common": "~21.2.0",
"@angular/compiler": "~21.2.0",
"@angular/core": "~21.2.0",
"@angular/forms": "~21.2.0",
"@angular/localize": "~21.2.12",
"@angular/platform-browser": "~21.2.0",
"@angular/router": "~21.2.0",
"@azure/msal-node": "^5.2.1",
"@nestjs/common": "^11.0.0",
"@nestjs/core": "^11.0.0",
"@nestjs/platform-express": "^11.0.0",
"@nestjs/swagger": "^11.4.3",
"@opentelemetry/api": "^1.9.1",
"@opentelemetry/exporter-trace-otlp-http": "^0.217.0",
"@opentelemetry/exporter-trace-otlp-proto": "^0.217.0",
"@opentelemetry/instrumentation": "^0.217.0",
"@opentelemetry/instrumentation-document-load": "^0.62.0",
"@opentelemetry/instrumentation-express": "^0.65.0",
"@opentelemetry/instrumentation-fetch": "^0.217.0",
"@opentelemetry/instrumentation-http": "^0.217.0",
"@opentelemetry/instrumentation-ioredis": "^0.65.0",
"@opentelemetry/instrumentation-nestjs-core": "^0.63.0",
"@opentelemetry/instrumentation-pg": "^0.69.0",
"@opentelemetry/instrumentation-pino": "^0.63.0",
"@opentelemetry/instrumentation-user-interaction": "^0.61.0",
"@opentelemetry/resources": "^2.7.1",
"@opentelemetry/sdk-node": "^0.217.0",
"@opentelemetry/sdk-trace-web": "^2.7.1",
"@opentelemetry/semantic-conventions": "^1.40.0",
"@prisma/client": "^6.19.3",
"@scalar/nestjs-api-reference": "^1.1.14",
"axios": "^1.6.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.15.1",
"connect-redis": "^9.0.0",
"cookie-parser": "^1.4.7",
"express-rate-limit": "^8.5.1",
"express-session": "^1.19.0",
"helmet": "^8.1.0",
"ioredis": "^5.10.1",
"jose": "^6.2.3",
"lucide-angular": "^1.0.0",
"nestjs-cls": "^6.2.0",
"nestjs-pino": "^4.6.1",
"nestjs-prisma": "^0.27.0",
"pino": "^10.3.1",
"pino-http": "^11.0.0",
"reflect-metadata": "^0.2.0",
"rxjs": "~7.8.0"
}
}