Skip to content

Commit 4120e9d

Browse files
authored
ci: cache Typst builds and unblock parallel browser tests (#3160)
* ci: cache Typst and task outputs; unblock non-PDF browser tests * ci: apply PDF exclusions to browser instances * ci: exclude package PDF test with its root-relative path * ci: drop task cache after measuring negligible reuse * ci: stabilize library task fingerprints across fresh checkouts * ci: make remaining build tasks reusable across clean runners * ci: speed report merging and avoid duplicate task-cache snapshots * ci: preserve the canonical root when replaying browser reports
1 parent c6f14b0 commit 4120e9d

31 files changed

Lines changed: 220 additions & 64 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: Restore Typst WASM cache
2+
description: Reuse compiled Typst WASM after dependency installation
3+
runs:
4+
using: composite
5+
steps:
6+
# Cache just the distributable (~25 MB), not the multi-GB Rust target tree.
7+
# ensure-wasm.mjs still verifies its content hash before using this output.
8+
- name: Cache Typst WASM
9+
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
10+
with:
11+
path: packages/xl-typst-compiler/pkg
12+
key: typst-wasm-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('packages/xl-typst-compiler/rust/Cargo.toml', 'packages/xl-typst-compiler/rust/Cargo.lock', 'packages/xl-typst-compiler/rust/rust-toolchain.toml', 'packages/xl-typst-compiler/rust/src/**', 'packages/xl-typst-compiler/scripts/ensure-wasm.mjs', 'packages/xl-typst-compiler/package.json', 'packages/xl-typst-compiler/node_modules/wasm-pack/package.json') }}

‎.github/workflows/build.yml‎

Lines changed: 96 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,33 @@ jobs:
2828
node-version-file: ".node-version"
2929
cache: true
3030

31-
- name: Install Dependencies
32-
run: vp install
31+
- uses: $/.github/actions/typst-cache
3332

34-
# `vp run -r build` includes @blocknote/xl-typst-compiler, whose build
35-
# task compiles its Rust wasm when missing or stale (rustup is
36-
# preinstalled on the runners; the pinned toolchain + wasm32 target
37-
# auto-provision from rust/rust-toolchain.toml).
33+
- name: Select task-cache generation
34+
id: task-cache-generation
35+
# Start fresh each ISO week instead of carrying old task results forever.
36+
run: echo "week=$(date -u +%G-%V)" >> "$GITHUB_OUTPUT"
37+
38+
- name: Restore build task cache
39+
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
40+
with:
41+
path: node_modules/.vite/task-cache
42+
# Immutable per merge commit: reruns reuse it without duplicate uploads.
43+
key: vite-task-v3-${{ runner.os }}-${{ runner.arch }}-${{ steps.task-cache-generation.outputs.week }}-${{ github.sha }}
44+
restore-keys: |
45+
vite-task-v3-${{ runner.os }}-${{ runner.arch }}-${{ steps.task-cache-generation.outputs.week }}-
46+
47+
# Unchanged Rust uses the cached WASM even when the TS build misses.
48+
# Other package outputs are restored by Vite Task's own fingerprints.
3849
- name: Build packages
3950
run: vp run -r build
4051

4152
- name: Lint packages
4253
run: vp lint
4354

4455
- name: Run unit tests
45-
run: vp run test
56+
# Always execute tests: only build results are reusable across CI runs.
57+
run: vp run --no-cache test
4658

4759
- name: Run Next.js integration test (production build)
4860
run: NEXTJS_TEST_MODE=build vp test run src/unit/nextjs/serverUtil.test.ts
@@ -91,8 +103,7 @@ jobs:
91103
node-version-file: ".node-version"
92104
cache: true
93105

94-
- name: Install dependencies
95-
run: vp install
106+
- uses: $/.github/actions/typst-cache
96107

