-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathturbo.json
More file actions
232 lines (229 loc) · 12.4 KB
/
Copy pathturbo.json
File metadata and controls
232 lines (229 loc) · 12.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
{
"$schema": "https://turborepo.com/schema.json",
// eslint.shared.ts is every package's lint configuration, imported by each package's own eslint.config.ts. It has to be a global dependency rather than a per-task input: `_lint`'s inputs are resolved relative to the package being linted, so a root file one directory up is invisible to them, and editing a rule there would otherwise leave all thirteen packages reporting a cache hit against results computed under the previous rule set.
// prettier.config.ts joins them for the same reason: eslint-plugin-prettier reads it at lint time, so changing a formatting option changes every package's lint result, and a per-package input one directory down cannot see it.
// stryker.shared.ts is the identical shape one directory up from every package's own stryker.config.ts, for `_test:mutation`.
"globalDependencies": [
"pnpm-lock.yaml",
".tool-versions",
"eslint.shared.ts",
"prettier.config.ts",
"knip.config.ts",
"tsconfig.base.json",
"stryker.shared.ts"
],
// Every task name is the underscore-prefixed one each package already used for its real command (`_build` runs tsdown; the package's own `build` script was `turbo run _build`). Running the public names from here instead would make turbo invoke those wrapper scripts, which invoke turbo again -- the recursive-call case Turborepo's own docs warn against ("You should only define these commands in the root package.json"). The wrapper scripts stay in place and stay usable for a single package, but the root pipeline reaches straight past them to the leaf commands.
//
// The web UI (`web`) needs different inputs/outputs/cache settings from the generic _build/_typecheck/etc (a vite.config.ts, a CI-only base-path env var, an uncacheable build since it stamps the commit SHA at build time) -- it uses the same underscore-prefixed task names as every other package via package-scoped overrides below, so a single `turbo run _build` still reaches it; only the settings differ, not the name. It is a leaf: nothing in the workspace depends on it.
//
// Every task depends on `^_build`, its dependencies' builds. In the separate repositories a sibling arrived pre-built from the registry, so typecheck, lint, and test needed nothing built first; here a sibling is a workspace symlink whose dist/ exists only once its own build has run, and tsc, type-aware eslint, and vitest all resolve imports through it.
"tasks": {
"_build": {
"dependsOn": ["^_build"],
// scripts/** covers document-schema.js's JSON-schema generation step (part of its build) and the standalone build scripts pdf-codec and markdown-codec carry; package.json is an input because that generation reads it.
"inputs": ["src/**", "tsdown.config.ts", "scripts/**", "package.json"],
// schemas/** is document-schema.js's second build output; the others produce dist/ only, and a declared output that a package never writes costs nothing.
"outputs": ["dist/**", "schemas/**"]
},
"_typecheck": {
"dependsOn": ["^_build"],
"inputs": ["$TURBO_DEFAULT$", "tsconfig.json", "tsconfig.node.json"],
"outputs": []
},
"_typecheck:node": {
"dependsOn": ["^_build"],
"inputs": ["$TURBO_DEFAULT$", "tsconfig.json", "tsconfig.node.json"],
"outputs": []
},
// attw --pack inspects the package's own dist/ against its own package.json exports map, so it depends on this package's own _build (which also builds every sibling `_build` depends on) rather than `^_build` -- the only task here that needs its own build rather than its dependencies'. Previously a raw shell loop in ci.yml's Typecheck job (`pnpm --recursive --filter='!documents' exec attw --pack`), preceded by an explicit `pnpm build` purely to give it a dist/ to inspect; both re-ran uncached on every push regardless of what changed. A package that doesn't publish (`web`) has no `_typecheck:attw` script, so turbo silently skips it here the same way it already skips packages missing `_test:corpus`.
"_typecheck:attw": {
"dependsOn": ["_build"],
"inputs": ["package.json"],
"outputs": []
},
"_lint": {
"dependsOn": ["^_build"],
"inputs": ["$TURBO_DEFAULT$", "eslint.config.ts"],
"outputs": [".eslintcache"]
},
"_test": {
"dependsOn": ["^_build"],
// Unit tests are co-located as src/**/*.test.ts, so src/** covers them; test/ holds only the smoke and workerd suites, which have their own tasks below.
"inputs": [
"src/**",
// documents.js's examples suite reads the committed goldens under examples/, so they are a real input to the task. Undeclared, editing a golden left the previous result cached and the change untested -- which is how a stale golden survived unnoticed until the schema package's own major bump made it fail.
"examples/**",
"vitest.config.ts",
"vitest.unit.config.ts",
"package.json"
],
// documents.js's examples suite regenerates its fixtures when this is set, which makes it a real input to the task rather than ambient state: turbo's strict env mode would otherwise strip it, and the switch would silently never take effect.
"env": ["GENERATE_EXAMPLES"],
"outputs": []
},
"_test:coverage": {
"dependsOn": ["^_build"],
"inputs": [
"src/**",
// documents.js's examples suite reads the committed goldens under examples/, so they are a real input to the task. Undeclared, editing a golden left the previous result cached and the change untested -- which is how a stale golden survived unnoticed until the schema package's own major bump made it fail.
"examples/**",
"vitest.config.ts",
"vitest.unit.config.ts",
"package.json"
],
"env": ["GENERATE_EXAMPLES"],
"outputs": ["coverage/**"]
},
"_test:workers": {
"dependsOn": ["^_build"],
"inputs": [
"src/**",
"test/workers/**",
"vitest.workers.config.ts",
"wrangler.jsonc",
"package.json"
],
"outputs": []
},
"_test:smoke": {
// The smoke suites import from dist/, and each package's own `_test:smoke` script rebuilds before running. Depending on `_build` means the build is turbo's, cached and shared with every other task that needs it, instead of an uncacheable rebuild inside the test command.
//
// `^_test:smoke` is what keeps the run correct, and it is not obvious. Those in-script rebuilds run tsdown with `clean: true`, so a smoke task empties its own dist/ before repopulating it. That was harmless while every sibling arrived pre-built from the npm registry, but here a dependent resolves a sibling through a workspace symlink into that very directory -- so two smoke tasks running concurrently let one observe the other mid-clean. Reproduced directly: document-mcp's smoke suite failed with "Failed to resolve entry for package documents.js" in a parallel run and passed both alone and at --concurrency=1. Ordering the smoke tasks topologically means no package resolves through a dist/ that a dependency is still rewriting.
"dependsOn": ["_build", "^_build", "^_test:smoke"],
"inputs": [
"src/**",
"test/smoke.test.mjs",
"vitest.config.ts",
"vitest.smoke.config.ts",
"tsdown.config.ts",
"scripts/**",
"package.json"
],
// Deliberately empty, where three packages previously declared dist/** here: dist/ is `_build`'s output, and two tasks claiming the same output directory means a cache replay of one can overwrite the other's. The smoke run itself produces nothing worth caching.
"outputs": []
},
"_test:corpus": {
"dependsOn": ["^_build"],
// markdown-codec's and pdf-codec's real-world conformance layers. Their corpora are gitignored, so this is a local-only task and CI does not run it -- as was true in those packages' own workflows.
"inputs": [
"src/**",
"test/corpus/**",
"vitest.config.ts",
"package.json"
],
"outputs": []
},
"_test:mutation": {
"dependsOn": ["^_build"],
"inputs": [
"src/**",
"stryker.config.ts",
"vitest.config.ts",
"vitest.mutation.config.ts",
"vitest.unit.config.ts",
"vite.config.ts",
"tsconfig.json",
"package.json"
],
// reports/stryker-incremental.json is Stryker's own cross-run cache (this workspace's CI restores/saves it separately via actions/cache, keyed independently of turbo's own cache), and the HTML/clear-text reports sit alongside it -- both worth keeping as a declared, replayable output rather than left for turbo to treat as untracked.
"outputs": ["reports/**"]
},
"web#_build": {
"dependsOn": ["^_build"],
"inputs": [
"src/**",
"public/**",
"index.html",
"vite.config.ts",
"tsconfig.json",
"tsconfig.worker.json",
"package.json"
],
// CI switches the app's base path to /<repo-name>/ (derived from GITHUB_REPOSITORY) for Pages; strict env mode would strip it and silently produce a build with root-relative asset paths that 404 once deployed.
"env": ["CI", "GITHUB_REPOSITORY"],
// Uncacheable on purpose. vite.config.ts embeds the HEAD commit SHA, its exact release tag, and its commit timestamp into the bundle by shelling out to git at config-load time. None of that is a declared input and none of it can be -- so on a commit that leaves packages/web/** untouched, a cache replay would deploy a bundle stamped with the previous commit's identity. A vite build per deploy is cheaper than shipping wrong version metadata.
"cache": false,
"outputs": ["dist/**"]
},
"web#_lint": {
"dependsOn": ["^_build"],
"inputs": ["$TURBO_DEFAULT$", "eslint.config.ts"],
"outputs": [".eslintcache"]
},
"web#_typecheck": {
"dependsOn": ["^_build"],
"inputs": [
"$TURBO_DEFAULT$",
"tsconfig.json",
"tsconfig.worker.json",
"tsconfig.node.json"
],
"outputs": []
},
"web#_test": {
"dependsOn": ["^_build"],
"inputs": ["src/**", "vite.config.ts", "package.json"],
"outputs": []
},
"web#_test:coverage": {
"dependsOn": ["^_build"],
"inputs": ["src/**", "vite.config.ts", "package.json"],
"outputs": ["coverage/**"]
},
"web#_test:e2e": {
// The webServer runs `pnpm dev` (vite) straight against src/, not web's own dist/ -- so this depends on siblings' builds (^_build), not web#_build.
"dependsOn": ["^_build"],
"inputs": ["src/**", "e2e/**", "playwright.config.ts", "package.json"],
"outputs": ["playwright-report/**"]
},
// The workspace root's own tooling files (eslint.config.ts, commitlint.config.ts, lint-staged.config.ts) are held to the same lint and typecheck gates as package code. Registered as root tasks so `turbo run _lint` and `turbo run _typecheck` cover them without a separate command.
"//#_lint": {
"inputs": [
"eslint.config.ts",
"eslint.shared.ts",
"prettier.config.ts",
"commitlint.config.ts",
"lint-staged.config.ts",
"tsconfig.json"
],
"outputs": [".eslintcache"]
},
// The root package has suites of its own -- the two CI scripts under .github/scripts. Without this entry `turbo run _test` skips the root package entirely, so they would never run.
"//#_test": {
"inputs": [
".github/scripts/**",
"vitest.root.config.ts",
"*.test.ts",
"release-workspace.config.json",
"pnpm-workspace.yaml",
"pnpm-lock.yaml"
],
"outputs": []
},
// knip is a whole-workspace analysis by construction: it resolves the import graph across every package at once to decide what is unreachable, so there is no per-package equivalent to run. Registered as a root task for that reason, not as a convenience.
"//#_knip": {
"inputs": [
"knip.config.ts",
"package.json",
"pnpm-workspace.yaml",
"packages/*/package.json",
"packages/*/src/**",
"packages/*/index.html"
],
"outputs": []
},
"//#_typecheck": {
"inputs": [
"eslint.config.ts",
"eslint.shared.ts",
"prettier.config.ts",
"commitlint.config.ts",
"lint-staged.config.ts",
"tsconfig.json",
"release-workspace.config.json",
"stryker.shared.ts"
],
"outputs": []
}
}
}