Skip to content

Commit 52b0786

Browse files
committed
chore(release): prepare Linaria 8 for WyW 2
1 parent 3ddf4ed commit 52b0786

32 files changed

Lines changed: 405 additions & 339 deletions

File tree

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
---
2-
"@linaria/atomic": patch
3-
"@linaria/core": patch
4-
"@linaria/react": patch
5-
"@linaria/stylelint": patch
2+
"@linaria/atomic": major
3+
"@linaria/core": major
4+
"@linaria/babel-plugin-interop": major
5+
"linaria": major
6+
"@linaria/postcss-linaria": major
7+
"@linaria/react": major
8+
"@linaria/server": major
9+
"@linaria/stylelint-config-standard-linaria": major
10+
"@linaria/stylelint": major
611
---
712

8-
Migrate WyW dependencies to 2.0.0-alpha.1 and expose processor static evaluation semantics for the new evaluator architecture.
13+
Release Linaria 8 with WyW 2.0.0 stable dependencies and Node.js 22+ support.
14+
15+
Linaria processors now expose WyW 2 static evaluation semantics, allowing the default `eval.strategy: "hybrid"` mode to resolve statically provable values before falling back to the evaluator. This keeps existing dynamic/runtime-only interpolation support while reducing evaluator work for values that can be resolved from static bindings and imports.
16+
17+
Migration notes:
18+
19+
- Node.js 22 or newer is required.
20+
- Top-level `evaluate` config should be migrated to `eval.strategy`. Use `execute` for evaluator-only compatibility, keep the default `hybrid` for static-first resolution with fallback, or use `static` to reject evaluator fallback.
21+
- CSS rule emission order may change for cascade ties with identical specificity because WyW 2 uses the Oxc/static-first pipeline and can preserve/process imports differently. Make precedence explicit with selector specificity, composition, or source structure where order matters.

.github/workflows/check.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ jobs:
1818
fail-fast: false
1919
matrix:
2020
os: [ubuntu-latest]
21-
node-version: [20.x, 22.x]
21+
node-version: [22.x, 24.x]
2222
include:
2323
- os: windows-latest
24-
node-version: 20.x
24+
node-version: 22.x
2525

2626
steps:
2727
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
@@ -51,10 +51,10 @@ jobs:
5151
- name: Install and prepare
5252
run: pnpm install --frozen-lockfile --strict-peer-dependencies
5353
- name: ESLint
54-
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '20.x'
54+
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '22.x'
5555
run: pnpm lint
5656
- name: TSLint
57-
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '20.x'
57+
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '22.x'
5858
run: pnpm turbo run test:dts
5959
- name: Tests
6060
run: pnpm turbo run test

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ jobs:
2626
version: 9
2727
run_install: false
2828

29-
- name: Setup Node.js 20.x
29+
- name: Setup Node.js 22.x
3030
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
3131
with:
32-
node-version: 20.x
32+
node-version: 22.x
3333
registry-url: 'https://registry.npmjs.org'
3434

3535
- name: Upgrade npm for trusted publishing (OIDC)

.github/workflows/site-deploy.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ jobs:
1919
version: 9
2020
run_install: false
2121

22-
- name: Use Node.js 20.x
22+
- name: Use Node.js 22.x
2323
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
2424
with:
25-
node-version: 20.x
25+
node-version: 22.x
2626