97108
# Compiles the Rust wasm when missing/stale (rustup is bootstrapped by
98109
# the build task itself) plus the TS wrapper's dist/types.
@@ -115,13 +126,11 @@ jobs:
115126
# The suite resolves every `@blocknote/*` import to its `src/` via the
116127
# aliases in `tests/vite.config.browser.ts` (vite transpiles the package
117128
# sources on the fly), so the packages do NOT need to be built to `dist`
118-
# first — `vp install` + the checked-out sources are enough (the one
119-
# exception, xl-typst-compiler, arrives prebuilt from the
120-
# build-typst-compiler job).
129+
# first. PDF tests run separately below so these shards start immediately,
130+
# without waiting for a cold Rust build.
121131
name: "E2E - ${{ matrix.browser }} (${{ matrix.shardIndex }}/${{ matrix.shardTotal }})"
122132
runs-on: ubuntu-latest
123133
timeout-minutes: 30
124-
needs: build-typst-compiler
125134
container:
126135
image: mcr.microsoft.com/playwright:v1.60.0-noble
127136
strategy:
@@ -140,15 +149,9 @@ jobs:
140149
with:
141150
node-version-file: ".node-version"
142151
cache: true
143-
144-
- name: Install dependencies
145-
run: vp install
146-
147-
- name: Download Typst compiler build outputs
148-
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
149-
with:
150-
name: typst-compiler-build
151-
path: packages/xl-typst-compiler
152+
# Build jobs populate this same dependency cache. Avoid six redundant
153+
# ~500 MB uploads racing on a cold key (observed up to 72s per shard).
154+
cache-save: false
152155

