@ranimontagna/agent-toolkit 0.1.10 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -2
- package/package.json +1 -1
- package/skills/backend/api/api-design/LICENSE +21 -0
- package/skills/backend/api/api-design/NOTICE.md +7 -0
- package/skills/backend/api/api-design/SKILL.md +523 -0
- package/skills/frontend/astro/astro-developer/LICENSE +59 -0
- package/skills/frontend/astro/astro-developer/NOTICE.md +7 -0
- package/skills/frontend/astro/astro-developer/SKILL.md +132 -0
- package/skills/frontend/astro/astro-developer/architecture.md +435 -0
- package/skills/frontend/astro/astro-developer/constraints.md +559 -0
- package/skills/frontend/astro/astro-developer/debugging.md +513 -0
- package/skills/frontend/astro/astro-developer/testing.md +973 -0
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
# Constraints & Gotchas
|
|
2
|
+
|
|
3
|
+
Critical constraints and common pitfalls when developing in the Astro monorepo.
|
|
4
|
+
|
|
5
|
+
## Node.js API Restrictions
|
|
6
|
+
|
|
7
|
+
**MOST IMPORTANT CONSTRAINT**
|
|
8
|
+
|
|
9
|
+
### The Rule (Conservative Approach)
|
|
10
|
+
|
|
11
|
+
**Location**: `/CONTRIBUTING.md:84-98`
|
|
12
|
+
|
|
13
|
+
Code in `packages/astro` has restricted Node.js API usage because Astro runs in multiple runtimes (Node.js, Cloudflare Workers, Deno, edge runtimes).
|
|
14
|
+
|
|
15
|
+
**Safe decision rule:**
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
1. In Vite plugin implementations → Node.js APIs allowed
|
|
19
|
+
2. In /runtime/ folders → Node.js APIs FORBIDDEN
|
|
20
|
+
3. Everywhere else → Avoid Node.js APIs, use @astrojs/internal-helpers
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Reality**: The codebase is messy. Not all code follows clear boundaries. The safest approach is to avoid Node.js APIs unless you're in a Vite plugin.
|
|
24
|
+
|
|
25
|
+
### Where Node.js APIs Are ABSOLUTELY FORBIDDEN
|
|
26
|
+
|
|
27
|
+
**Pattern** (enforced by Biome linter):
|
|
28
|
+
|
|
29
|
+
1. Any file in a `runtime/` folder: `**/packages/astro/src/**/runtime/**/*.ts`
|
|
30
|
+
2. Any file with `runtime` in its name: `**/packages/astro/src/**/*runtime*.ts`
|
|
31
|
+
|
|
32
|
+
**Examples of forbidden locations**:
|
|
33
|
+
|
|
34
|
+
- `packages/astro/src/runtime/server/` → FORBIDDEN (runtime folder)
|
|
35
|
+
- `packages/astro/src/runtime/client/` → FORBIDDEN (runtime folder)
|
|
36
|
+
- `packages/astro/src/vite-plugin-astro/runtime.ts` → FORBIDDEN (runtime in name)
|
|
37
|
+
- `packages/astro/src/core/render/runtime-utils.ts` → FORBIDDEN (runtime in name)
|
|
38
|
+
|
|
39
|
+
**Forbidden APIs**:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
// FORBIDDEN in runtime/ folders or *runtime*.ts files
|
|
43
|
+
import fs from 'node:fs';
|
|
44
|
+
import path from 'node:path';
|
|
45
|
+
import { Buffer } from 'node:buffer';
|
|
46
|
+
import process from 'node:process';
|
|
47
|
+
import crypto from 'node:crypto';
|
|
48
|
+
// etc.
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Enforcement**: Biome linter rule `noNodejsModules` prevents this at lint time.
|
|
52
|
+
|
|
53
|
+
### Where Node.js APIs Are SAFE
|
|
54
|
+
|
|
55
|
+
**Vite Plugin Implementations**: Node.js APIs are safe in Vite plugins
|
|
56
|
+
|
|
57
|
+
**Locations**:
|
|
58
|
+
|
|
59
|
+
- `packages/astro/src/vite-plugin-*/` → Safe for Node.js APIs
|
|
60
|
+
- `packages/astro/src/cli/` → Safe for Node.js APIs
|
|
61
|
+
- Test files → Safe for Node.js APIs
|
|
62
|
+
|
|
63
|
+
**Mixed/Unclear locations**:
|
|
64
|
+
|
|
65
|
+
- `packages/astro/src/core/` → Mixed (contains both build-time and runtime code)
|
|
66
|
+
|
|
67
|
+
**Safe approach for core/**:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
// AVOID in core/ unless in Vite plugin
|
|
71
|
+
import fs from 'node:fs';
|
|
72
|
+
|
|
73
|
+
// PREFER cross-platform utilities
|
|
74
|
+
import { fileURLToPath } from '@astrojs/internal-helpers/path';
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Special Case: Vite Plugins
|
|
78
|
+
|
|
79
|
+
**CAN use Node.js APIs**: In the plugin implementation itself
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// ALLOWED
|
|
83
|
+
export function myVitePlugin() {
|
|
84
|
+
return {
|
|
85
|
+
name: 'my-plugin',
|
|
86
|
+
load: {
|
|
87
|
+
filter: {
|
|
88
|
+
id: /\.astro$/,
|
|
89
|
+
},
|
|
90
|
+
async handler(id) {
|
|
91
|
+
// Can use Node.js APIs here
|
|
92
|
+
const fs = await import('node:fs/promises');
|
|
93
|
+
const content = await fs.readFile(id, 'utf-8');
|
|
94
|
+
return { code: content };
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**CANNOT use Node.js APIs**: In virtual modules returned by plugins
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// FORBIDDEN
|
|
105
|
+
export function myVitePlugin() {
|
|
106
|
+
return {
|
|
107
|
+
name: 'my-plugin',
|
|
108
|
+
load: {
|
|
109
|
+
filter: {
|
|
110
|
+
id: new RegExp(`^\\0virtual:my-module$`),
|
|
111
|
+
},
|
|
112
|
+
handler() {
|
|
113
|
+
// This code runs in runtime/server context
|
|
114
|
+
return {
|
|
115
|
+
code: `
|
|
116
|
+
import fs from 'node:fs'; // FORBIDDEN
|
|
117
|
+
export const data = fs.readFileSync('/data.json');
|
|
118
|
+
`,
|
|
119
|
+
};
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Critical: NonRunnableDevEnvironment
|
|
127
|
+
|
|
128
|
+
**Important**: Some adapters (like Cloudflare) set Vite's `NonRunnableDevEnvironment`, which imposes limitations on what Vite plugins can do.
|
|
129
|
+
|
|
130
|
+
**Limitation**: Vite plugins execute, but certain operations are restricted. For example, you cannot use `runner.import()` in this environment.
|
|
131
|
+
|
|
132
|
+
**Implication**: While Vite plugins still run their hooks (transform, load, etc.), they may not have access to all runtime capabilities. Code must work with these limitations.
|
|
133
|
+
|
|
134
|
+
**Rule**: Write code that doesn't depend on full Vite runtime capabilities. This is why runtime-agnostic code is essential.
|
|
135
|
+
|
|
136
|
+
### Why This Matters
|
|
137
|
+
|
|
138
|
+
**Multi-runtime support**: Astro code must run in:
|
|
139
|
+
|
|
140
|
+
- Node.js (traditional hosting)
|
|
141
|
+
- Cloudflare Workers (V8 isolates)
|
|
142
|
+
- Deno (alternative runtime)
|
|
143
|
+
- Edge runtimes (limited APIs)
|
|
144
|
+
|
|
145
|
+
**Implication**: Most code must be platform-agnostic.
|
|
146
|
+
|
|
147
|
+
**Reality**: The codebase doesn't have perfect separation yet. When in doubt, avoid Node.js APIs and use cross-platform utilities from `@astrojs/internal-helpers`.
|
|
148
|
+
|
|
149
|
+
### How to Handle This
|
|
150
|
+
|
|
151
|
+
#### Pattern 1: Use Cross-Platform Utilities
|
|
152
|
+
|
|
153
|
+
Use `@astrojs/internal-helpers` instead of Node.js APIs:
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// BAD: Direct Node.js API
|
|
157
|
+
import { resolve } from 'node:path';
|
|
158
|
+
const fullPath = resolve('./config.json');
|
|
159
|
+
|
|
160
|
+
// GOOD: Cross-platform utility
|
|
161
|
+
import { fileURLToPath } from '@astrojs/internal-helpers/path';
|
|
162
|
+
const fullPath = fileURLToPath(new URL('./config.json', import.meta.url));
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
#### Pattern 2: Vite Plugin for File Operations
|
|
166
|
+
|
|
167
|
+
If you need file operations, do them in a Vite plugin:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
// GOOD: In Vite plugin implementation
|
|
171
|
+
export function myVitePlugin() {
|
|
172
|
+
return {
|
|
173
|
+
name: 'my-plugin',
|
|
174
|
+
load: {
|
|
175
|
+
filter: {
|
|
176
|
+
id: /\.config\.js$/,
|
|
177
|
+
},
|
|
178
|
+
async handler(id) {
|
|
179
|
+
// Safe to use Node.js APIs here
|
|
180
|
+
const fs = await import('node:fs/promises');
|
|
181
|
+
const content = await fs.readFile(id, 'utf-8');
|
|
182
|
+
return { code: content };
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### Pattern 3: Build-Time Data Generation
|
|
190
|
+
|
|
191
|
+
Generate data at build time via Vite plugin, embed in virtual module:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
// Vite plugin - safe to use Node.js APIs
|
|
195
|
+
const VIRTUAL_MODULE_ID = 'virtual:my-config';
|
|
196
|
+
const RESOLVED_VIRTUAL_MODULE_ID = '\0' + VIRTUAL_MODULE_ID;
|
|
197
|
+
|
|
198
|
+
export function myVitePlugin() {
|
|
199
|
+
return {
|
|
200
|
+
name: 'my-plugin',
|
|
201
|
+
resolveId: {
|
|
202
|
+
filter: {
|
|
203
|
+
id: new RegExp(`^${VIRTUAL_MODULE_ID}$`),
|
|
204
|
+
},
|
|
205
|
+
handler() {
|
|
206
|
+
return RESOLVED_VIRTUAL_MODULE_ID;
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
load: {
|
|
210
|
+
filter: {
|
|
211
|
+
id: new RegExp(`^${RESOLVED_VIRTUAL_MODULE_ID}$`),
|
|
212
|
+
},
|
|
213
|
+
async handler() {
|
|
214
|
+
// Read at build time (safe here)
|
|
215
|
+
const fs = await import('node:fs/promises');
|
|
216
|
+
const config = JSON.parse(await fs.readFile('./config.json', 'utf-8'));
|
|
217
|
+
// Embed in generated code (no Node.js APIs in output)
|
|
218
|
+
return {
|
|
219
|
+
code: `export default ${JSON.stringify(config)}`,
|
|
220
|
+
};
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Detection
|
|
228
|
+
|
|
229
|
+
**Error message**: If you violate this, you'll typically see:
|
|
230
|
+
|
|
231
|
+
- `ReferenceError: fs is not defined`
|
|
232
|
+
- `ReferenceError: process is not defined`
|
|
233
|
+
- Build succeeds but runtime fails in edge environments
|
|
234
|
+
|
|
235
|
+
**Prevention**: Code review, test in multiple environments
|
|
236
|
+
|
|
237
|
+
## Test Isolation Requirements
|
|
238
|
+
|
|
239
|
+
**Every test fixture MUST have a unique `outDir`** to avoid cache pollution between tests.
|
|
240
|
+
|
|
241
|
+
**Why**: Build artifacts are cached and shared via ESM between test runs.
|
|
242
|
+
|
|
243
|
+
**Reference**: See [testing.md](testing.md) for detailed explanation, examples, and detection strategies.
|
|
244
|
+
|
|
245
|
+
## Circular Dependencies
|
|
246
|
+
|
|
247
|
+
### The Problem
|
|
248
|
+
|
|
249
|
+
TypeScript circular dependencies can cause:
|
|
250
|
+
|
|
251
|
+
- Undefined exports at runtime
|
|
252
|
+
- Type resolution issues
|
|
253
|
+
- Build failures
|
|
254
|
+
|
|
255
|
+
### Where It Happens
|
|
256
|
+
|
|
257
|
+
Most commonly in type imports.
|
|
258
|
+
|
|
259
|
+
### The Solution
|
|
260
|
+
|
|
261
|
+
**Types are centralized**: `packages/astro/src/types/`
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
// BAD: Import type from implementation
|
|
265
|
+
import type { AstroConfig } from '../config/index.js';
|
|
266
|
+
|
|
267
|
+
// GOOD: Import type from types/
|
|
268
|
+
import type { AstroConfig } from '../types/public.js';
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Prevention
|
|
272
|
+
|
|
273
|
+
- Import types from `types/` directory
|
|
274
|
+
- Avoid importing implementation files for types
|
|
275
|
+
- Use `import type` (not `import`) for type-only imports
|
|
276
|
+
|
|
277
|
+
## Virtual Module Conventions
|
|
278
|
+
|
|
279
|
+
**Constraint**: New virtual modules must use `virtual:astro:*` prefix (not `@astro-page:*` which is legacy).
|
|
280
|
+
|
|
281
|
+
**Why**: Standard convention, avoids conflicts, follows Rollup/Vite patterns.
|
|
282
|
+
|
|
283
|
+
**Reference**: See [architecture.md](architecture.md) for virtual module registry, implementation patterns, and detailed conventions.
|
|
284
|
+
|
|
285
|
+
## Build vs Runtime Boundaries
|
|
286
|
+
|
|
287
|
+
### The Separation
|
|
288
|
+
|
|
289
|
+
Code must respect execution boundaries:
|
|
290
|
+
|
|
291
|
+
| Context | Location | When Runs | Node APIs |
|
|
292
|
+
| -------------- | ----------------- | ----------------- | --------- |
|
|
293
|
+
| Build | `core/` | `astro build` | Yes |
|
|
294
|
+
| Dev | `core/` | `astro dev` setup | Yes |
|
|
295
|
+
| Runtime Server | `runtime/server/` | SSR rendering | No |
|
|
296
|
+
| Runtime Client | `runtime/client/` | Browser | No |
|
|
297
|
+
|
|
298
|
+
### Common Violation
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
// BAD: Runtime code importing build code
|
|
302
|
+
// In runtime/server/render.ts
|
|
303
|
+
import { buildSomething } from '../../core/build/utils.js';
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Why bad**: Runtime shouldn't depend on build-time code. Creates coupling and increases bundle size.
|
|
307
|
+
|
|
308
|
+
### Correct Pattern
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
// GOOD: Data flows from build to runtime via manifest
|
|
312
|
+
// Build time (core/build/)
|
|
313
|
+
const manifest = {
|
|
314
|
+
routes: processedRoutes,
|
|
315
|
+
config: runtimeConfig,
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
// Runtime (runtime/server/)
|
|
319
|
+
import { manifest } from 'virtual:astro:manifest';
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Package Boundaries
|
|
323
|
+
|
|
324
|
+
### Workspace Dependencies
|
|
325
|
+
|
|
326
|
+
Test fixtures and examples MUST use workspace dependencies:
|
|
327
|
+
|
|
328
|
+
```json
|
|
329
|
+
// GOOD: fixture package.json
|
|
330
|
+
{
|
|
331
|
+
"dependencies": {
|
|
332
|
+
"astro": "workspace:*",
|
|
333
|
+
"@astrojs/react": "workspace:*"
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
```json
|
|
339
|
+
// BAD: specific versions
|
|
340
|
+
{
|
|
341
|
+
"dependencies": {
|
|
342
|
+
"astro": "^4.0.0",
|
|
343
|
+
"@astrojs/react": "^3.0.0"
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Why
|
|
349
|
+
|
|
350
|
+
- Links to local packages during development
|
|
351
|
+
- Automatically uses latest local code
|
|
352
|
+
- Prevents version mismatches
|
|
353
|
+
|
|
354
|
+
### Catalog Dependencies
|
|
355
|
+
|
|
356
|
+
For external packages, use catalog when available:
|
|
357
|
+
|
|
358
|
+
```json
|
|
359
|
+
{
|
|
360
|
+
"dependencies": {
|
|
361
|
+
"astro": "workspace:*",
|
|
362
|
+
"react": "catalog:",
|
|
363
|
+
"react-dom": "catalog:"
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**Catalog location**: Root `package.json`
|
|
369
|
+
|
|
370
|
+
## Changeset Requirements
|
|
371
|
+
|
|
372
|
+
### When Required
|
|
373
|
+
|
|
374
|
+
**Required for**:
|
|
375
|
+
|
|
376
|
+
- All packages in `packages/`
|
|
377
|
+
- Any user-facing changes
|
|
378
|
+
|
|
379
|
+
**NOT required for**:
|
|
380
|
+
|
|
381
|
+
- Examples in `examples/`
|
|
382
|
+
- Test fixtures
|
|
383
|
+
- Documentation only changes
|
|
384
|
+
- Internal refactors with no API changes
|
|
385
|
+
|
|
386
|
+
### Prerelease Mode
|
|
387
|
+
|
|
388
|
+
**Current state**: Repository in prerelease mode (check `.changeset/config.json`)
|
|
389
|
+
|
|
390
|
+
```json
|
|
391
|
+
{
|
|
392
|
+
"baseBranch": "origin/next"
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**Implication**: Changes go to `next` release, not `latest`
|
|
397
|
+
|
|
398
|
+
### Creating Changeset
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
pnpm exec changeset
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
Select packages and describe changes.
|
|
405
|
+
|
|
406
|
+
## Performance Constraints
|
|
407
|
+
|
|
408
|
+
### Build Cache
|
|
409
|
+
|
|
410
|
+
**Shared cache**: Build artifacts cached in `.astro/` and `dist/`
|
|
411
|
+
|
|
412
|
+
**Implication**:
|
|
413
|
+
|
|
414
|
+
- Tests must use unique `outDir`
|
|
415
|
+
- Manual cache clear may be needed
|
|
416
|
+
- Cache can speed up but also cause issues
|
|
417
|
+
|
|
418
|
+
### Content Layer Concurrency
|
|
419
|
+
|
|
420
|
+
**Location**: `packages/astro/src/content/content-layer.ts`
|
|
421
|
+
|
|
422
|
+
**Pattern**: Uses PQueue with concurrency: 1
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
const queue = new PQueue({ concurrency: 1 });
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
**Implication**: Loaders run sequentially, not in parallel
|
|
429
|
+
|
|
430
|
+
**Reason**: Prevents race conditions in data store
|
|
431
|
+
|
|
432
|
+
### Memory Constraints
|
|
433
|
+
|
|
434
|
+
**Large sites**: May hit memory limits during build
|
|
435
|
+
|
|
436
|
+
**Mitigation**:
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
node --max-old-space-size=4096 node_modules/.bin/astro build
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
## Debugging Constraints
|
|
443
|
+
|
|
444
|
+
### Cannot Use Interactive Commands
|
|
445
|
+
|
|
446
|
+
**Forbidden in CI**:
|
|
447
|
+
|
|
448
|
+
```bash
|
|
449
|
+
# BAD: Interactive
|
|
450
|
+
git rebase -i
|
|
451
|
+
git add -i
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
**Reason**: No TTY in CI environment
|
|
455
|
+
|
|
456
|
+
### Log Levels
|
|
457
|
+
|
|
458
|
+
**Production**: Don't log verbosely by default
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
// BAD: Always logs
|
|
462
|
+
console.log('Processing file:', file);
|
|
463
|
+
|
|
464
|
+
// GOOD: Use logger with levels
|
|
465
|
+
logger.debug('Processing file:', file);
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
## Common Gotchas
|
|
469
|
+
|
|
470
|
+
### 1. File Paths in Tests
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
// BAD: Relative to cwd
|
|
474
|
+
const fixture = await loadFixture({
|
|
475
|
+
root: 'fixtures/my-test/',
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
// GOOD: Relative to test file
|
|
479
|
+
const fixture = await loadFixture({
|
|
480
|
+
root: './fixtures/my-test/',
|
|
481
|
+
});
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### 2. Async/Await in Hooks
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
// BAD: Forgetting await
|
|
488
|
+
before(async () => {
|
|
489
|
+
fixture.build(); // Missing await
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
// GOOD: Proper await
|
|
493
|
+
before(async () => {
|
|
494
|
+
await fixture.build();
|
|
495
|
+
});
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### 3. Server Cleanup
|
|
499
|
+
|
|
500
|
+
```typescript
|
|
501
|
+
// BAD: Server not stopped
|
|
502
|
+
describe('dev', () => {
|
|
503
|
+
before(async () => {
|
|
504
|
+
devServer = await fixture.startDevServer();
|
|
505
|
+
});
|
|
506
|
+
// Missing after() hook
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
// GOOD: Always cleanup
|
|
510
|
+
describe('dev', () => {
|
|
511
|
+
before(async () => {
|
|
512
|
+
devServer = await fixture.startDevServer();
|
|
513
|
+
});
|
|
514
|
+
after(async () => {
|
|
515
|
+
await devServer.stop();
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### 4. Type Imports
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
// BAD: Runtime import for types
|
|
524
|
+
import { AstroConfig } from 'astro';
|
|
525
|
+
|
|
526
|
+
// GOOD: Type-only import
|
|
527
|
+
import type { AstroConfig } from 'astro';
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### 5. Module Resolution
|
|
531
|
+
|
|
532
|
+
```typescript
|
|
533
|
+
// BAD: May fail in different contexts
|
|
534
|
+
import helper from '../utils';
|
|
535
|
+
|
|
536
|
+
// GOOD: Explicit extension
|
|
537
|
+
import helper from '../utils.js';
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
## Constraint Checklist
|
|
541
|
+
|
|
542
|
+
Before submitting code, verify:
|
|
543
|
+
|
|
544
|
+
- [ ] No Node.js APIs in `runtime/` code
|
|
545
|
+
- [ ] Tests have unique `outDir`
|
|
546
|
+
- [ ] No circular dependencies
|
|
547
|
+
- [ ] Virtual modules follow naming conventions
|
|
548
|
+
- [ ] Workspace dependencies in fixtures
|
|
549
|
+
- [ ] Changeset created (if needed)
|
|
550
|
+
- [ ] Servers cleaned up in tests
|
|
551
|
+
- [ ] Type imports use `import type`
|
|
552
|
+
- [ ] File extensions explicit (`.js`)
|
|
553
|
+
|
|
554
|
+
## Further Reading
|
|
555
|
+
|
|
556
|
+
- CONTRIBUTING.md: Node.js API restrictions (lines 84-98)
|
|
557
|
+
- CONTRIBUTING.md: Test isolation (lines 203-214)
|
|
558
|
+
- architecture.md: Execution contexts
|
|
559
|
+
- testing.md: Test patterns
|