Skip to content

fix: build and typecheck with postcss 8.5 - #1516

Merged
Anber merged 4 commits into
callstack:masterfrom
Anber:fix/postcss-8-5-types
Oct 19, 2026
Merged

Anber merged 4 commits into
callstack:masterfrom
Anber:fix/postcss-8-5-types

Conversation

@Anber

@Anber Anber commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator

Motivation

The dependabot pull request #1504 raises postcss from 8.4.31 to 8.5.23 in @linaria/atomic, @linaria/postcss-linaria and @linaria/server, and the build fails on it. postcss 8.5 changed three declarations that the sources relied on, and typechecking the three packages against 8.5.23 on master reports these errors:

This pull request fixes those errors in the sources so that #1504 can be rebased and merged. The package manifests keep ^8.4.31; the bump itself stays in #1504.

Summary

The change touches two source files. No package.json, lockfile, snapshot or test file is edited.

  • packages/server/src/collect.ts: handleAtRule reads the nodes of the cloned at-rules through optional chaining: nodes?.[i]?.remove() and nodes?.length. handleAtRule is only called with the parent of a walked rule, which always has nodes, so the undefined branch is unreachable and the output does not change.
  • packages/postcss-linaria/src/stringify.ts: the raw and rawValue overrides keep their string signatures and return super.raw(...) as string and super.rawValue(...) as string, with a comment saying why. The inherited result is returned unchanged.

Why an assertion and not a guard in stringify.ts:

  • The value is not always a string. The inherited body reads the boolean semicolon raw through the override, so converting with String(...) turns false into the truthy 'false'. I tried it on postcss 8.4.31 and 3 of the 100 @linaria/postcss-linaria tests failed.
  • Widening the override to boolean | string breaks the class's own callers, which pass the result on as string (TS2345 and TS2322 at several call sites in the same file).

The class is not exported, and the assertions are erased at compile time.

Published output: with the committed lockfile (postcss 8.4.31), the emitted declarations of @linaria/server, @linaria/postcss-linaria and @linaria/atomic are identical to master, so I did not add a changeset. The emitted JavaScript differs only by the null checks in collect.ts and by comments in stringify.ts.

The first commit adds scripts/typecheck-postcss-8-5.sh. It is separate from the fix and can be dropped. It swaps in the manifests and lockfile of the postcss 8.5.23 update from the head of #1504, installs with --ignore-scripts, typechecks the three packages and puts the committed files back on exit. It needs the head commit of #1504 to be fetched in the clone and stops with a clear message otherwise. On the master sources it fails with the errors listed above, and with this fix it passes. If it is interrupted during its own install, a plain pnpm install --frozen-lockfile puts node_modules back. It stops being useful once postcss 8.5.23 is in the committed lockfile.

Test plan

I ran these on the committed lockfile (postcss 8.4.31) and again with the manifests and lockfile of #1504 applied temporarily (postcss 8.5.23, not committed). Both installs used --ignore-scripts, with pnpm 9.15.9 and Node 24.4.1.

pnpm exec turbo run build --force
pnpm exec turbo run typecheck --force
pnpm --filter ./packages/postcss-linaria test
pnpm --filter ./packages/testkit test -- --testTimeout=60000 --ci
pnpm lint

On both versions:

  • the build is 16 of 16 tasks and the typecheck is 19 of 19, with no error TS;
  • @linaria/postcss-linaria passes 5 suites and 100 tests;
  • testkit, which exercises @linaria/atomic, passes 150 tests with 2 skipped and 279 snapshots;
  • lint is clean.

@linaria/server is the part these runs do not cover. It has no test script, so pnpm turbo run test in CI does not run it, and its jest suite already fails on master, independent of postcss: prettier.format returns a Promise under prettier 3, so 16 of the 20 tests compare Promise {} with the snapshot strings. I left that suite alone, because repairing it edits existing test lines. Instead I compared its output: a copy of collect.test.ts that awaits prettier.format writes 16 fresh snapshots, and they are byte-identical between master and this branch on postcss 8.4.31, between master and this branch on postcss 8.5.23, and between this branch on the two versions. Nothing else about @linaria/server on 8.5.23 was run.

Anber added 4 commits October 16, 2026 11:45
The committed lockfile resolves postcss to 8.4.31, so the typings of 8.5
are never checked. The script swaps in the manifests and lockfile of the
postcss 8.5.23 update, runs typecheck for @linaria/server,
@linaria/postcss-linaria and @linaria/atomic, and puts everything back.

It fails today: TS18048 for the unguarded AtRule nodes in
packages/server/src/collect.ts and TS2322 for the raw and rawValue
returns in packages/postcss-linaria/src/stringify.ts.
postcss 8.5 types `AtRule#nodes` as possibly undefined, so the typecheck
of @linaria/server fails against it. `handleAtRule` only receives the
parents of rules, which always have nodes, so reading them through
optional chaining keeps the output unchanged on postcss 8.4 and 8.5.
postcss 8.5 widens the declared results of `Stringifier#raw` to
`boolean | string` and of `Stringifier#rawValue` to `number | string`,
while 8.4 declares `string` for both. The overrides return the base
result unchanged and keep their `string` signatures, which the raws and
fields the stringifier reads through them satisfy, so they compile
against both versions without a runtime change.
`Stringifier#raw` does return a boolean at runtime: the inherited `body`
reads the `semicolon` raw through it. The comments claimed that every raw
read through the override is a string. Say instead that `string` is the
declared signature the calls in this class rely on, and that the base
result is returned unchanged. Comment-only, no code change.
@changeset-bot

changeset-bot Bot commented Oct 18, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: ba6962c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@Anber
Anber merged commit 829e01c into callstack:master Oct 19, 2026
4 checks passed
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.

1 participant