Skip to content

feat(css): export PostCSS config type for type-safe configs#22792

Open
linyiru wants to merge 1 commit into
vitejs:mainfrom
linyiru:feat/postcss-user-config-type
Open

feat(css): export PostCSS config type for type-safe configs#22792
linyiru wants to merge 1 commit into
vitejs:mainfrom
linyiru:feat/postcss-user-config-type

Conversation

@linyiru

@linyiru linyiru commented Jun 27, 2026

Copy link
Copy Markdown

Description

Re-exports the PostCSS user config shape as PostcssUserConfig from vite, so PostCSS configs can be typed against the same definition Vite loads them with:

import type { PostcssUserConfig } from 'vite'

const config: PostcssUserConfig = { plugins: [] }
export default config

Closes #19109 (approved by @bluwy in the issue). This continues the work of #22525, which was closed by its author; the only outstanding review feedback there (from @sapphi-red) was "We should use the types from postcss-load-config" instead of hand-writing the shape — this PR addresses exactly that.

Why it mirrors the type instead of re-exporting it

A literal re-export turned out not to be possible with the current type-bundling setup, for two compounding reasons:

  • postcss-load-config is a bundled devDependency, not a runtime dependency — so it can't be referenced as an external import('postcss-load-config') in the published .d.ts (consumers don't have it installed).
  • Its declarations use CommonJS export = syntax, which rolldown-plugin-dts cannot re-export through the bundled .d.ts. A named re-export fails codegen (Export 'PostcssUserConfig' is not defined), and resolving the type inline pulls in non-externalized postcss/lib/* subpaths and fails on their export = declarations.

So PostcssUserConfig is defined by mirroring postcss-load-config's Config using the already-public postcss types. To make sure the mirror can never silently drift, a type-level test asserts it stays structurally identical to the upstream Config:

export type cases = [ExpectTrue<Equal<PostcssUserConfig, PostcssLoadConfig>>]

This also caught a subtle bug in the previous attempt: it used PostCSS.TransformCallback where Config actually uses Transformer (which additionally requires postcssPlugin/postcssVersion).

Tests

  • packages/vite/src/node/__tests_dts__/postcss.ts — a type-only test that (1) locks PostcssUserConfig to postcss-load-config's Config via Equal, and (2) checks both the array and object plugin formats are accepted and an invalid value is rejected. It runs as part of pnpm typecheck (tsc -p src/node/__tests_dts__).
  • Verified locally: pnpm typecheck, pnpm build-types (roll + check), eslint, and oxfmt --check all pass.

Notes for reviewers

  • The mirror + Equal lock is the approach I landed on given the export = / bundled-dep constraints above. If you'd prefer a literal reference (e.g. by also externalizing postcss subpaths in rolldown.dts.config.ts, which leaks import ... from "postcss/lib/processor" into the public .d.ts), happy to switch — let me know.
  • No docs change included: the type carries inline JSDoc with a usage example. Glad to add a docs note if you'd like one.

@linyiru linyiru marked this pull request as draft June 27, 2026 20:29
@linyiru linyiru force-pushed the feat/postcss-user-config-type branch 2 times, most recently from 1cdd72d to f3fc791 Compare June 27, 2026 20:41
Re-exports the PostCSS user config shape as `PostcssUserConfig` from
`vite`, so PostCSS configs can be typed against the same definition Vite
loads them with:

```ts
import type { PostcssUserConfig } from 'vite'

const config: PostcssUserConfig = { plugins: [] }
export default config
```

The type mirrors `postcss-load-config`'s `Config`. `postcss-load-config`
is bundled into Vite and its declarations use CommonJS `export =` syntax,
which `rolldown-plugin-dts` cannot re-export through the bundled `.d.ts`,
so the shape is mirrored from `postcss` types instead. A type-level test
asserts the mirror stays structurally identical to the upstream `Config`,
so it cannot silently drift.

Closes vitejs#19109
@linyiru linyiru force-pushed the feat/postcss-user-config-type branch from f3fc791 to ec6bbc4 Compare June 27, 2026 20:48
@linyiru linyiru marked this pull request as ready for review June 27, 2026 20:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Re-export PostCSS config type from postcss-load-config

1 participant