Portfolio Manifest — Prepared 2026-08-20
Full-Stack Node.js/Vue Engineer
An independently maintained port of Directus's own monorepo — a real-time API/App dashboard for managing SQL database content — migrated from pnpm to Yarn and rebuilt one package at a time . All 40 workspace manifests are done; real source is genuinely early, three packages in, but every migration decision along the way has been verified against a real install or a real compiler run, and every gap found — five fixed, one tracked openly — is disclosed in this repo's own build log, not smoothed over.
A real package-manager migration, verified rather than trusted
Moving a large monorepo off
pnpm
is a genuinely common, genuinely underrated engineering task — the kind of work that shows up in real migrations
far more often than greenfield builds do. Directus's own monorepo (40 workspace packages, a 331-entry shared
version catalog, 17 CI workflows, two Dockerfiles) made a useful subject precisely because pnpm has mechanisms
Yarn has no exact equivalent for: each one needed a real decision, tested against a real install, not a
find-and-replace. Two of those first-pass decisions turned out to be wrong and got corrected properly rather than
left standing.
All 40 package.json files done · directus/ source complete, not yet runnable · types/ complete (56/56) · schema/ started (3/16)
Migration order is deliberate: every workspace's
package.json
was individually inspected and transformed before any real source landed —
yarn install
has resolved the complete dependency graph since that phase finished. Real source is additive from there.
directus/
(the CLI wrapper, 6 files) has a complete source tree, though not yet a runnable one —
cli.js
imports two still-manifest-only packages (
@directus/update-check
,
@directus/api/cli/run.js
), the same "manifests first" gap
packages/types
already discloses for itself;
packages/types
is now complete — 56 of 56 planned files, added one file per commit, each one diffed byte-for-byte against
Directus's real upstream source before landing, not reconstructed from memory — though it doesn't fully type-check
yet: cross-package dependencies on
@directus/constants
and
@directus/schema
touch several files each, plus one more on
@directus/ai
.
packages/schema
is newly started (3 of 16 files), directly chipping away at two of those gaps. The other 37 packages,
sdk
,
api
, and
app
are still manifests waiting on their source trees; see
todo.md
for the honest current state rather than assuming more is done.
Every ported file gets a real
diff -u
against upstream before it's committed. Every import is checked against what's actually landed in the fork,
not what's expected to be there. The
isolated-vm
fix below was confirmed by reading real
g++
compiler output, not by guessing at a Node compatibility table.
A permissive
enableScripts: true
default (Yarn has no scoped install-script allowlist like pnpm's) and a Docker build-cache regression (no
equivalent to
pnpm fetch
's layer-caching trick) are both accepted trade-offs — written down as real regressions in
todo.md
, not silently absorbed.
Found by verifying against a real install or a real compiler run, not by assuming the first pass was right
Two turned up in this fork's own first-pass migration work and got corrected before anything was left standing on a wrong assumption. Two turned up in Directus's own upstream source or its published tooling — genuine gaps in a widely-used project, not typos. One turned up in a VS Code extension's own stale bundled data, misdiagnosing this repo's real config as broken.
gh run view --log-failed
) showed the native addon calling V8 APIs Node 26's bundled V8 has since removed or changed —
Template::SetAccessor
,
GetPrototype
, internal-field accessor signatures. Every
other
native module in the ~2,150-package graph built cleanly, ruling out a missing-toolchain theory first. Fixed
by bumping to
7.0.1
, verified with a real
yarn install
.
yarn config -v
's full settings dump (not
yarn help
, which doesn't mention it) surfaced real
catalog
/
catalogs
config keys. Verified in a throwaway scratch project before touching this repo. Fixed properly, not just
reverted: a 326-entry catalog rebuilt from the original 331 (5 confirmed-dead entries dropped), and 671 of
673 literal-pin conversions restored to
catalog:
across 40 files, each diff reviewed before committing.
deploy --legacy --prod
has no Yarn equivalent; the first replacement script pruned this repo's own root
node_modules
in place — a real regression from pnpm's separately-built deploy output. Reconsidered:
yarn workspaces focus --production
only needs
a
checkout at the right commit, not the live working tree, so the script now runs inside a disposable
git worktree
instead. Verified end-to-end — a working
dist/
with 724
node_modules
entries came out the other side.
@directus/tsconfig
npm package (v4.0.0): with
outDir
set but no explicit
rootDir
, TypeScript falls back to inferring it from the "common source directory" of the include set. Real
tsc
5.9.3 builds identically either way — confirmed by running it directly and diffing the output before and
after — but newer/preview TS tooling errors on the implicit inference. Fixed with an explicit
"rootDir": "./src"
in
packages/types/tsconfig.json
, the same value already being inferred.
typescript-config/is-valid
hint flagged
packages/types/tsconfig.json
's inherited
lib: ["ES2023"]
as invalid. It isn't — TypeScript 5.9.3 (the version actually installed) has supported
ES2023
as a
lib
value since 5.2; the hint's bundled schema is just out of date. Confirmed against the real installed
TypeScript version before suppressing, and scoped the suppression to that one hint only rather than
disabling Webhint's defaults wholesale.
release-notes-generator
's
package.json
no longer lists
@pnpm/workspace.find-packages
,
@pnpm/workspace.pkgs-graph
, or
@pnpm/logger
— but the actual source file that imports them,
src/utils/process-packages.ts
, hasn't been rewritten yet. Caught and tracked rather than assumed fixed just because the manifest looked clean.
Planned replacement: read each workspace's
package.json
directly and build the dependency graph from
workspace:*
references — no package-manager-specific API needed at all.
todo.md, architect.md, the profile README, the portfolio site, and the wiki — checked, not assumed in sync
Progress claims that live in more than one place drift, quietly, unless someone actually checks. A full sweep of
every surface that cross-references this repo's status — done after the twelfth file landed in
packages/types
— found three wiki pages still claiming only one workspace package had real source, stale since the first file
after
directus/
landed. Fixed the same day, verified live afterward rather than assumed fixed on commit.
Every file added to
packages/types
gets its own commit, followed by a second commit updating
todo.md
and
architect.md
's file counts — not batched at the end of a session where drift is easy to lose track of.
The wiki , scrum board , and the family profile/portfolio pages carry coarser claims — swept periodically instead, since updating them per-file would be noise for a five-page wiki tracking a 54-file package.
Where the real trade-offs got made, and written down
Not every pnpm mechanism has a clean Yarn replacement, and pretending otherwise would just move the gap somewhere
less visible.
onlyBuiltDependencies
— pnpm's default-deny list for which packages may run install/postinstall scripts — has no Yarn Berry equivalent;
enableScripts: true
is Yarn's permissive default, and that's a real security-posture downgrade, accepted and documented rather than
quietly inherited. Similarly,
pnpm fetch
's layer-caching trick (populate the store from just the lockfile before copying in source) has no equivalent
under Yarn workspaces, since every workspace's
package.json
needs to be present to resolve at all — so both Dockerfiles now do one
COPY . .
then
yarn install
, meaning any source change invalidates the install layer too. Both trade-offs are recorded in
todo.md
as accepted regressions, not oversights discovered later.