[READ-ONLY] Mirror of https://github.com/lukebennett88/luke-ui. ui.lukebennett.dev
luke-ui docs DEPENDENCIES.md
7.1 kB

Dependencies #

This guide explains where dependency versions live, and the workspace rules Renovate has to respect.

Where versions live #

Almost every version lives in the catalog: block of pnpm-workspace.yaml. Package manifests say catalog: and follow it. catalogMode: prefer keeps new dependencies pointing at the catalog. Renovate updates the catalog entry, so a shared dependency moves once rather than once per package.

Two entries are not plain versions:

  • vite is an alias for @voidzero-dev/vite-plus-core, pinned to the same version as vite-plus. overrides forces one copy of vite and vitest across the workspace, so they only resolve if they move together. Renovate groups them.
  • playwright is *. Renovate cannot upgrade a wildcard and skips it. The version is decided by the browser install step in CI.

The release quarantine #

minimumReleaseAge: 4320 is exactly three days. It stops pnpm resolving any release, direct or transitive, that is younger than three days. .github/renovate.json5 sets minimumReleaseAge: '3 days', so Renovate and pnpm use the same three-day quarantine.

The two settings do not cover the same ground. Renovate's applies to the dependency it is updating. pnpm's applies to everything the update pulls in. A bump to a three-day-old release can still drag in a transitive package published yesterday, and the lockfile update then fails.

trustLockfile: true means the check is not re-run against entries already in the lockfile, so this only bites when a lockfile is generated, never on a plain pnpm install --frozen-lockfile in CI.

The exclude lists #

minimumReleaseAgeExclude and trustPolicyExclude stay hand maintained. Renovate has no manager for these keys. Catalog entries are the only part of pnpm-workspace.yaml it reads and writes. It cannot add an entry, and it cannot prune one.

This is the intended release valve. When a pull request fails to install because a version is too young or trips trustPolicy: no-downgrade, add the exact version to the matching list.

Stale entries are inert rather than wrong. Each entry names an exact version, so once that version is older than the quarantine the exemption grants nothing. Pruning is optional housekeeping: delete an entry, run pnpm install, and keep the deletion if the install succeeds.

peerDependencyRules, overrides, and allowBuilds are hand maintained for the same reason. An update can make an entry unnecessary or wrong, and only a maintainer reading the failure will notice.

Runtime dependencies #

Every consumer installs the dependencies of @luke-ui/react. Declare a package there only when the published JavaScript or declarations import it. Keep build-time packages in devDependencies. The packed-consumer harness in TESTING.md fails on an undeclared import or an unused dependency.

Prefer declaring a dependency to bundling it. Bundle one only for a concrete reason, such as published code that needs a small part of a package whose install would cost consumers far more than that part. To bundle a dependency, list it in devDependencies and in deps.onlyBundle in packages/@luke-ui/react/vite.config.ts. The build fails when it bundles a package that deps.onlyBundle does not list. It records each bundled version in inlinedDependencies in package.json.

Changesets #

@luke-ui/react is unpublished at version 0.0.0. @luke-ui/rainbow-sprinkles is a publishable 0.x support package used by @luke-ui/react at runtime. It is not part of the stable Luke UI 1.x consumer API. Publish it with React whenever React depends on a Rainbow version that is not yet on the registry. apps/docs and @luke-ui/playground-core are private. Before 1.0.0 no pull request needs a changeset, including one that moves a runtime or peer dependency.

The needs-changeset label in .github/renovate.json5 is advance notice. It marks packages that will be runtime, peer, or bundled dependencies of the published package at 1.0.0. Re-sync that list against dependencies, peerDependencies, and inlinedDependencies in packages/@luke-ui/react/package.json at 1.0.0.

react and react-dom use rangeStrategy: 'replace' rather than bump, so the catalog range only widens when the caret stops covering the new version. The catalog range is what gets published as the peer range, and bumping it on every minor would narrow what consumers can satisfy.

Grouping and schedule #

Renovate runs weekly before 6am on Monday. It groups non-major updates by release train and splits major updates into separate pull requests.

lockFileMaintenance runs on the first of the month and refreshes transitive versions, which nothing else moves.

Automerge #

Only type definitions automerges: non-major @types/* updates, excluding @types/react and @types/react-dom, which have to land with the react major they describe. Type packages ship nothing to consumers, and a bad bump fails check:types.

Everything else is merged by hand. Two reasons. Visual regression gates on a manual approval environment, so a change to rendered output should be looked at. And a share of pull requests need an exclude list entry before they will install, which no amount of green CI will produce.

Tooling versions #

The root package.json packageManager field pins the exact pnpm version. Omitting the hash avoids Renovate's Corepack-based hash regeneration.

The root devEngines.runtime field pins the project Node runtime, and onFail: 'download' makes pnpm provision it. pnpm resolves the 24.x range to an exact version and records it in the lockfile, with a download and integrity hash for each platform.

GitHub Actions sets up tooling with pnpm/setup. It installs the pnpm version from packageManager and the Node runtime from devEngines.runtime.

A local developer bootstraps by installing pnpm itself. pnpm install then downloads the declared Node runtime and links it as node_modules/.bin/node, so pnpm exec node and pnpm scripts run it. Bare node is project-aware only when pnpm's global Node shim is the node found first on PATH.

Cloudflare Pages keeps its host-level NODE_VERSION=24 setting on the Pages project. Its build image does not document devEngines.runtime as a Node version selector.

Renovate has no manager for devEngines.runtime, so .github/renovate.json5 adds a custom.regex manager for it. The regex captures only the major before .x, so an update PR rewrites 24.x to the next <major>.x. Renovate follows Node's release schedule and only proposes stable LTS lines.

@types/node tracks that Node major. Renovate's allowedVersions: '<25' blocks newer majors, and an overrides entry forces every copy onto the catalog so optional peers cannot drift. When the Node major PR lands, update allowedVersions and the catalog entry in the same change.

The workflows in .github/workflows pin actions at the major tag, so the only update Renovate can offer is a major tag move. They group into one github actions pull request and are never automerged.