153156
# No preview server: Vitest Browser Mode serves the tests + mounted example
154157
# apps itself. `--browser` selects this matrix job's browser and
@@ -158,6 +161,8 @@ jobs:
158161
# stitches every browser's shards into one HTML report afterwards.
159162
- name: Run e2e tests (${{ matrix.browser }} ${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
160163
run: HOME=/root vp test -c vite.config.browser.ts --run --browser ${{ matrix.browser }} --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --reporter=default --reporter=blob --outputFile.blob=blob-report/blob-${{ matrix.browser }}-${{ matrix.shardIndex }}.json
164+
env:
165+
BLOCKNOTE_E2E_GROUP: non-pdf
161166
working-directory: tests
162167

163168
- name: Upload blob report (${{ matrix.browser }} ${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
@@ -179,20 +184,69 @@ jobs:
179184
include-hidden-files: true
180185
retention-days: 7
181186

187+
e2e-pdf:
188+
# Only these two files load the compiled WASM. All other browser coverage
189+
# runs concurrently with build-typst-compiler in the e2e job above.
190+
name: "E2E PDF - ${{ matrix.browser }}"
191+
runs-on: ubuntu-latest
192+
timeout-minutes: 30
193+
needs: build-typst-compiler
194+
container:
195+
image: mcr.microsoft.com/playwright:v1.60.0-noble
196+
strategy:
197+
fail-fast: false
198+
matrix:
199+
browser: [chromium, firefox, webkit]
200+
steps:
201+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
202+
with:
203+
fetch-depth: 100
204+
persist-credentials: false
205+
206+
- uses: voidzero-dev/setup-vp@3754dd7dbdb32bd8f6d28b6043de13ad3a75f21f # v1.21.1
207+
with:
208+
node-version-file: ".node-version"
209+
cache: true
210+
cache-save: false
211+
212+
- name: Download Typst compiler build outputs
213+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
214+
with:
215+
name: typst-compiler-build
216+
path: packages/xl-typst-compiler
217+
218+
- name: Run PDF browser tests
219+
run: HOME=/root vp test -c vite.config.browser.ts --run typstPdfImages.test.tsx compileTypst.browser.test.ts --browser ${{ matrix.browser }} --reporter=default --reporter=blob --outputFile.blob=blob-report/blob-pdf-${{ matrix.browser }}.json
220+
working-directory: tests
221+
222+
- name: Upload PDF blob report
223+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
224+
if: ${{ !cancelled() }}
225+
with:
226+
name: blob-report-pdf-${{ matrix.browser }}
227+
path: tests/blob-report/
228+
retention-days: 1
229+
230+
- name: Upload failure artifacts
231+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
232+
if: ${{ failure() }}
233+
with:
234+
name: e2e-attachments-pdf-${{ matrix.browser }}
235+
path: tests/.vitest-attachments/
236+
include-hidden-files: true
237+
retention-days: 7
238+
182239
merge-reports:
183240
# Stitch every browser+shard blob report into a single navigable HTML
184241
# report (the Vitest equivalent of `playwright merge-reports`). Runs even
185242
# when a shard failed, so the report always covers every browser.
186243
name: "E2E Report"
187244
runs-on: ubuntu-latest
188-
needs: e2e
245+
needs: [e2e, e2e-pdf]
189246
if: ${{ !cancelled() }}
190247
timeout-minutes: 15
191-
# Same container as the e2e shards: `--mergeReports` doesn't run tests or
192-
# launch browsers, but the HTML reporter still resolves the test files'
193-
# browser environment, so the browser config must stay enabled (and present).
194-
container:
195-
image: mcr.microsoft.com/playwright:v1.60.0-noble
248+
# Keep the browser configuration to resolve the recorded projects, but
249+
# merging replays results without launching browsers or needing their image.
196250
steps:
197251
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
198252
with:
@@ -203,9 +257,7 @@ jobs:
203257
with:
204258
node-version-file: ".node-version"
205259
cache: true
206-
207-
- name: Install dependencies
208-
run: vp install
260+
cache-save: false
209261

210262
# Gather every shard's blob into one directory (blob-report-chromium-1, …).
211263
- name: Download blob reports
@@ -216,8 +268,20 @@ jobs:
216268
merge-multiple: true
217269

218270
# Re-emit a single HTML report from the merged blobs (no tests are run).
271+
# Blob source paths use the producer containers' /__w checkout location.
272+
# Vitest also derives result IDs from the canonical root, so a forward
273+
# symlink alone loses its success/failure lookup. Move the disposable
274+
# checkout and leave a backlink for artifact actions using GITHUB_WORKSPACE.
275+
- name: Map container report paths
276+
run: |
277+
repo_name="${GITHUB_REPOSITORY#*/}"
278+
container_root="/__w/$repo_name/$repo_name"
279+
sudo mkdir -p "$(dirname "$container_root")"
280+
sudo mv "$GITHUB_WORKSPACE" "$container_root"
281+
sudo ln -s "$container_root" "$GITHUB_WORKSPACE"
282+
219283
- name: Merge into HTML report
220-
run: HOME=/root vp test -c vite.config.browser.ts --mergeReports=blob-report --reporter=html
284+
run: vp test -c vite.config.browser.ts --mergeReports=blob-report --reporter=html
221285
working-directory: tests
222286

223287
- name: Upload merged HTML report

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"lint": "vp lint --type-aware",
3333
"typecheck": "tsc --noEmit -p tsconfig.json",
3434
"postpublish": "rm -rf packages/core/README.md && rm -rf packages/react/README.md",
35-
"prebuild": "cp README.md packages/core/README.md && cp README.md packages/react/README.md",
35+
"prebuild": "vp run copy-package-readmes",
3636
"prestart": "vp run build",
3737
"start": "vp run --filter @blocknote/example-editor preview",
3838
"test": "vp run --filter \"@blocknote/*\" --filter \"docs\" test",

‎packages/ariakit/vite.config.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as path from "path";
33
import { webpackStats } from "rollup-plugin-webpack-stats";
44
import { defineConfig, type UserConfig } from "vite-plus";
55
import pkg from "./package.json";
6+
import { buildCacheInputs } from "../../scripts/build-cache-inputs.js";
67
// import eslintPlugin from "vite-plugin-eslint";
78

89
// https://vitejs.dev/config/
@@ -14,7 +15,7 @@ export default defineConfig(
1415
build: {
1516
command: "tsc && vp build",
1617
input: [
17-
{ auto: true },
18+
...buildCacheInputs("packages/ariakit"),
1819
{ pattern: "!**/*.tsbuildinfo", base: "workspace" },
1920
],
2021
// `types/**` must be declared too: a cache replay that restores only

‎packages/code-block/vite.config.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as path from "path";
22
import { webpackStats } from "rollup-plugin-webpack-stats";
33
import { defineConfig, type UserConfig } from "vite-plus";
44
import pkg from "./package.json";
5+
import { buildCacheInputs } from "../../scripts/build-cache-inputs.js";
56
// import eslintPlugin from "vite-plugin-eslint";
67

78
// https://vitejs.dev/config/
@@ -13,7 +14,7 @@ export default defineConfig(
1314
build: {
1415
command: "tsc && vp build",
1516
input: [
16-
{ auto: true },
17+
...buildCacheInputs("packages/code-block"),
1718
{ pattern: "!**/*.tsbuildinfo", base: "workspace" },
1819
],
1920
// `types/**` must be declared too: a cache replay that restores only

‎packages/core/vite.config.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as path from "path";
22
import { webpackStats } from "rollup-plugin-webpack-stats";
33
import { configDefaults, defineConfig } from "vite-plus";
44
import pkg from "./package.json";
5+
import { buildCacheInputs } from "../../scripts/build-cache-inputs.js";
56
// import eslintPlugin from "vite-plugin-eslint";
67

78
// https://vitejs.dev/config/
@@ -11,7 +12,7 @@ export default defineConfig({
1112
build: {
1213
command: "tsc && vp build",
1314
input: [
14-
{ auto: true },
15+
...buildCacheInputs("packages/core"),
1516
{ pattern: "!**/*.tsbuildinfo", base: "workspace" },
1617
],
1718
// `types/**` must be declared too: a cache replay that restores only

‎packages/dev-scripts/vite.config.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import { defineConfig } from "vite-plus";
2+
import { buildCacheInputs } from "../../scripts/build-cache-inputs.js";
23

34
export default defineConfig({
45
run: {
56
tasks: {
67
build: {
78
command: "tsc",
89
input: [
9-
{ auto: true },
10+
...buildCacheInputs("packages/dev-scripts"),
1011
{ pattern: "!**/*.tsbuildinfo", base: "workspace" },
1112
],
12-
output: ["dist/**"],
13+
output: ["dist/**", "types/**", "!dist/*.tsbuildinfo"],
1314
},
1415
"gen:examples": {
1516
command: "tsx examples/gen.ts",

‎packages/diagram-block/vite.config.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as path from "path";
22
import { webpackStats } from "rollup-plugin-webpack-stats";
33
import { configDefaults, defineConfig, type UserConfig } from "vite-plus";
44
import pkg from "./package.json";
5+
import { buildCacheInputs } from "../../scripts/build-cache-inputs.js";
56

67
// https://vitejs.dev/config/
78
export default defineConfig(
@@ -12,7 +13,7 @@ export default defineConfig(
1213
build: {
1314
command: "tsc && vp build",
1415
input: [
15-
{ auto: true },
16+
...buildCacheInputs("packages/diagram-block"),
1617
{ pattern: "!**/*.tsbuildinfo", base: "workspace" },
1718
],
1819
// `types/**` must be declared too: a cache replay that restores only

‎packages/mantine/vite.config.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as path from "path";
33
import { webpackStats } from "rollup-plugin-webpack-stats";
44
import { defineConfig, type UserConfig } from "vite-plus";
55
import pkg from "./package.json";
6+
import { buildCacheInputs } from "../../scripts/build-cache-inputs.js";
67
// import eslintPlugin from "vite-plugin-eslint";
78

89
// https://vitejs.dev/config/
@@ -14,7 +15,7 @@ export default defineConfig(
1415
build: {
1516
command: "tsc && vp build",
1617
input: [
17-
{ auto: true },
18+
...buildCacheInputs("packages/mantine"),
1819
{ pattern: "!**/*.tsbuildinfo", base: "workspace" },
1920
],
2021
// `types/**` must be declared too: a cache replay that restores only

‎packages/math-block/vite.config.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as path from "path";
22
import { webpackStats } from "rollup-plugin-webpack-stats";
33
import { configDefaults, defineConfig, type UserConfig } from "vite-plus";
44
import pkg from "./package.json";
5+
import { buildCacheInputs } from "../../scripts/build-cache-inputs.js";
56

67
// https://vitejs.dev/config/
78
export default defineConfig(
@@ -12,7 +13,7 @@ export default defineConfig(
1213
build: {
1314
command: "tsc && vp build",
1415
input: [
15-
{ auto: true },
16+
...buildCacheInputs("packages/math-block"),
1617
{ pattern: "!**/*.tsbuildinfo", base: "workspace" },
1718
],
1819
// `types/**` must be declared too: a cache replay that restores only

0 commit comments

Comments
 (0)