2727
- name: Install and prepare
2828
run: pnpm install --frozen-lockfile --strict-peer-dependencies

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ See [Configuration](https://wyw-in-js.dev/configuration) to customize how Linari
6565

6666
Linaria relies on WyW (`@wyw-in-js/*`) to evaluate your modules at build time and extract CSS. If you hit issues like slow builds, invalidation storms, or unexpected code being executed during the build, it’s usually related to the WyW evaluation model and how your modules are structured.
6767

68-
Linaria 7 requires Node.js `>=20` (WyW 1.x enforces this via `engines`).
68+
Linaria 8 requires Node.js `>=22` (WyW 2.x enforces this via `engines`). WyW 2 defaults to `eval.strategy: "hybrid"`, so statically provable values are resolved before falling back to the evaluator for dynamic values.
69+
70+
If your build depends on evaluator-only side effects or exact CSS rule order ties, review the Linaria 8 migration notes in [docs/MIGRATION_GUIDE.md](./docs/MIGRATION_GUIDE.md).
6971

7072
See https://wyw-in-js.dev/stability for practical guidance and common pitfalls.
7173

docs/CONFIGURATION.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,22 @@ Example `wyw-in-js.config.js`:
1111

1212
```js
1313
module.exports = {
14-
evaluate: true,
14+
eval: {
15+
strategy: 'hybrid',
16+
},
1517
displayName: false,
1618
};
1719
```
1820

1921
## Options
2022

21-
- `evaluate: boolean` (default: `true`):
23+
- `eval.strategy: "hybrid" | "execute" | "static"` (default: `"hybrid"`):
24+
25+
Controls how WyW resolves values used in CSS interpolations. The recommended default, `"hybrid"`, uses static-first resolution: WyW first tries to prove values from Linaria processor static semantics, `staticBindings`, and statically resolvable imports, then falls back to the evaluator for values that cannot be proven statically.
2226

23-
Enabling this will evaluate dynamic expressions in the CSS. You need to enable this if you want to use imported variables in the CSS or interpolate other components. Enabling this also ensures that your styled components wrapping other styled components will have the correct specificity and override styles properly.
27+
Use `"execute"` when you need evaluator-only compatibility, for example while migrating code that relies on build-time side effects or exact import execution order. Use `"static"` as a strict validation mode when fallback to the evaluator should be rejected. The older top-level `evaluate` option should be migrated to `eval.strategy` in Linaria 8 / WyW 2.
28+
29+
Evaluated values are included in the generated CSS. Since fallback evaluation runs at build time in Node.js, avoid browser-only APIs, unavailable runtime globals, Node native modules such as `fs`, and side effects in evaluated expressions.
2430

2531
- `displayName: boolean` (default: `false`):
2632

@@ -445,7 +451,9 @@ module.exports = {
445451
[
446452
'@linaria',
447453
{
448-
evaluate: true,
454+
eval: {
455+
strategy: 'hybrid',
456+
},
449457
displayName: process.env.NODE_ENV !== 'production',
450458
},
451459
],

docs/HOW_IT_WORKS.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ const Container = styled.h1`
148148

149149
We support this usage because it allows you to use a library such as [polished.js](https://polished.js.org) which outputs object based styles along with Linaria.
150150

151-
If you've configured the plugin to evaluate expressions with `evaluate: true` (default), any dynamic expressions we encounter will be evaluated during the build-time in a sandbox, and the result will be included in the CSS. Since these expressions are evaluated at build time in Node, you cannot use any browser specific APIs or any API which is only available in runtime. Access to Node native modules such as `fs` is also not allowed inside the sandbox to prevent malicious scripts. In addition, to achieve consistent build output, you should also avoid doing any side effects in these expressions and keep them pure.
151+
By default, Linaria uses WyW's `eval.strategy: "hybrid"` mode. WyW first tries to resolve values statically from Linaria processor metadata, `staticBindings`, and statically resolvable imports. If a value cannot be proven statically, WyW falls back to build-time evaluation and includes the result in the generated CSS. Since fallback evaluation runs in Node.js, you cannot use browser-specific APIs, runtime-only globals, or Node native modules such as `fs`. To keep build output consistent, avoid side effects in evaluated expressions and keep them pure.
152152

153153
You might want to skip evaluating a certain interpolation if you're using a browser API, a global variable which is only available at runtime, or a module which breaks when evaluating in the sandbox for some reason. To skip evaluating an interpolation, you can always wrap it in a function, like so:
154154

@@ -162,13 +162,13 @@ But keep in mind that if you're doing SSR for your app, this won't work with SSR
162162

163163
### Evaluators
164164

165-
Linaria can use different strategies for evaluating the interpolated values.
166-
Currently, we have two built-in strategies:
165+
Linaria relies on WyW strategies for resolving interpolated values:
167166

168-
- `extractor` was the default strategy in `1.x` version. It takes an interpolated expression, finds all the referenced identifiers, gets all its declarations, repeats cycle for all identifiers in found declarations, and then constructs a new tree of statements from all found declarations. It's a pretty simple strategy, but it significantly changes an evaluated code and doesn't work for non-primitive js-constructions.
169-
- `shaker` was introduced as an option in `1.4` and became the default in `2.0` version. In contrast to `extractor`, `shaker` tries to find all irrelevant code and cuts it out of the file. As a result, interpolated values can be defined without any restrictions.
167+
- `hybrid` is the default in Linaria 8 / WyW 2. It resolves statically provable values without starting the evaluator, then falls back to evaluator execution for unresolved dynamic values.
168+
- `execute` uses evaluator-only behavior and is the compatibility escape hatch for projects that depend on build-time side effects or exact import execution order.
169+
- `static` is a strict validation mode that rejects fallback to evaluator execution.
170170

171-
If an interpolated value or one of its dependencies is imported from another module, that module will be also processed with an evaluator (the implementation of evaluator will be chosen by matching `rules` from [the Linaria config](./CONFIGURATION.md#options)).
171+
If an interpolated value or one of its dependencies is imported from another module, WyW processes that module according to the configured strategy. In `hybrid` mode, the imported value may be resolved statically; otherwise WyW falls back to the evaluator selected by matching `rules` from [the Linaria config](./CONFIGURATION.md#options).
172172

173173
Sometimes it can be useful to implement your own strategy (it can be just a mocked version of some heavy or browser-only library). You can do it by implementing `Evaluator` function:
174174

docs/MIGRATION_GUIDE.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
11
# Migration Guide
22

3+
# 8.x from 7.x
4+
5+
## For Users
6+
7+
Linaria 8 updates the WyW toolchain (`@wyw-in-js/*`) to `2.0.0` stable. This is a major release because WyW 2 changes the build-time evaluation pipeline and raises the minimum Node.js version.
8+
9+
- Linaria 8 requires Node.js 22+ (aligned with WyW 2.x `engines`).
10+
- The default evaluation mode is WyW's `eval.strategy: "hybrid"`. It resolves statically provable values first using Linaria processor static semantics, `staticBindings`, and statically resolvable imports, then falls back to the evaluator for values that cannot be proven statically.
11+
- Top-level `evaluate` config should be migrated to `eval.strategy`. Use `execute` for evaluator-only compatibility, keep the default `hybrid` for static-first resolution with evaluator fallback, or use `static` to reject evaluator fallback.
12+
- If your project relies on build-time side effects or on the exact order in which evaluated imports execute, compare the generated CSS/JS output after upgrading and use `eval.strategy: "execute"` where evaluator-only behavior is required.
13+
- CSS rule emission order can change for cascade ties with identical specificity. WyW 2 uses the Oxc/static-first pipeline and can preserve or process imports differently, so make precedence explicit through selector specificity, composition, or source structure where order matters.
14+
- Review https://wyw-in-js.dev/migration/v2 and https://wyw-in-js.dev/stability for the WyW 2 evaluation model, debugging notes, and performance guidance.
15+
16+
Example evaluator-only compatibility config:
17+
18+
```js
19+
module.exports = {
20+
eval: {
21+
strategy: 'execute',
22+
},
23+
};
24+
```
25+
26+
## For Custom Processor Developers
27+
28+
Linaria processors now expose WyW 2 static evaluation semantics. Custom processors that integrate with WyW's static-first path should implement the optional static processor contract in `@wyw-in-js/processor-utils`; unresolved values can still fall back to the evaluator in `hybrid` mode.
29+
330
# 7.x from 6.x
431

532
## For Users

examples/astro-solid/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"@astrojs/solid-js": "^1.2.3",
99
"@babel/core": "^7.23.5",
1010
"@linaria/core": "workspace:^",
11-
"@wyw-in-js/vite": "2.0.0-alpha.1",
11+
"@wyw-in-js/vite": "2.0.0",
1212
"astro": "^1.6.10",
1313
"solid-js": "^1.6.2",
1414
"vite": "^3",

examples/esbuild/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"linaria-website": "workspace:^"
88
},
99
"devDependencies": {
10-
"@wyw-in-js/esbuild": "2.0.0-alpha.1",
10+
"@wyw-in-js/esbuild": "2.0.0",
1111
"esbuild": "^0.15.16"
1212
},
1313
"scripts": {

0 commit comments

Comments
 (0)