({
workPath,
repoRootPath,
files: originalFiles,
entrypoint: rawEntrypoint,
meta = {},
config,
span: parentSpan,
service,
registerPreDeploy,
})
| 481 | } |
| 482 | |
| 483 | export const build: BuildVX = async ({ |
| 484 | workPath, |
| 485 | repoRootPath, |
| 486 | files: originalFiles, |
| 487 | entrypoint: rawEntrypoint, |
| 488 | meta = {}, |
| 489 | config, |
| 490 | span: parentSpan, |
| 491 | service, |
| 492 | registerPreDeploy, |
| 493 | }) => { |
| 494 | let entrypoint: string | undefined = |
| 495 | rawEntrypoint === '<detect>' ? undefined : rawEntrypoint; |
| 496 | |
| 497 | const builderSpan = parentSpan ?? new Span({ name: 'vc.builder' }); |
| 498 | const framework = config?.framework; |
| 499 | let shouldInstallVercelWorkers = config?.hasWorkerServices === true; |
| 500 | let subscribers: Subscriber[] = []; |
| 501 | let spawnEnv: NodeJS.ProcessEnv | undefined; |
| 502 | // Custom install command from dashboard/project settings, if any. |
| 503 | let projectInstallCommand: string | undefined; |
| 504 | // Track whether a custom install command was used. When true, runtime |
| 505 | // dependency installation is disabled because custom install commands may |
| 506 | // install dependencies not tracked in uv.lock. |
| 507 | let hasCustomCommand = false; |
| 508 | // Track whether a custom build command/script was used. When true, compileall |
| 509 | // is disabled (a custom build may emit its own bytecode or bypass the venv |
| 510 | // layout compileall assumes). It does not affect runtime installation, since |
| 511 | // dependencies are still installed normally. |
| 512 | let hasCustomBuildCommand = false; |
| 513 | |
| 514 | const target = getTargetPlatform(meta.isDev ?? false); |
| 515 | |
| 516 | debug(`workPath: ${workPath}`); |
| 517 | |
| 518 | workPath = await downloadFilesInWorkPath({ |
| 519 | workPath, |
| 520 | files: originalFiles, |
| 521 | entrypoint, |
| 522 | meta, |
| 523 | }); |
| 524 | |
| 525 | // `tool.vercel.subscribers` declares background workers for a standalone |
| 526 | // Python app and compiles them into additional queue-triggered Lambdas. |
| 527 | // It is intentionally scoped to non-service framework builds: |
| 528 | // - `experimentalServices` projects already declare queue consumers as |
| 529 | // first-class `worker`/`job` services, so a second implicit mechanism |
| 530 | // would be redundant and ambiguous (services can share one pyproject.toml, |
| 531 | // which would duplicate every subscriber across each service build). |
| 532 | // - Bare `api/**` functions build once per file sharing this workPath, so |
| 533 | // emitting subscribers there would duplicate their outputs per build. |
| 534 | if (!service && isPythonFramework(framework)) { |
| 535 | subscribers = await getPyprojectSubscribers(workPath); |
| 536 | shouldInstallVercelWorkers ||= subscribers.length > 0; |
| 537 | } |
| 538 | |
| 539 | try { |
| 540 | // See: https://stackoverflow.com/a/44728772/376773 |
no test coverage detected