0
# Detection System
1
2
Automatic detection of project frameworks and appropriate builders for zero-configuration deployments.
3
4
## Capabilities
5
6
### Builder Detection
7
8
Automatically detect appropriate builders for a project based on its files and configuration.
9
10
```typescript { .api }
11
/**
12
* Detect appropriate builders for a project
13
* @param files - Array of file paths in the project
14
* @param pkg - Package.json contents (for npm projects)
15
* @param options - Detection options
16
* @returns Object containing detected builders, errors, and warnings
17
*/
18
function detectBuilders(
19
files: string[],
20
pkg?: PackageJson,
21
options?: Options
22
): { builders: Builder[]; errors: ErrorResponse[]; warnings: WarningResponse[] };
23
24
interface Options {
25
tag?: 'canary' | 'latest' | string;
26
functions?: BuilderFunctions;
27
ignoreBuildScript?: boolean;
28
projectSettings?: {
29
framework?: string | null;
30
devCommand?: string | null;
31
buildCommand?: string | null;
32
outputDirectory?: string | null;
33
};
34
}
35
36
interface Builder {
37
use: string;
38
src: string;
39
config?: Config;
40
}
41
42
interface ErrorResponse {
43
code: string;
44
message: string;
45
}
46
```
47
48
**Usage Examples:**
49
50
```typescript
51
import { detectBuilders } from "@now/build-utils";
52
53
// Detect builders for a Node.js project
54
const files = [
55
"index.js",
56
"package.json",
57
"api/users.js",
58
"api/posts.js",
59
"public/index.html"
60
];
61
62
const packageJson = {
63
name: "my-app",
64
scripts: {
65
build: "next build"
66
},
67
dependencies: {
68
next: "^12.0.0"
69
}
70
};
71
72
const result = detectBuilders(files, packageJson);
73
console.log("Detected builders:", result.builders);
74
// Output: [
75
// { use: "@vercel/next", src: "package.json" },
76
// { use: "@vercel/node", src: "api/**/*.js" }
77
// ]
78
79
// With custom options
80
const customResult = detectBuilders(files, packageJson, {
81
tag: "canary",
82
functions: {
83
"api/slow.js": { memory: 1024, maxDuration: 60 }
84
}
85
});
86
```
87
88
### Framework Detection
89
90
Detect which framework is being used in a project.
91
92
```typescript { .api }
93
/**
94
* Detect framework being used in a project
95
* @param options - Detection options with filesystem interface
96
* @returns Promise resolving to framework slug or null if none detected
97
*/
98
function detectFramework(options: DetectFrameworkOptions): Promise<string | null>;
99
100
interface DetectFrameworkOptions {
101
/** Filesystem interface for reading project files */
102
fs: DetectorFilesystem;
103
/** List of frameworks to check against */
104
frameworkList: Framework[];
105
}
106
107
interface Framework {
108
slug: string;
109
name: string;
110
detectors?: {
111
every?: FrameworkDetectionItem[];
112
some?: FrameworkDetectionItem[];
113
};
114
}
115
116
interface FrameworkDetectionItem {
117
path: string;
118
matchContent?: string;
119
}
120
```
121
122
**Usage Examples:**
123
124
```typescript
125
import { detectFramework } from "@now/build-utils";
126
127
// Implement filesystem interface
128
class ProjectFilesystem extends DetectorFilesystem {
129
protected async _hasPath(path: string): Promise<boolean> {
130
return fs.existsSync(path);
131
}
132
133
protected async _readFile(path: string): Promise<Buffer> {
134
return fs.readFileSync(path);
135
}
136
137
protected async _isFile(path: string): Promise<boolean> {
138
const stat = await fs.lstat(path);
139
return stat.isFile();
140
}
141
}
142
143
const framework = await detectFramework({
144
fs: new ProjectFilesystem(),
145
frameworkList: [
146
{
147
slug: "nextjs",
148
name: "Next.js",
149
detectors: {
150
some: [
151
{ path: "next.config.js" },
152
{ path: "package.json", matchContent: '"next"' }
153
]
154
}
155
}
156
]
157
});
158
159
console.log("Detected framework:", framework); // "nextjs" or null
160
```
161
162
### Route Detection
163
164
Detect API routes and generate routing configuration from filesystem structure.
165
166
```typescript { .api }
167
/**
168
* Detect API routes from filesystem
169
* @param filePaths - Array of file paths to analyze
170
* @param builders - Array of detected builders
171
* @param options - Route detection options
172
* @returns Array of detected routes
173
*/
174
function detectRoutes(
175
filePaths: string[],
176
builders: Builder[],
177
options?: DetectRoutesOptions
178
): Route[];
179
180
interface DetectRoutesOptions {
181
cleanUrls?: boolean;
182
trailingSlash?: boolean;
183
}
184
185
interface Route {
186
src: string;
187
dest?: string;
188
headers?: { [key: string]: string };
189
methods?: string[];
190
status?: number;
191
}
192
```
193
194
**Usage Examples:**
195
196
```typescript
197
import { detectRoutes } from "@now/build-utils";
198
199
const filePaths = [
200
"api/users/[id].js",
201
"api/posts/index.js",
202
"api/auth/login.js"
203
];
204
205
const builders = [
206
{ use: "@vercel/node", src: "api/**/*.js" }
207
];
208
209
const routes = detectRoutes(filePaths, builders, {
210
cleanUrls: true
211
});
212
213
console.log("Generated routes:", routes);
214
// Routes for dynamic routing, API endpoints, etc.
215
```
216
217
### Directory Detection
218
219
Detect specific directories and their purposes from builder configurations.
220
221
```typescript { .api }
222
/**
223
* Detect output directory from builders
224
* @param builders - Array of detected builders
225
* @returns Output directory path or null if not found
226
*/
227
function detectOutputDirectory(builders: Builder[]): string | null;
228
229
/**
230
* Detect API directory from builders
231
* @param builders - Array of detected builders
232
* @returns API directory path or null if not found
233
*/
234
function detectApiDirectory(builders: Builder[]): string | null;
235
236
/**
237
* Detect API file extensions from builders
238
* @param builders - Array of detected builders
239
* @returns Set of supported file extensions
240
*/
241
function detectApiExtensions(builders: Builder[]): Set<string>;
242
```
243
244
**Usage Examples:**
245
246
```typescript
247
import {
248
detectBuilders,
249
detectOutputDirectory,
250
detectApiDirectory,
251
detectApiExtensions
252
} from "@now/build-utils";
253
254
// First detect builders from project files
255
const files = [
256
"dist/index.html",
257
"dist/assets/style.css",
258
"api/hello.js",
259
"api/users.ts"
260
];
261
262
const builders = detectBuilders(files).builders;
263
264
// Then use builders to detect directories and extensions
265
const outputDir = detectOutputDirectory(builders);
266
console.log("Output directory:", outputDir); // "dist" or null
267
268
const apiDir = detectApiDirectory(builders);
269
console.log("API directory:", apiDir); // "api" or null
270
271
const apiExts = detectApiExtensions(builders);
272
console.log("API extensions:", apiExts); // Set([".js", ".ts"])
273
```
274
275
## Filesystem Detection Interface
276
277
### DetectorFilesystem
278
279
Abstract filesystem interface for framework detection that can be implemented for different storage backends.
280
281
```typescript { .api }
282
/**
283
* Abstract filesystem interface for framework detection
284
*/
285
abstract class DetectorFilesystem {
286
/** Check if a path exists */
287
hasPath(path: string): Promise<boolean>;
288
/** Check if a path represents a file */
289
isFile(path: string): Promise<boolean>;
290
/** Read file contents as Buffer */
291
readFile(path: string): Promise<Buffer>;
292
293
// Abstract methods that must be implemented
294
protected abstract _hasPath(path: string): Promise<boolean>;
295
protected abstract _readFile(path: string): Promise<Buffer>;
296
protected abstract _isFile(path: string): Promise<boolean>;
297
}
298
```
299
300
**Usage Examples:**
301
302
```typescript
303
import { DetectorFilesystem } from "@now/build-utils";
304
305
// Local filesystem implementation
306
class LocalFilesystem extends DetectorFilesystem {
307
constructor(private basePath: string) {
308
super();
309
}
310
311
protected async _hasPath(path: string): Promise<boolean> {
312
const fullPath = require('path').join(this.basePath, path);
313
return require('fs').existsSync(fullPath);
314
}
315
316
protected async _readFile(path: string): Promise<Buffer> {
317
const fullPath = require('path').join(this.basePath, path);
318
return require('fs').readFileSync(fullPath);
319
}
320
321
protected async _isFile(path: string): Promise<boolean> {
322
const fullPath = require('path').join(this.basePath, path);
323
const stat = await require('fs').promises.lstat(fullPath);
324
return stat.isFile();
325
}
326
}
327
328
// HTTP filesystem implementation
329
class HttpFilesystem extends DetectorFilesystem {
330
constructor(private baseUrl: string) {
331
super();
332
}
333
334
protected async _hasPath(path: string): Promise<boolean> {
335
try {
336
const response = await fetch(`${this.baseUrl}/${path}`, { method: 'HEAD' });
337
return response.ok;
338
} catch {
339
return false;
340
}
341
}
342
343
protected async _readFile(path: string): Promise<Buffer> {
344
const response = await fetch(`${this.baseUrl}/${path}`);
345
const arrayBuffer = await response.arrayBuffer();
346
return Buffer.from(arrayBuffer);
347
}
348
349
protected async _isFile(path: string): Promise<boolean> {
350
// Implementation depends on HTTP API capabilities
351
return this._hasPath(path);
352
}
353
}
354
```
355
356
## Detection Patterns
357
358
### Framework Detection Patterns
359
360
Common patterns used for framework detection:
361
362
```typescript
363
const frameworkPatterns = {
364
nextjs: {
365
some: [
366
{ path: "next.config.js" },
367
{ path: "next.config.ts" },
368
{ path: "package.json", matchContent: '"next"' }
369
]
370
},
371
nuxtjs: {
372
some: [
373
{ path: "nuxt.config.js" },
374
{ path: "nuxt.config.ts" },
375
{ path: "package.json", matchContent: '"nuxt"' }
376
]
377
},
378
gatsby: {
379
some: [
380
{ path: "gatsby-config.js" },
381
{ path: "gatsby-config.ts" },
382
{ path: "package.json", matchContent: '"gatsby"' }
383
]
384
}
385
};
386
```
387
388
### Builder Selection Logic
389
390
The detection system uses the following priority for selecting builders:
391
392
1. **API functions**: Files in `api/` directory get function builders
393
2. **Framework detection**: Detected frameworks get their specific builders
394
3. **Build scripts**: Projects with build scripts get static builders
395
4. **File extensions**: Fallback based on file types (.js, .ts, .py, etc.)
396
5. **Zero config**: Default builders for common patterns