CodeVetter · Repo Unpack · Contributor handoff
vuejs/core
Read the contributing guide's Project Structure and Package Dependencies sections before touching anything — the import rules there are enforced by both eslint and the release process. Expect ES2016-target lint restrictions that will reject idiomatic modern TypeScript, and expect every dev-only behaviour to be guarded by a `__DEV__` flag that must tree-shake cleanly. The fastest verification loop is `pnpm test-unit <package>`; the slowest and most CI-relevant are `pnpm check`, `pnpm test-dts` and `node scripts/verify-treeshaking.js`. Never reach across packages with relative paths, and never add a runtime import to a compiler package.
- Read first, in order: `.github/contributing.md` (scripts + project structure), `package.json` (the script surface), `vitest.config.ts` (which project your test will land in), and `scripts/aliases.js` (how `@vue/*` resolves in tests and builds).
- The eslint config bans object rest/spread, `await`, optional chaining and `const enum` repo-wide with explicit rationale messages (ES2016 output target, esbuild helper bloat, enum inlining); use `extend` from `@vue/shared` instead of object spread.
- `no-restricted-globals` is scoped by directory: DOM globals are banned everywhere except `packages/{vue,vue-compat,runtime-dom}` and shared; Node globals are banned in DOM packages; `import-x/no-nodejs-modules` allows bare (non-`node:`) builtins only under `packages/compiler-sfc/src/**`.
- Safe edit boundary: a change confined to one package's `src` plus its `__tests__` is verifiable with `pnpm test-unit <pkg>`; anything touching `renderer.ts`, `component.ts`, `scheduler.ts` or `vnode.ts` needs the full `pnpm test-unit` plus `pnpm test-e2e` because runtime-test, SSR and hydration all ride on them. (inferred)
- Trap: any new public export must also be re-exported at the package index — direct relative imports across package boundaries are forbidden, and a non-type import from package B requires B to be listed in A's package.json dependencies because the packages are externalised in ESM/CJS builds.
- Trap: commit messages are validated by a regex in `scripts/verify-commit.js` limited to a fixed type list with a ≤50-character subject; a non-conforming message fails the commit-msg hook outright.
- Trap: the pre-commit hook runs `pnpm lint-staged && pnpm check`, so a full `tsc --incremental --noEmit` over the whole repo runs on every commit — type errors in unrelated packages will block an otherwise-clean change.
- Trap: `tsconfig.json` sets `isolatedDeclarations: true`, which means exported functions and consts need explicit return/value type annotations — this is why the codebase writes `export const version: string = __VERSION__` and `export function initDev(): void`.
- Convention: dev-only code goes inside `if (__DEV__)` or `__DEV__ && ...` rather than behind a runtime boolean, and new warnings should be asserted in tests with the custom `toHaveBeenWarned` matchers.
- Convention: compile-time optional features must be wrapped in the corresponding flag — `__FEATURE_OPTIONS_API__` for `app.mixin` and `applyOptions`, `__FEATURE_SUSPENSE__` for Suspense dispatch, `__COMPAT__` for Vue-2 behaviour — or the feature will not tree-shake and `verify-treeshaking.js` may fail.
- Tests to run before opening a PR, mirroring CI exactly: `pnpm run test-unit`, `pnpm run test-e2e`, `pnpm run lint`, `pnpm run format-check`, `pnpm run check`, `pnpm run test-dts`.
- To iterate on compiler output interactively use `nr dev-compiler` (template-explorer at `localhost:3000/packages-private/template-explorer/local.html`, opened by `nr open`); for full SFC behaviour use `nr dev-sfc`, which runs `pre-dev-sfc.js` and falls back to `build-all-cjs`.
- Never hand-edit `dist/` or generated `.d.ts` files: dist is rebuilt by `scripts/build.js` (which rm -rf's it for full builds) and declarations are regenerated by `build-dts`; `.gitignore` and the eslint `ignores` block both exclude `**/dist/` and `**/temp/`.
- Versions across all packages are lockstepped at the root version (3.5.43) and rewritten by `scripts/release.js`, which reads and patches each package.json — do not bump a package version by hand.