mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 12:57:46 +00:00
Compare commits
18 Commits
@vercel/st
...
@vercel/py
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c7b54edad | ||
|
|
6d42816395 | ||
|
|
6fe6d05a42 | ||
|
|
50a201f145 | ||
|
|
701a02ae9d | ||
|
|
39f7586621 | ||
|
|
c4a39c8d29 | ||
|
|
3ac238cf08 | ||
|
|
8384813a0d | ||
|
|
c4587de439 | ||
|
|
d997dc4fbc | ||
|
|
d15b90bd4d | ||
|
|
5b31297f0c | ||
|
|
e232566cbe | ||
|
|
592689cad1 | ||
|
|
9b08e72f76 | ||
|
|
bd0e10cfe7 | ||
|
|
28436ade60 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "4.0.0",
|
||||
"version": "4.1.0",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
@@ -23,7 +23,7 @@
|
||||
"@types/cross-spawn": "6.0.0",
|
||||
"@types/end-of-stream": "^1.4.0",
|
||||
"@types/fs-extra": "9.0.13",
|
||||
"@types/glob": "^7.1.1",
|
||||
"@types/glob": "7.2.0",
|
||||
"@types/jest": "27.4.1",
|
||||
"@types/js-yaml": "3.12.1",
|
||||
"@types/ms": "0.7.31",
|
||||
@@ -40,7 +40,7 @@
|
||||
"cross-spawn": "6.0.5",
|
||||
"end-of-stream": "1.4.1",
|
||||
"fs-extra": "10.0.0",
|
||||
"glob": "7.1.3",
|
||||
"glob": "8.0.3",
|
||||
"into-stream": "5.0.0",
|
||||
"js-yaml": "3.13.1",
|
||||
"minimatch": "3.0.4",
|
||||
|
||||
85
packages/build-utils/src/fs/get-glob-fs.ts
Normal file
85
packages/build-utils/src/fs/get-glob-fs.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import fs from 'fs';
|
||||
import { DetectorFilesystem } from '../detectors/filesystem';
|
||||
|
||||
type GlobFs = typeof fs;
|
||||
|
||||
function normalizePath(path: string) {
|
||||
// on windows, this will return a path like
|
||||
// D:/c/package.json
|
||||
// since we abstract the filesystem, we need to remove windows specific info from the path
|
||||
// and let the FS decide how to process the path
|
||||
// D:/c/package.json => /c/package.json
|
||||
return path.replace(/^[a-zA-Z]:/, '');
|
||||
}
|
||||
|
||||
export function getGlobFs(_fs: DetectorFilesystem): GlobFs {
|
||||
const readdir = (
|
||||
path: fs.PathLike,
|
||||
callback: (err: NodeJS.ErrnoException | null, files: string[]) => void
|
||||
): void => {
|
||||
_fs
|
||||
.readdir(normalizePath(String(path)))
|
||||
.then(stats =>
|
||||
callback(
|
||||
null,
|
||||
stats.map(stat => stat.name)
|
||||
)
|
||||
)
|
||||
.catch(err => callback(err, []));
|
||||
};
|
||||
|
||||
const stat = (
|
||||
path: fs.PathLike,
|
||||
callback: (
|
||||
err: NodeJS.ErrnoException | null,
|
||||
stats: fs.Stats | null
|
||||
) => void
|
||||
): void => {
|
||||
_fs
|
||||
.isFile(normalizePath(String(path)))
|
||||
.then(isPathAFile => {
|
||||
callback(null, {
|
||||
ino: 0,
|
||||
mode: 0,
|
||||
nlink: 0,
|
||||
uid: 0,
|
||||
gid: 0,
|
||||
rdev: 0,
|
||||
size: 0,
|
||||
blksize: 0,
|
||||
blocks: 0,
|
||||
atimeMs: 0,
|
||||
mtimeMs: 0,
|
||||
ctimeMs: 0,
|
||||
birthtimeMs: 0,
|
||||
atime: new Date(),
|
||||
mtime: new Date(),
|
||||
ctime: new Date(),
|
||||
birthtime: new Date(),
|
||||
dev: 0,
|
||||
isBlockDevice: () => false,
|
||||
isCharacterDevice: () => false,
|
||||
isDirectory: () => !isPathAFile,
|
||||
isFIFO: () => false,
|
||||
isFile: () => isPathAFile,
|
||||
isSocket: () => false,
|
||||
isSymbolicLink: () => false,
|
||||
});
|
||||
})
|
||||
.catch(err => callback(err, null));
|
||||
};
|
||||
|
||||
return new Proxy(fs, {
|
||||
get(_target, prop) {
|
||||
switch (prop) {
|
||||
case 'readdir':
|
||||
return readdir;
|
||||
case 'lstat':
|
||||
case 'stat':
|
||||
return stat;
|
||||
default:
|
||||
throw new Error('Not Implemented');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -117,5 +117,14 @@ export const isStaticRuntime = (name?: string): boolean => {
|
||||
};
|
||||
|
||||
export { workspaceManagers } from './workspaces/workspace-managers';
|
||||
export { getWorkspaces } from './workspaces/get-workspaces';
|
||||
export {
|
||||
getWorkspaces,
|
||||
GetWorkspaceOptions,
|
||||
Workspace,
|
||||
WorkspaceType,
|
||||
} from './workspaces/get-workspaces';
|
||||
export {
|
||||
getWorkspacePackagePaths,
|
||||
GetWorkspacePackagePathsOptions,
|
||||
} from './workspaces/get-workspace-package-paths';
|
||||
export { monorepoManagers } from './monorepos/monorepo-managers';
|
||||
|
||||
@@ -428,7 +428,7 @@ export interface BuildResultV2Typical {
|
||||
export type BuildResultV2 = BuildResultV2Typical | BuildResultBuildOutput;
|
||||
|
||||
export interface BuildResultV3 {
|
||||
output: Lambda;
|
||||
output: Lambda | EdgeFunction;
|
||||
}
|
||||
|
||||
export type BuildV2 = (options: BuildOptions) => Promise<BuildResultV2>;
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
import _path from 'path';
|
||||
import yaml from 'js-yaml';
|
||||
import glob from 'glob';
|
||||
import { DetectorFilesystem } from '../detectors/filesystem';
|
||||
import { Workspace } from './get-workspaces';
|
||||
import { getGlobFs } from '../fs/get-glob-fs';
|
||||
import { normalizePath } from '../fs/normalize-path';
|
||||
|
||||
const posixPath = _path.posix;
|
||||
|
||||
interface GetPackagePathOptions {
|
||||
fs: DetectorFilesystem;
|
||||
}
|
||||
|
||||
export interface GetWorkspacePackagePathsOptions extends GetPackagePathOptions {
|
||||
fs: DetectorFilesystem;
|
||||
workspace: Workspace;
|
||||
}
|
||||
|
||||
export async function getWorkspacePackagePaths({
|
||||
fs,
|
||||
workspace,
|
||||
}: GetWorkspacePackagePathsOptions): Promise<string[]> {
|
||||
const { type, rootPath } = workspace;
|
||||
const workspaceFs = fs.chdir(rootPath);
|
||||
|
||||
let results: string[] = [];
|
||||
|
||||
switch (type) {
|
||||
case 'yarn':
|
||||
case 'npm':
|
||||
results = await getPackageJsonWorkspacePackagePaths({ fs: workspaceFs });
|
||||
break;
|
||||
case 'pnpm':
|
||||
results = await getPnpmWorkspacePackagePaths({ fs: workspaceFs });
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown workspace implementation: ${type}`);
|
||||
}
|
||||
|
||||
return results.map(packagePath => {
|
||||
return posixPath.join(rootPath, posixPath.dirname(packagePath));
|
||||
});
|
||||
}
|
||||
|
||||
type PackageJsonWithWorkspace = {
|
||||
workspaces?:
|
||||
| {
|
||||
packages?: string[];
|
||||
noHoist?: string[];
|
||||
}
|
||||
| string[];
|
||||
};
|
||||
|
||||
type PnpmWorkspaces = {
|
||||
packages?: string[];
|
||||
};
|
||||
|
||||
async function getPackagePaths(
|
||||
packages: string[],
|
||||
fs: DetectorFilesystem
|
||||
): Promise<string[]> {
|
||||
return (
|
||||
await Promise.all(
|
||||
packages.map(
|
||||
packageGlob =>
|
||||
new Promise<string[]>((resolve, reject) => {
|
||||
glob(
|
||||
normalizePath(posixPath.join(packageGlob, 'package.json')),
|
||||
{
|
||||
cwd: '/',
|
||||
fs: getGlobFs(fs),
|
||||
},
|
||||
(err, matches) => {
|
||||
if (err) reject(err);
|
||||
else resolve(matches);
|
||||
}
|
||||
);
|
||||
})
|
||||
)
|
||||
)
|
||||
).flat();
|
||||
}
|
||||
|
||||
async function getPackageJsonWorkspacePackagePaths({
|
||||
fs,
|
||||
}: GetPackagePathOptions): Promise<string[]> {
|
||||
const packageJsonAsBuffer = await fs.readFile('package.json');
|
||||
const { workspaces } = JSON.parse(
|
||||
packageJsonAsBuffer.toString()
|
||||
) as PackageJsonWithWorkspace;
|
||||
|
||||
let packages: string[] = [];
|
||||
|
||||
if (Array.isArray(workspaces)) {
|
||||
packages = workspaces;
|
||||
} else {
|
||||
packages = workspaces?.packages ?? [];
|
||||
}
|
||||
|
||||
return getPackagePaths(packages, fs);
|
||||
}
|
||||
|
||||
async function getPnpmWorkspacePackagePaths({
|
||||
fs,
|
||||
}: GetPackagePathOptions): Promise<string[]> {
|
||||
const pnpmWorkspaceAsBuffer = await fs.readFile('pnpm-workspace.yaml');
|
||||
const { packages = [] } = yaml.load(
|
||||
pnpmWorkspaceAsBuffer.toString()
|
||||
) as PnpmWorkspaces;
|
||||
|
||||
return getPackagePaths(packages, fs);
|
||||
}
|
||||
@@ -36,7 +36,7 @@ export async function getWorkspaces({
|
||||
const childDirectories = directoryContents.filter(
|
||||
stat => stat.type === 'dir'
|
||||
);
|
||||
|
||||
|
||||
return (
|
||||
await Promise.all(
|
||||
childDirectories.map(childDirectory =>
|
||||
|
||||
15
packages/build-utils/test/fixtures/25-multiple-lock-files-yarn/a/package.json
vendored
Normal file
15
packages/build-utils/test/fixtures/25-multiple-lock-files-yarn/a/package.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "a",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.2"
|
||||
}
|
||||
}
|
||||
15
packages/build-utils/test/fixtures/25-multiple-lock-files-yarn/b/package.json
vendored
Normal file
15
packages/build-utils/test/fixtures/25-multiple-lock-files-yarn/b/package.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "b",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"cowsay": "^1.5.0"
|
||||
}
|
||||
}
|
||||
15
packages/build-utils/test/fixtures/26-multiple-lock-files-pnpm/a/package.json
vendored
Normal file
15
packages/build-utils/test/fixtures/26-multiple-lock-files-pnpm/a/package.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "a",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.2"
|
||||
}
|
||||
}
|
||||
15
packages/build-utils/test/fixtures/26-multiple-lock-files-pnpm/b/package.json
vendored
Normal file
15
packages/build-utils/test/fixtures/26-multiple-lock-files-pnpm/b/package.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "b",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"cowsay": "^1.5.0"
|
||||
}
|
||||
}
|
||||
251
packages/build-utils/test/fixtures/26-multiple-lock-files-pnpm/pnpm-lock.yaml
generated
vendored
251
packages/build-utils/test/fixtures/26-multiple-lock-files-pnpm/pnpm-lock.yaml
generated
vendored
@@ -1,19 +1,260 @@
|
||||
lockfileVersion: 5.3
|
||||
lockfileVersion: 5.4
|
||||
|
||||
specifiers:
|
||||
once: ^1.4.0
|
||||
importers:
|
||||
|
||||
dependencies:
|
||||
once: 1.4.0
|
||||
.:
|
||||
specifiers:
|
||||
once: ^1.4.0
|
||||
dependencies:
|
||||
once: 1.4.0
|
||||
|
||||
a:
|
||||
specifiers:
|
||||
debug: ^4.3.2
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
|
||||
b:
|
||||
specifiers:
|
||||
cowsay: ^1.5.0
|
||||
dependencies:
|
||||
cowsay: 1.5.0
|
||||
|
||||
packages:
|
||||
|
||||
/ansi-regex/3.0.1:
|
||||
resolution: {integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==}
|
||||
engines: {node: '>=4'}
|
||||
dev: false
|
||||
|
||||
/ansi-regex/5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/ansi-styles/4.3.0:
|
||||
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
dev: false
|
||||
|
||||
/camelcase/5.3.1:
|
||||
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/cliui/6.0.0:
|
||||
resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
|
||||
dependencies:
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 6.2.0
|
||||
dev: false
|
||||
|
||||
/color-convert/2.0.1:
|
||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||
engines: {node: '>=7.0.0'}
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
dev: false
|
||||
|
||||
/color-name/1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
dev: false
|
||||
|
||||
/cowsay/1.5.0:
|
||||
resolution: {integrity: sha512-8Ipzr54Z8zROr/62C8f0PdhQcDusS05gKTS87xxdji8VbWefWly0k8BwGK7+VqamOrkv3eGsCkPtvlHzrhWsCA==}
|
||||
engines: {node: '>= 4'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
get-stdin: 8.0.0
|
||||
string-width: 2.1.1
|
||||
strip-final-newline: 2.0.0
|
||||
yargs: 15.4.1
|
||||
dev: false
|
||||
|
||||
/debug/4.3.4:
|
||||
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
||||
engines: {node: '>=6.0'}
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
dev: false
|
||||
|
||||
/decamelize/1.2.0:
|
||||
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/emoji-regex/8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
dev: false
|
||||
|
||||
/find-up/4.1.0:
|
||||
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
locate-path: 5.0.0
|
||||
path-exists: 4.0.0
|
||||
dev: false
|
||||
|
||||
/get-caller-file/2.0.5:
|
||||
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
||||
engines: {node: 6.* || 8.* || >= 10.*}
|
||||
dev: false
|
||||
|
||||
/get-stdin/8.0.0:
|
||||
resolution: {integrity: sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==}
|
||||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
/is-fullwidth-code-point/2.0.0:
|
||||
resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==}
|
||||
engines: {node: '>=4'}
|
||||
dev: false
|
||||
|
||||
/is-fullwidth-code-point/3.0.0:
|
||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/locate-path/5.0.0:
|
||||
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
p-locate: 4.1.0
|
||||
dev: false
|
||||
|
||||
/ms/2.1.2:
|
||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||
dev: false
|
||||
|
||||
/once/1.4.0:
|
||||
resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=}
|
||||
dependencies:
|
||||
wrappy: 1.0.2
|
||||
dev: false
|
||||
|
||||
/p-limit/2.3.0:
|
||||
resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
p-try: 2.2.0
|
||||
dev: false
|
||||
|
||||
/p-locate/4.1.0:
|
||||
resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
p-limit: 2.3.0
|
||||
dev: false
|
||||
|
||||
/p-try/2.2.0:
|
||||
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/path-exists/4.0.0:
|
||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/require-directory/2.1.1:
|
||||
resolution: {integrity: sha1-jGStX9MNqxyXbiNE/+f3kqam30I=}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/require-main-filename/2.0.0:
|
||||
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
|
||||
dev: false
|
||||
|
||||
/set-blocking/2.0.0:
|
||||
resolution: {integrity: sha1-BF+XgtARrppoA93TgrJDkrPYkPc=}
|
||||
dev: false
|
||||
|
||||
/string-width/2.1.1:
|
||||
resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
is-fullwidth-code-point: 2.0.0
|
||||
strip-ansi: 4.0.0
|
||||
dev: false
|
||||
|
||||
/string-width/4.2.3:
|
||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
emoji-regex: 8.0.0
|
||||
is-fullwidth-code-point: 3.0.0
|
||||
strip-ansi: 6.0.1
|
||||
dev: false
|
||||
|
||||
/strip-ansi/4.0.0:
|
||||
resolution: {integrity: sha1-qEeQIusaw2iocTibY1JixQXuNo8=}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
ansi-regex: 3.0.1
|
||||
dev: false
|
||||
|
||||
/strip-ansi/6.0.1:
|
||||
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
ansi-regex: 5.0.1
|
||||
dev: false
|
||||
|
||||
/strip-final-newline/2.0.0:
|
||||
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/which-module/2.0.0:
|
||||
resolution: {integrity: sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=}
|
||||
dev: false
|
||||
|
||||
/wrap-ansi/6.2.0:
|
||||
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
dev: false
|
||||
|
||||
/wrappy/1.0.2:
|
||||
resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=}
|
||||
dev: false
|
||||
|
||||
/y18n/4.0.3:
|
||||
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
|
||||
dev: false
|
||||
|
||||
/yargs-parser/18.1.3:
|
||||
resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
camelcase: 5.3.1
|
||||
decamelize: 1.2.0
|
||||
dev: false
|
||||
|
||||
/yargs/15.4.1:
|
||||
resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
cliui: 6.0.0
|
||||
decamelize: 1.2.0
|
||||
find-up: 4.1.0
|
||||
get-caller-file: 2.0.5
|
||||
require-directory: 2.1.1
|
||||
require-main-filename: 2.0.0
|
||||
set-blocking: 2.0.0
|
||||
string-width: 4.2.3
|
||||
which-module: 2.0.0
|
||||
y18n: 4.0.3
|
||||
yargs-parser: 18.1.3
|
||||
dev: false
|
||||
|
||||
38
packages/build-utils/test/unit.get-workspaces-package-paths.test.ts
vendored
Normal file
38
packages/build-utils/test/unit.get-workspaces-package-paths.test.ts
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
import path from 'path';
|
||||
import { getWorkspaces } from '../src/workspaces/get-workspaces';
|
||||
import { getWorkspacePackagePaths } from '../src/workspaces/get-workspace-package-paths';
|
||||
import { FixtureFilesystem } from './utils/fixture-filesystem';
|
||||
|
||||
describe.each<[string, string[]]>([
|
||||
['21-npm-workspaces', ['/a', '/b']],
|
||||
['23-pnpm-workspaces', ['/c', '/d']],
|
||||
['27-yarn-workspaces', ['/a', '/b']],
|
||||
['25-multiple-lock-files-yarn', ['/a', '/b']],
|
||||
['26-multiple-lock-files-pnpm', ['/a', '/b']],
|
||||
[
|
||||
'29-nested-workspaces',
|
||||
['/backend/c', '/backend/d', '/frontend/a', '/frontend/b'],
|
||||
],
|
||||
['22-pnpm', []],
|
||||
])('`getWorkspacesPackagePaths()`', (fixturePath, packagePaths) => {
|
||||
const testName =
|
||||
packagePaths.length > 0
|
||||
? `should detect ${packagePaths.join()} package${
|
||||
packagePaths.length > 1 ? 's' : ''
|
||||
} for ${fixturePath}`
|
||||
: `should not detect any workspace for ${fixturePath}`;
|
||||
|
||||
it(testName, async () => {
|
||||
const fixture = path.join(__dirname, 'fixtures', fixturePath);
|
||||
const fs = new FixtureFilesystem(fixture);
|
||||
|
||||
const workspaces = await getWorkspaces({ fs });
|
||||
const actualPackagePaths = (
|
||||
await Promise.all(
|
||||
workspaces.map(workspace => getWorkspacePackagePaths({ fs, workspace }))
|
||||
)
|
||||
).flat();
|
||||
|
||||
expect(actualPackagePaths).toEqual(packagePaths);
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "25.0.0",
|
||||
"version": "25.1.0",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Vercel",
|
||||
@@ -42,15 +42,15 @@
|
||||
"node": ">= 14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "4.0.0",
|
||||
"@vercel/go": "2.0.0",
|
||||
"@vercel/next": "3.0.0",
|
||||
"@vercel/node": "2.0.0",
|
||||
"@vercel/python": "3.0.0",
|
||||
"@vercel/redwood": "1.0.0",
|
||||
"@vercel/remix": "1.0.0",
|
||||
"@vercel/ruby": "1.3.8",
|
||||
"@vercel/static-build": "1.0.0",
|
||||
"@vercel/build-utils": "4.1.0",
|
||||
"@vercel/go": "2.0.1",
|
||||
"@vercel/next": "3.0.1",
|
||||
"@vercel/node": "2.1.0",
|
||||
"@vercel/python": "3.0.1",
|
||||
"@vercel/redwood": "1.0.1",
|
||||
"@vercel/remix": "1.0.1",
|
||||
"@vercel/ruby": "1.3.9",
|
||||
"@vercel/static-build": "1.0.1",
|
||||
"update-notifier": "5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -94,7 +94,7 @@
|
||||
"@types/which": "1.3.2",
|
||||
"@types/write-json-file": "2.2.1",
|
||||
"@types/yauzl-promise": "2.1.0",
|
||||
"@vercel/client": "12.0.0",
|
||||
"@vercel/client": "12.0.1",
|
||||
"@vercel/frameworks": "1.0.1",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@zeit/fun": "0.11.2",
|
||||
|
||||
@@ -4,6 +4,7 @@ import dotenv from 'dotenv';
|
||||
import { join, relative } from 'path';
|
||||
import {
|
||||
detectBuilders,
|
||||
normalizePath,
|
||||
Files,
|
||||
FileFsRef,
|
||||
PackageJson,
|
||||
@@ -178,7 +179,7 @@ export default async function main(client: Client): Promise<number> {
|
||||
|
||||
// Get a list of source files
|
||||
const files = (await getFiles(workPath, client)).map(f =>
|
||||
relative(workPath, f)
|
||||
normalizePath(relative(workPath, f))
|
||||
);
|
||||
|
||||
const routesResult = getTransformedRoutes({ nowConfig: vercelConfig || {} });
|
||||
@@ -266,19 +267,20 @@ export default async function main(client: Client): Promise<number> {
|
||||
}
|
||||
|
||||
// Delete output directory from potential previous build
|
||||
await fs.remove(OUTPUT_DIR);
|
||||
const outputDir = join(cwd, OUTPUT_DIR);
|
||||
await fs.remove(outputDir);
|
||||
|
||||
const buildStamp = stamp();
|
||||
|
||||
// Create fresh new output directory
|
||||
await fs.mkdirp(OUTPUT_DIR);
|
||||
await fs.mkdirp(outputDir);
|
||||
|
||||
const ops: Promise<Error | void>[] = [];
|
||||
|
||||
// Write the `detectedBuilders` result to output dir
|
||||
ops.push(
|
||||
fs.writeJSON(
|
||||
join(OUTPUT_DIR, 'builds.json'),
|
||||
join(outputDir, 'builds.json'),
|
||||
{
|
||||
'//': 'This file was generated by the `vercel build` command. It is not part of the Build Output API.',
|
||||
target,
|
||||
@@ -356,6 +358,7 @@ export default async function main(client: Client): Promise<number> {
|
||||
// Start flushing the file outputs to the filesystem asynchronously
|
||||
ops.push(
|
||||
writeBuildResult(
|
||||
outputDir,
|
||||
buildResult,
|
||||
build,
|
||||
builder,
|
||||
@@ -387,7 +390,7 @@ export default async function main(client: Client): Promise<number> {
|
||||
if (hadError) return 1;
|
||||
|
||||
// Merge existing `config.json` file into the one that will be produced
|
||||
const configPath = join(OUTPUT_DIR, 'config.json');
|
||||
const configPath = join(outputDir, 'config.json');
|
||||
// TODO: properly type
|
||||
const existingConfig = await readJSONFile<any>(configPath);
|
||||
if (existingConfig instanceof CantParseJSONFile) {
|
||||
@@ -445,7 +448,7 @@ export default async function main(client: Client): Promise<number> {
|
||||
wildcard: mergedWildcard,
|
||||
overrides: mergedOverrides,
|
||||
};
|
||||
await fs.writeJSON(join(OUTPUT_DIR, 'config.json'), config, { spaces: 2 });
|
||||
await fs.writeJSON(join(outputDir, 'config.json'), config, { spaces: 2 });
|
||||
|
||||
output.print(
|
||||
`${prependEmoji(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { resolve, join } from 'path';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import DevServer from '../../util/dev/server';
|
||||
import parseListen from '../../util/dev/parse-listen';
|
||||
@@ -12,6 +13,7 @@ import setupAndLink from '../../util/link/setup-and-link';
|
||||
import getSystemEnvValues from '../../util/env/get-system-env-values';
|
||||
import { getCommandName } from '../../util/pkg-name';
|
||||
import param from '../../util/output/param';
|
||||
import { OUTPUT_DIR } from '../../util/build/write-build-result';
|
||||
|
||||
type Options = {
|
||||
'--listen': string;
|
||||
@@ -104,6 +106,15 @@ export default async function dev(
|
||||
devCommand = process.env.VERCEL_DEV_COMMAND;
|
||||
}
|
||||
|
||||
// If there is no Development Command, we must delete the
|
||||
// v3 Build Output because it will incorrectly be detected by
|
||||
// @vercel/static-build in BuildOutputV3.getBuildOutputDirectory()
|
||||
if (!devCommand) {
|
||||
output.log(`Removing ${OUTPUT_DIR}`);
|
||||
const outputDir = join(cwd, OUTPUT_DIR);
|
||||
await fs.remove(outputDir);
|
||||
}
|
||||
|
||||
const devServer = new DevServer(cwd, {
|
||||
output,
|
||||
devCommand,
|
||||
|
||||
7
packages/cli/src/commands/env/index.ts
vendored
7
packages/cli/src/commands/env/index.ts
vendored
@@ -42,6 +42,13 @@ const help = () => {
|
||||
|
||||
${chalk.dim('Examples:')}
|
||||
|
||||
${chalk.gray(
|
||||
'–'
|
||||
)} Pull all Development Environment Variables down from the cloud
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} env pull <file>`)}
|
||||
${chalk.cyan(`$ ${getPkgName()} env pull .env.development.local`)}
|
||||
|
||||
${chalk.gray('–')} Add a new variable to multiple Environments
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} env add <name>`)}
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
|
||||
const help = () => {
|
||||
return console.log(`
|
||||
${chalk.bold(`${logo} ${getPkgName()} pull`)} [path]
|
||||
${chalk.bold(`${logo} ${getPkgName()} pull`)} [project-path]
|
||||
|
||||
${chalk.dim('Options:')}
|
||||
|
||||
@@ -42,25 +42,29 @@ const help = () => {
|
||||
|
||||
${chalk.dim('Examples:')}
|
||||
|
||||
${chalk.gray('–')} Pull the latest Project Settings from the cloud
|
||||
${chalk.gray(
|
||||
'–'
|
||||
)} Pull the latest Environment Variables and Project Settings from the cloud
|
||||
and stores them in \`.vercel/.env.\${target}.local\` and \`.vercel/project.json\` respectively.
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} pull`)}
|
||||
${chalk.cyan(`$ ${getPkgName()} pull ./path-to-project`)}
|
||||
${chalk.cyan(`$ ${getPkgName()} pull --env .env.local`)}
|
||||
${chalk.cyan(`$ ${getPkgName()} pull ./path-to-project --env .env.local`)}
|
||||
|
||||
${chalk.gray('–')} Pull specific environment's Project Settings from the cloud
|
||||
${chalk.gray('–')} Pull for a specific environment
|
||||
|
||||
${chalk.cyan(
|
||||
`$ ${getPkgName()} pull --environment=${getEnvTargetPlaceholder()}`
|
||||
)}
|
||||
|
||||
${chalk.gray(
|
||||
'If you want to download environment variables to a specific file, use `vercel env pull` instead.'
|
||||
)}
|
||||
`);
|
||||
};
|
||||
|
||||
function processArgs(client: Client) {
|
||||
return getArgs(client.argv.slice(2), {
|
||||
'--yes': Boolean,
|
||||
'--env': String, // deprecated
|
||||
'--environment': String,
|
||||
'--debug': Boolean,
|
||||
'-d': '--debug',
|
||||
|
||||
@@ -23,6 +23,7 @@ import { VERCEL_DIR } from '../projects/link';
|
||||
export const OUTPUT_DIR = join(VERCEL_DIR, 'output');
|
||||
|
||||
export async function writeBuildResult(
|
||||
outputDir: string,
|
||||
buildResult: BuildResultV2 | BuildResultV3,
|
||||
build: Builder,
|
||||
builder: BuilderV2 | BuilderV3,
|
||||
@@ -31,9 +32,13 @@ export async function writeBuildResult(
|
||||
) {
|
||||
const { version } = builder;
|
||||
if (version === 2) {
|
||||
return writeBuildResultV2(buildResult as BuildResultV2, cleanUrls);
|
||||
return writeBuildResultV2(
|
||||
outputDir,
|
||||
buildResult as BuildResultV2,
|
||||
cleanUrls
|
||||
);
|
||||
} else if (version === 3) {
|
||||
return writeBuildResultV3(buildResult as BuildResultV3, build);
|
||||
return writeBuildResultV3(outputDir, buildResult as BuildResultV3, build);
|
||||
}
|
||||
throw new Error(
|
||||
`Unsupported Builder version \`${version}\` from "${builderPkg.name}"`
|
||||
@@ -67,11 +72,12 @@ export interface PathOverride {
|
||||
* the filesystem.
|
||||
*/
|
||||
async function writeBuildResultV2(
|
||||
outputDir: string,
|
||||
buildResult: BuildResultV2,
|
||||
cleanUrls?: boolean
|
||||
) {
|
||||
if ('buildOutputPath' in buildResult) {
|
||||
await mergeBuilderOutput(buildResult);
|
||||
await mergeBuilderOutput(outputDir, buildResult);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -79,16 +85,16 @@ async function writeBuildResultV2(
|
||||
const overrides: Record<string, PathOverride> = {};
|
||||
for (const [path, output] of Object.entries(buildResult.output)) {
|
||||
if (isLambda(output)) {
|
||||
await writeLambda(output, path, lambdas);
|
||||
await writeLambda(outputDir, output, path, lambdas);
|
||||
} else if (isPrerender(output)) {
|
||||
await writeLambda(output.lambda, path, lambdas);
|
||||
await writeLambda(outputDir, output.lambda, path, lambdas);
|
||||
|
||||
// Write the fallback file alongside the Lambda directory
|
||||
let fallback = output.fallback;
|
||||
if (fallback) {
|
||||
const ext = getFileExtension(fallback);
|
||||
const fallbackName = `${path}.prerender-fallback${ext}`;
|
||||
const fallbackPath = join(OUTPUT_DIR, 'functions', fallbackName);
|
||||
const fallbackPath = join(outputDir, 'functions', fallbackName);
|
||||
const stream = fallback.toStream();
|
||||
await pipe(
|
||||
stream,
|
||||
@@ -101,7 +107,7 @@ async function writeBuildResultV2(
|
||||
}
|
||||
|
||||
const prerenderConfigPath = join(
|
||||
OUTPUT_DIR,
|
||||
outputDir,
|
||||
'functions',
|
||||
`${path}.prerender-config.json`
|
||||
);
|
||||
@@ -112,9 +118,9 @@ async function writeBuildResultV2(
|
||||
};
|
||||
await fs.writeJSON(prerenderConfigPath, prerenderConfig, { spaces: 2 });
|
||||
} else if (isFile(output)) {
|
||||
await writeStaticFile(output, path, overrides, cleanUrls);
|
||||
await writeStaticFile(outputDir, output, path, overrides, cleanUrls);
|
||||
} else if (isEdgeFunction(output)) {
|
||||
await writeEdgeFunction(output, path);
|
||||
await writeEdgeFunction(outputDir, output, path);
|
||||
} else {
|
||||
throw new Error(
|
||||
`Unsupported output type: "${(output as any).type}" for ${path}`
|
||||
@@ -128,15 +134,24 @@ async function writeBuildResultV2(
|
||||
* Writes the output from the `build()` return value of a v3 Builder to
|
||||
* the filesystem.
|
||||
*/
|
||||
async function writeBuildResultV3(buildResult: BuildResultV3, build: Builder) {
|
||||
async function writeBuildResultV3(
|
||||
outputDir: string,
|
||||
buildResult: BuildResultV3,
|
||||
build: Builder
|
||||
) {
|
||||
const { output } = buildResult;
|
||||
const src = build.src;
|
||||
if (typeof src !== 'string') {
|
||||
throw new Error(`Expected "build.src" to be a string`);
|
||||
}
|
||||
const ext = extname(src);
|
||||
const path = build.config?.zeroConfig
|
||||
? src.substring(0, src.length - ext.length)
|
||||
: src;
|
||||
if (isLambda(output)) {
|
||||
const src = build.src!;
|
||||
const ext = extname(src);
|
||||
const path = build.config?.zeroConfig
|
||||
? src.substring(0, src.length - ext.length)
|
||||
: src;
|
||||
await writeLambda(output, path);
|
||||
await writeLambda(outputDir, output, path);
|
||||
} else if (isEdgeFunction(output)) {
|
||||
await writeEdgeFunction(outputDir, output, path);
|
||||
} else {
|
||||
throw new Error(
|
||||
`Unsupported output type: "${(output as any).type}" for ${build.src}`
|
||||
@@ -154,6 +169,7 @@ async function writeBuildResultV3(buildResult: BuildResultV3, build: Builder) {
|
||||
* @param overrides Record of override configuration when a File is renamed or has other metadata
|
||||
*/
|
||||
async function writeStaticFile(
|
||||
outputDir: string,
|
||||
file: File,
|
||||
path: string,
|
||||
overrides: Record<string, PathOverride>,
|
||||
@@ -191,7 +207,7 @@ async function writeStaticFile(
|
||||
overrides[fsPath] = override;
|
||||
}
|
||||
|
||||
const dest = join(OUTPUT_DIR, 'static', fsPath);
|
||||
const dest = join(outputDir, 'static', fsPath);
|
||||
await fs.mkdirp(dirname(dest));
|
||||
|
||||
// TODO: handle (or skip) symlinks?
|
||||
@@ -205,8 +221,12 @@ async function writeStaticFile(
|
||||
* @param edgeFunction The `EdgeFunction` instance
|
||||
* @param path The URL path where the `EdgeFunction` can be accessed from
|
||||
*/
|
||||
async function writeEdgeFunction(edgeFunction: EdgeFunction, path: string) {
|
||||
const dest = join(OUTPUT_DIR, 'functions', `${path}.func`);
|
||||
async function writeEdgeFunction(
|
||||
outputDir: string,
|
||||
edgeFunction: EdgeFunction,
|
||||
path: string
|
||||
) {
|
||||
const dest = join(outputDir, 'functions', `${path}.func`);
|
||||
|
||||
await fs.mkdirp(dest);
|
||||
const ops: Promise<any>[] = [];
|
||||
@@ -235,11 +255,12 @@ async function writeEdgeFunction(edgeFunction: EdgeFunction, path: string) {
|
||||
* @param lambdas (optional) Map of `Lambda` instances that have previously been written
|
||||
*/
|
||||
async function writeLambda(
|
||||
outputDir: string,
|
||||
lambda: Lambda,
|
||||
path: string,
|
||||
lambdas?: Map<Lambda, string>
|
||||
) {
|
||||
const dest = join(OUTPUT_DIR, 'functions', `${path}.func`);
|
||||
const dest = join(outputDir, 'functions', `${path}.func`);
|
||||
|
||||
// If the `lambda` has already been written to the filesystem at a different
|
||||
// location then create a symlink to the previous location instead of copying
|
||||
@@ -248,7 +269,7 @@ async function writeLambda(
|
||||
if (existingLambdaPath) {
|
||||
const destDir = dirname(dest);
|
||||
const targetDest = join(
|
||||
OUTPUT_DIR,
|
||||
outputDir,
|
||||
'functions',
|
||||
`${existingLambdaPath}.func`
|
||||
);
|
||||
@@ -312,14 +333,17 @@ async function writeLambda(
|
||||
* `.vercel/output` directory that was specified by the Builder into the
|
||||
* `vc build` output directory.
|
||||
*/
|
||||
async function mergeBuilderOutput(buildResult: BuildResultBuildOutput) {
|
||||
const absOutputDir = resolve(OUTPUT_DIR);
|
||||
async function mergeBuilderOutput(
|
||||
outputDir: string,
|
||||
buildResult: BuildResultBuildOutput
|
||||
) {
|
||||
const absOutputDir = resolve(outputDir);
|
||||
if (absOutputDir === buildResult.buildOutputPath) {
|
||||
// `.vercel/output` dir is already in the correct location,
|
||||
// so no need to do anything
|
||||
return;
|
||||
}
|
||||
await fs.copy(buildResult.buildOutputPath, OUTPUT_DIR);
|
||||
await fs.copy(buildResult.buildOutputPath, outputDir);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { resolve } from 'path';
|
||||
import _glob, { IOptions as GlobOptions } from 'glob';
|
||||
import fs from 'fs-extra';
|
||||
import { getVercelIgnore } from '@vercel/client';
|
||||
import uniqueStrings from './unique-strings';
|
||||
@@ -21,14 +20,6 @@ function flatten(
|
||||
return res;
|
||||
}
|
||||
|
||||
async function glob(pattern: string, options: GlobOptions): Promise<string[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
_glob(pattern, options, (err, files) => {
|
||||
err ? reject(err) : resolve(files);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform relative paths into absolutes,
|
||||
* and maintains absolutes as such.
|
||||
@@ -65,15 +56,16 @@ interface StaticFilesOptions {
|
||||
export async function staticFiles(
|
||||
path: string,
|
||||
{ output, src }: StaticFilesOptions
|
||||
) {
|
||||
): Promise<string[]> {
|
||||
const { debug, time } = output;
|
||||
let files: string[] = [];
|
||||
|
||||
// The package.json `files` whitelist still
|
||||
// honors ignores: https://docs.npmjs.com/files/package.json#files
|
||||
const source = src || '.';
|
||||
// Convert all filenames into absolute paths
|
||||
const search = await glob(source, { cwd: path, absolute: true, dot: true });
|
||||
|
||||
// Ensure that `path` is an absolute path
|
||||
const search = resolve(path, source);
|
||||
|
||||
// Compile list of ignored patterns and files
|
||||
const { ig } = await getVercelIgnore(path);
|
||||
@@ -104,7 +96,7 @@ export async function staticFiles(
|
||||
// Locate files
|
||||
files = await time(
|
||||
`Locating files ${path}`,
|
||||
explode(search, {
|
||||
explode([search], {
|
||||
accepts,
|
||||
output,
|
||||
})
|
||||
@@ -164,7 +156,7 @@ async function explode(
|
||||
const all = await fs.readdir(file);
|
||||
/* eslint-disable no-use-before-define */
|
||||
const recursive = many(all.map(subdir => asAbsolute(subdir, file)));
|
||||
return (recursive as any) as Promise<string | null>;
|
||||
return recursive as any as Promise<string | null>;
|
||||
/* eslint-enable no-use-before-define */
|
||||
}
|
||||
if (!s.isFile()) {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* A fast implementation of an algorithm that takes an array and returns a copy of the array without duplicates.
|
||||
* We used to use `array-unique` ( https://github.com/jonschlinkert/array-unique/blob/5d1fbe560da8125e28e4ad6fbfa9daaf9f2ec120/index.js )
|
||||
* We used to use `array-unique` (https://github.com/jonschlinkert/array-unique/blob/5d1fbe560da8125e28e4ad6fbfa9daaf9f2ec120/index.js)
|
||||
* but from running benchmarks, found the implementation to be too slow. This implementation has show to be upto ~10x faster for large
|
||||
* projects
|
||||
* @param {Array} arr Input array that potentially has duplicates
|
||||
* @returns {Array} An array of the unique values in `arr`
|
||||
*/
|
||||
export default (arr: string[]) => {
|
||||
export default (arr: string[]): string[] => {
|
||||
const len = arr.length;
|
||||
const res: string[] = [];
|
||||
const o: { [key: string]: string | number } = {};
|
||||
|
||||
2
packages/cli/test/fixtures/unit/commands/build/.gitignore
vendored
Normal file
2
packages/cli/test/fixtures/unit/commands/build/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
!/*/.vercel
|
||||
/*/.vercel/output
|
||||
1
packages/cli/test/fixtures/unit/commands/build/edge-function/.vercel/builders/.gitignore
vendored
Normal file
1
packages/cli/test/fixtures/unit/commands/build/edge-function/.vercel/builders/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!node_modules
|
||||
15
packages/cli/test/fixtures/unit/commands/build/edge-function/.vercel/builders/node_modules/edge-function/builder.js
generated
vendored
Normal file
15
packages/cli/test/fixtures/unit/commands/build/edge-function/.vercel/builders/node_modules/edge-function/builder.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
const { EdgeFunction } = require('@vercel/build-utils');
|
||||
|
||||
exports.version = 3;
|
||||
|
||||
exports.build = async ({ entrypoint, files }) => {
|
||||
const output = new EdgeFunction({
|
||||
name: entrypoint,
|
||||
deploymentTarget: 'v8-worker',
|
||||
entrypoint,
|
||||
files: {
|
||||
[entrypoint]: files[entrypoint]
|
||||
},
|
||||
});
|
||||
return { output };
|
||||
};
|
||||
6
packages/cli/test/fixtures/unit/commands/build/edge-function/.vercel/builders/node_modules/edge-function/package.json
generated
vendored
Normal file
6
packages/cli/test/fixtures/unit/commands/build/edge-function/.vercel/builders/node_modules/edge-function/package.json
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "edge-function",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"main": "builder.js"
|
||||
}
|
||||
7
packages/cli/test/fixtures/unit/commands/build/edge-function/.vercel/project.json
vendored
Normal file
7
packages/cli/test/fixtures/unit/commands/build/edge-function/.vercel/project.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"orgId": ".",
|
||||
"projectId": ".",
|
||||
"settings": {
|
||||
"framework": null
|
||||
}
|
||||
}
|
||||
5
packages/cli/test/fixtures/unit/commands/build/edge-function/api/edge.js
vendored
Normal file
5
packages/cli/test/fixtures/unit/commands/build/edge-function/api/edge.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export const config = {
|
||||
runtime: 'experimental-edge',
|
||||
};
|
||||
|
||||
export default req => new Response('from edge');
|
||||
7
packages/cli/test/fixtures/unit/commands/build/edge-function/vercel.json
vendored
Normal file
7
packages/cli/test/fixtures/unit/commands/build/edge-function/vercel.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"functions": {
|
||||
"api/*.js": {
|
||||
"runtime": "edge-function@0.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
7
packages/cli/test/fixtures/unit/commands/build/node/.vercel/project.json
vendored
Normal file
7
packages/cli/test/fixtures/unit/commands/build/node/.vercel/project.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"orgId": ".",
|
||||
"projectId": ".",
|
||||
"settings": {
|
||||
"framework": null
|
||||
}
|
||||
}
|
||||
1
packages/cli/test/fixtures/unit/commands/build/node/api/es6.js
vendored
Normal file
1
packages/cli/test/fixtures/unit/commands/build/node/api/es6.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export default (req, res) => res.end('Vercel');
|
||||
1
packages/cli/test/fixtures/unit/commands/build/node/api/index.js
vendored
Normal file
1
packages/cli/test/fixtures/unit/commands/build/node/api/index.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = (req, res) => res.end('Vercel');
|
||||
1
packages/cli/test/fixtures/unit/commands/build/node/api/mjs.mjs
vendored
Normal file
1
packages/cli/test/fixtures/unit/commands/build/node/api/mjs.mjs
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export default (req, res) => res.end('Vercel');
|
||||
3
packages/cli/test/fixtures/unit/commands/build/node/api/typescript.ts
vendored
Normal file
3
packages/cli/test/fixtures/unit/commands/build/node/api/typescript.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { IncomingMessage, ServerResponse } from 'http';
|
||||
|
||||
export default (req: IncomingMessage, res: ServerResponse) => res.end('Vercel');
|
||||
7
packages/cli/test/fixtures/unit/commands/build/static/.vercel/project.json
vendored
Normal file
7
packages/cli/test/fixtures/unit/commands/build/static/.vercel/project.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"orgId": ".",
|
||||
"projectId": ".",
|
||||
"settings": {
|
||||
"framework": null
|
||||
}
|
||||
}
|
||||
1
packages/cli/test/fixtures/unit/commands/build/static/index.html
vendored
Normal file
1
packages/cli/test/fixtures/unit/commands/build/static/index.html
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<h1>Vercel</h1>
|
||||
@@ -0,0 +1 @@
|
||||
!node_modules
|
||||
14
packages/cli/test/fixtures/unit/commands/build/third-party-builder/.vercel/builders/node_modules/txt-builder/index.js
generated
vendored
Normal file
14
packages/cli/test/fixtures/unit/commands/build/third-party-builder/.vercel/builders/node_modules/txt-builder/index.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
const { Lambda } = require('@vercel/build-utils');
|
||||
|
||||
exports.version = 3;
|
||||
|
||||
exports.build = async ({ entrypoint, files }) => {
|
||||
const output = new Lambda({
|
||||
files: {
|
||||
[entrypoint]: files[entrypoint]
|
||||
},
|
||||
runtime: 'provided',
|
||||
handler: entrypoint
|
||||
});
|
||||
return { output };
|
||||
};
|
||||
6
packages/cli/test/fixtures/unit/commands/build/third-party-builder/.vercel/builders/node_modules/txt-builder/package.json
generated
vendored
Normal file
6
packages/cli/test/fixtures/unit/commands/build/third-party-builder/.vercel/builders/node_modules/txt-builder/package.json
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "txt-builder",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"main": "index.js"
|
||||
}
|
||||
7
packages/cli/test/fixtures/unit/commands/build/third-party-builder/.vercel/project.json
vendored
Normal file
7
packages/cli/test/fixtures/unit/commands/build/third-party-builder/.vercel/project.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"orgId": ".",
|
||||
"projectId": ".",
|
||||
"settings": {
|
||||
"framework": null
|
||||
}
|
||||
}
|
||||
1
packages/cli/test/fixtures/unit/commands/build/third-party-builder/api/foo.txt
vendored
Normal file
1
packages/cli/test/fixtures/unit/commands/build/third-party-builder/api/foo.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Text file
|
||||
7
packages/cli/test/fixtures/unit/commands/build/third-party-builder/vercel.json
vendored
Normal file
7
packages/cli/test/fixtures/unit/commands/build/third-party-builder/vercel.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"functions": {
|
||||
"api/*.txt": {
|
||||
"runtime": "txt-builder@0.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
240
packages/cli/test/unit/commands/build.test.ts
Normal file
240
packages/cli/test/unit/commands/build.test.ts
Normal file
@@ -0,0 +1,240 @@
|
||||
import ms from 'ms';
|
||||
import fs from 'fs-extra';
|
||||
import { join } from 'path';
|
||||
import { client } from '../../mocks/client';
|
||||
import build from '../../../src/commands/build';
|
||||
|
||||
jest.setTimeout(ms('1 minute'));
|
||||
|
||||
const fixture = (name: string) =>
|
||||
join(__dirname, '../../fixtures/unit/commands/build', name);
|
||||
|
||||
describe('build', () => {
|
||||
const originalCwd = process.cwd();
|
||||
|
||||
it('should build with `@vercel/static`', async () => {
|
||||
const cwd = fixture('static');
|
||||
const output = join(cwd, '.vercel/output');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
const exitCode = await build(client);
|
||||
expect(exitCode).toEqual(0);
|
||||
|
||||
// `builds.json` says that "@vercel/static" was run
|
||||
const builds = await fs.readJSON(join(output, 'builds.json'));
|
||||
expect(builds).toMatchObject({
|
||||
target: 'preview',
|
||||
builds: [
|
||||
{
|
||||
require: '@vercel/static',
|
||||
apiVersion: 2,
|
||||
src: '**',
|
||||
use: '@vercel/static',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// "static" directory contains static files
|
||||
const files = await fs.readdir(join(output, 'static'));
|
||||
expect(files.sort()).toEqual(['index.html']);
|
||||
} finally {
|
||||
process.chdir(originalCwd);
|
||||
delete process.env.__VERCEL_BUILD_RUNNING;
|
||||
}
|
||||
});
|
||||
|
||||
it('should build with `@vercel/node`', async () => {
|
||||
const cwd = fixture('node');
|
||||
const output = join(cwd, '.vercel/output');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
const exitCode = await build(client);
|
||||
expect(exitCode).toEqual(0);
|
||||
|
||||
// `builds.json` says that "@vercel/node" was run
|
||||
const builds = await fs.readJSON(join(output, 'builds.json'));
|
||||
expect(builds).toMatchObject({
|
||||
target: 'preview',
|
||||
builds: [
|
||||
{
|
||||
require: '@vercel/node',
|
||||
apiVersion: 3,
|
||||
use: '@vercel/node',
|
||||
src: 'api/es6.js',
|
||||
config: { zeroConfig: true },
|
||||
},
|
||||
{
|
||||
require: '@vercel/node',
|
||||
apiVersion: 3,
|
||||
use: '@vercel/node',
|
||||
src: 'api/index.js',
|
||||
config: { zeroConfig: true },
|
||||
},
|
||||
{
|
||||
require: '@vercel/node',
|
||||
apiVersion: 3,
|
||||
use: '@vercel/node',
|
||||
src: 'api/mjs.mjs',
|
||||
config: { zeroConfig: true },
|
||||
},
|
||||
{
|
||||
require: '@vercel/node',
|
||||
apiVersion: 3,
|
||||
use: '@vercel/node',
|
||||
src: 'api/typescript.ts',
|
||||
config: { zeroConfig: true },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// "static" directory is empty
|
||||
const hasStaticFiles = await fs.pathExists(join(output, 'static'));
|
||||
expect(
|
||||
hasStaticFiles,
|
||||
'Expected ".vercel/output/static" to not exist'
|
||||
).toEqual(false);
|
||||
|
||||
// "functions/api" directory has output Functions
|
||||
const functions = await fs.readdir(join(output, 'functions/api'));
|
||||
expect(functions.sort()).toEqual([
|
||||
'es6.func',
|
||||
'index.func',
|
||||
'mjs.func',
|
||||
'typescript.func',
|
||||
]);
|
||||
} finally {
|
||||
process.chdir(originalCwd);
|
||||
delete process.env.__VERCEL_BUILD_RUNNING;
|
||||
}
|
||||
});
|
||||
|
||||
it('should build with 3rd party Builder', async () => {
|
||||
const cwd = fixture('third-party-builder');
|
||||
const output = join(cwd, '.vercel/output');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
const exitCode = await build(client);
|
||||
expect(exitCode).toEqual(0);
|
||||
|
||||
// `builds.json` says that "@vercel/node" was run
|
||||
const builds = await fs.readJSON(join(output, 'builds.json'));
|
||||
expect(builds).toMatchObject({
|
||||
target: 'preview',
|
||||
builds: [
|
||||
{
|
||||
require: 'txt-builder',
|
||||
apiVersion: 3,
|
||||
use: 'txt-builder@0.0.0',
|
||||
src: 'api/foo.txt',
|
||||
config: {
|
||||
zeroConfig: true,
|
||||
functions: {
|
||||
'api/*.txt': {
|
||||
runtime: 'txt-builder@0.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
require: '@vercel/static',
|
||||
apiVersion: 2,
|
||||
use: '@vercel/static',
|
||||
src: '!{api/**,package.json}',
|
||||
config: {
|
||||
zeroConfig: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// "static" directory is empty
|
||||
const hasStaticFiles = await fs.pathExists(join(output, 'static'));
|
||||
expect(
|
||||
hasStaticFiles,
|
||||
'Expected ".vercel/output/static" to not exist'
|
||||
).toEqual(false);
|
||||
|
||||
// "functions/api" directory has output Functions
|
||||
const functions = await fs.readdir(join(output, 'functions/api'));
|
||||
expect(functions.sort()).toEqual(['foo.func']);
|
||||
|
||||
const vcConfig = await fs.readJSON(
|
||||
join(output, 'functions/api/foo.func/.vc-config.json')
|
||||
);
|
||||
expect(vcConfig).toMatchObject({
|
||||
handler: 'api/foo.txt',
|
||||
runtime: 'provided',
|
||||
environment: {},
|
||||
});
|
||||
} finally {
|
||||
process.chdir(originalCwd);
|
||||
delete process.env.__VERCEL_BUILD_RUNNING;
|
||||
}
|
||||
});
|
||||
|
||||
it('should serialize `EdgeFunction` output in version 3 Builder', async () => {
|
||||
const cwd = fixture('edge-function');
|
||||
const output = join(cwd, '.vercel/output');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
client.setArgv('build', '--prod');
|
||||
const exitCode = await build(client);
|
||||
expect(exitCode).toEqual(0);
|
||||
|
||||
// `builds.json` says that "@vercel/node" was run
|
||||
const builds = await fs.readJSON(join(output, 'builds.json'));
|
||||
expect(builds).toMatchObject({
|
||||
target: 'production',
|
||||
builds: [
|
||||
{
|
||||
require: 'edge-function',
|
||||
apiVersion: 3,
|
||||
use: 'edge-function@0.0.0',
|
||||
src: 'api/edge.js',
|
||||
config: {
|
||||
zeroConfig: true,
|
||||
functions: {
|
||||
'api/*.js': {
|
||||
runtime: 'edge-function@0.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
require: '@vercel/static',
|
||||
apiVersion: 2,
|
||||
use: '@vercel/static',
|
||||
src: '!{api/**,package.json}',
|
||||
config: {
|
||||
zeroConfig: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// "static" directory is empty
|
||||
const hasStaticFiles = await fs.pathExists(join(output, 'static'));
|
||||
expect(
|
||||
hasStaticFiles,
|
||||
'Expected ".vercel/output/static" to not exist'
|
||||
).toEqual(false);
|
||||
|
||||
// "functions/api" directory has output Functions
|
||||
const functions = await fs.readdir(join(output, 'functions/api'));
|
||||
expect(functions.sort()).toEqual(['edge.func']);
|
||||
|
||||
const vcConfig = await fs.readJSON(
|
||||
join(output, 'functions/api/edge.func/.vc-config.json')
|
||||
);
|
||||
expect(vcConfig).toMatchObject({
|
||||
runtime: 'edge',
|
||||
name: 'api/edge.js',
|
||||
deploymentTarget: 'v8-worker',
|
||||
entrypoint: 'api/edge.js',
|
||||
});
|
||||
} finally {
|
||||
process.chdir(originalCwd);
|
||||
delete process.env.__VERCEL_BUILD_RUNNING;
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
import vercelNextPkg from '@vercel/next/package.json';
|
||||
import vercelNodePkg from '@vercel/node/package.json';
|
||||
|
||||
jest.setTimeout(ms('20 seconds'));
|
||||
jest.setTimeout(ms('30 seconds'));
|
||||
|
||||
describe('importBuilders()', () => {
|
||||
it('should import built-in Builders', async () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/client",
|
||||
"version": "12.0.0",
|
||||
"version": "12.0.1",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"homepage": "https://vercel.com",
|
||||
@@ -42,7 +42,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "4.0.0",
|
||||
"@vercel/build-utils": "4.1.0",
|
||||
"@zeit/fetch": "5.2.0",
|
||||
"async-retry": "1.2.3",
|
||||
"async-sema": "3.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/go",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
||||
@@ -25,7 +25,7 @@
|
||||
"@types/fs-extra": "^5.0.5",
|
||||
"@types/node-fetch": "^2.3.0",
|
||||
"@types/tar": "^4.0.0",
|
||||
"@vercel/build-utils": "4.0.0",
|
||||
"@vercel/build-utils": "4.1.0",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"async-retry": "1.3.1",
|
||||
"execa": "^1.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/next",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
||||
@@ -45,7 +45,7 @@
|
||||
"@types/semver": "6.0.0",
|
||||
"@types/text-table": "0.2.1",
|
||||
"@types/webpack-sources": "3.2.0",
|
||||
"@vercel/build-utils": "4.0.0",
|
||||
"@vercel/build-utils": "4.1.0",
|
||||
"@vercel/nft": "0.19.1",
|
||||
"@vercel/routing-utils": "1.13.4",
|
||||
"async-sema": "3.0.1",
|
||||
|
||||
@@ -2,23 +2,6 @@ const KIB = 1024;
|
||||
const MIB = 1024 * KIB;
|
||||
|
||||
/**
|
||||
* The limit after compression. it has to be kibibyte instead of kilobyte
|
||||
* See https://github.com/cloudflare/wrangler/blob/8907b12add3d70ee21ac597b69cd66f6807571f4/src/wranglerjs/output.rs#L44
|
||||
* The maximum size of a *compressed* edge function.
|
||||
*/
|
||||
const EDGE_FUNCTION_SCRIPT_SIZE_LIMIT = MIB;
|
||||
|
||||
/**
|
||||
* This safety buffer must cover the size of our whole runtime layer compressed
|
||||
* plus some extra space to allow it to grow in the future. At the time of
|
||||
* writing this comment the compressed size size is ~7KiB so 20KiB should
|
||||
* be more than enough.
|
||||
*/
|
||||
const EDGE_FUNCTION_SCRIPT_SIZE_BUFFER = 20 * KIB;
|
||||
|
||||
/**
|
||||
* The max size we allow for compressed user code is the compressed script
|
||||
* limit minus the compressed safety buffer. We must check this limit after
|
||||
* compressing the user code.
|
||||
*/
|
||||
export const EDGE_FUNCTION_USER_SCRIPT_SIZE_LIMIT =
|
||||
EDGE_FUNCTION_SCRIPT_SIZE_LIMIT - EDGE_FUNCTION_SCRIPT_SIZE_BUFFER;
|
||||
export const EDGE_FUNCTION_SIZE_LIMIT = MIB;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { readFile } from 'fs-extra';
|
||||
import { ConcatSource, Source } from 'webpack-sources';
|
||||
import { fileToSource, raw, sourcemapped } from '../sourcemapped';
|
||||
import { join } from 'path';
|
||||
import { EDGE_FUNCTION_USER_SCRIPT_SIZE_LIMIT } from './constants';
|
||||
import { EDGE_FUNCTION_SIZE_LIMIT } from './constants';
|
||||
import zlib from 'zlib';
|
||||
import { promisify } from 'util';
|
||||
import bytes from 'pretty-bytes';
|
||||
@@ -74,11 +74,11 @@ function getWasmImportStatements(wasm: { name: string }[] = []) {
|
||||
|
||||
async function validateScript(content: string) {
|
||||
const gzipped = await gzip(content);
|
||||
if (gzipped.length > EDGE_FUNCTION_USER_SCRIPT_SIZE_LIMIT) {
|
||||
if (gzipped.length > EDGE_FUNCTION_SIZE_LIMIT) {
|
||||
throw new Error(
|
||||
`Exceeds maximum edge function script size: ${bytes(
|
||||
gzipped.length
|
||||
)} / ${bytes(EDGE_FUNCTION_USER_SCRIPT_SIZE_LIMIT)}`
|
||||
)} / ${bytes(EDGE_FUNCTION_SIZE_LIMIT)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ import {
|
||||
getExportStatus,
|
||||
getFilesMapFromReasons,
|
||||
getImagesManifest,
|
||||
getMiddlewareManifest,
|
||||
getNextConfig,
|
||||
getPageLambdaGroups,
|
||||
getPrerenderManifest,
|
||||
@@ -77,6 +78,7 @@ import {
|
||||
updateRouteSrc,
|
||||
validateEntrypoint,
|
||||
} from './utils';
|
||||
import assert from 'assert';
|
||||
|
||||
export const version = 2;
|
||||
export const htmlContentType = 'text/html; charset=utf-8';
|
||||
@@ -1001,7 +1003,11 @@ export const build: BuildV2 = async ({
|
||||
buildId,
|
||||
'pages'
|
||||
);
|
||||
const pages = await glob('**/!(_middleware).js', pagesDir);
|
||||
const pages = await getServerlessPages({
|
||||
pagesDir,
|
||||
entryPath,
|
||||
outputDirectory,
|
||||
});
|
||||
const launcherPath = path.join(__dirname, 'legacy-launcher.js');
|
||||
const launcherData = await readFile(launcherPath, 'utf8');
|
||||
|
||||
@@ -1074,7 +1080,11 @@ export const build: BuildV2 = async ({
|
||||
'pages'
|
||||
);
|
||||
|
||||
const pages = await glob('**/!(_middleware).js', pagesDir);
|
||||
const pages = await getServerlessPages({
|
||||
pagesDir,
|
||||
entryPath,
|
||||
outputDirectory,
|
||||
});
|
||||
const isApiPage = (page: string) =>
|
||||
page
|
||||
.replace(/\\/g, '/')
|
||||
@@ -2575,3 +2585,32 @@ export const prepareCache: PrepareCache = async ({
|
||||
debug('Cache file manifest produced');
|
||||
return cache;
|
||||
};
|
||||
|
||||
async function getServerlessPages(params: {
|
||||
pagesDir: string;
|
||||
entryPath: string;
|
||||
outputDirectory: string;
|
||||
}) {
|
||||
const [pages, middlewareManifest] = await Promise.all([
|
||||
glob('**/!(_middleware).js', params.pagesDir),
|
||||
getMiddlewareManifest(params.entryPath, params.outputDirectory),
|
||||
]);
|
||||
|
||||
// Edge Functions do not consider as Serverless Functions
|
||||
for (const edgeFunctionFile of Object.keys(
|
||||
middlewareManifest?.functions ?? {}
|
||||
)) {
|
||||
// `getStaticProps` are expecting `Prerender` output which is a Serverless function
|
||||
// and not an Edge Function. Therefore we only remove API endpoints for now, as they
|
||||
// don't have `getStaticProps`.
|
||||
//
|
||||
// Context: https://github.com/vercel/vercel/pull/7905#discussion_r890213165
|
||||
assert(
|
||||
edgeFunctionFile.startsWith('/api/'),
|
||||
`Only API endpoints are currently supported for Edge endpoints.`
|
||||
);
|
||||
delete pages[edgeFunctionFile.slice(1) + '.js'];
|
||||
}
|
||||
|
||||
return pages;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ import prettyBytes from 'pretty-bytes';
|
||||
|
||||
// related PR: https://github.com/vercel/next.js/pull/30046
|
||||
const CORRECT_NOT_FOUND_ROUTES_VERSION = 'v12.0.1';
|
||||
const CORRECT_MIDDLEWARE_ORDER_VERSION = 'v12.1.7-canary.29';
|
||||
|
||||
export async function serverBuild({
|
||||
dynamicPages,
|
||||
@@ -131,6 +132,10 @@ export async function serverBuild({
|
||||
nextVersion,
|
||||
CORRECT_NOT_FOUND_ROUTES_VERSION
|
||||
);
|
||||
const isCorrectMiddlewareOrder = semver.gte(
|
||||
nextVersion,
|
||||
CORRECT_MIDDLEWARE_ORDER_VERSION
|
||||
);
|
||||
let hasStatic500 = !!staticPages[path.join(entryDirectory, '500')];
|
||||
|
||||
if (lambdaPageKeys.length === 0) {
|
||||
@@ -788,6 +793,7 @@ export async function serverBuild({
|
||||
entryPath,
|
||||
outputDirectory,
|
||||
routesManifest,
|
||||
isCorrectMiddlewareOrder,
|
||||
});
|
||||
|
||||
const dynamicRoutes = await getDynamicRoutes(
|
||||
@@ -1025,6 +1031,10 @@ export async function serverBuild({
|
||||
|
||||
...redirects,
|
||||
|
||||
// middleware comes directly after redirects but before
|
||||
// beforeFiles rewrites as middleware is not a "file" route
|
||||
...(isCorrectMiddlewareOrder ? middleware.staticRoutes : []),
|
||||
|
||||
...beforeFilesRewrites,
|
||||
|
||||
// Make sure to 404 for the /404 path itself
|
||||
@@ -1067,7 +1077,10 @@ export async function serverBuild({
|
||||
},
|
||||
]),
|
||||
|
||||
...middleware.staticRoutes,
|
||||
// while middleware was in beta the order came right before
|
||||
// handle: 'filesystem' we maintain this for older versions
|
||||
// to prevent a local/deploy mismatch
|
||||
...(!isCorrectMiddlewareOrder ? middleware.staticRoutes : []),
|
||||
|
||||
// Next.js page lambdas, `static/` folder, reserved assets, and `public/`
|
||||
// folder
|
||||
|
||||
@@ -2124,12 +2124,11 @@ export {
|
||||
interface MiddlewareManifest {
|
||||
version: 1;
|
||||
sortedMiddleware: string[];
|
||||
middleware: {
|
||||
[page: string]: MiddlewareInfo;
|
||||
};
|
||||
middleware: { [page: string]: EdgeFunctionInfo };
|
||||
functions?: { [page: string]: EdgeFunctionInfo };
|
||||
}
|
||||
|
||||
interface MiddlewareInfo {
|
||||
interface EdgeFunctionInfo {
|
||||
env: string[];
|
||||
files: string[];
|
||||
name: string;
|
||||
@@ -2142,25 +2141,45 @@ export async function getMiddlewareBundle({
|
||||
entryPath,
|
||||
outputDirectory,
|
||||
routesManifest,
|
||||
isCorrectMiddlewareOrder,
|
||||
}: {
|
||||
entryPath: string;
|
||||
outputDirectory: string;
|
||||
routesManifest: RoutesManifest;
|
||||
isCorrectMiddlewareOrder: boolean;
|
||||
}) {
|
||||
const middlewareManifest = await getMiddlewareManifest(
|
||||
entryPath,
|
||||
outputDirectory
|
||||
);
|
||||
const sortedFunctions = [
|
||||
...(!middlewareManifest
|
||||
? []
|
||||
: middlewareManifest.sortedMiddleware.map(key => ({
|
||||
key,
|
||||
edgeFunction: middlewareManifest?.middleware[key],
|
||||
type: 'middleware' as const,
|
||||
}))),
|
||||
|
||||
if (middlewareManifest && middlewareManifest?.sortedMiddleware.length > 0) {
|
||||
...Object.entries(middlewareManifest?.functions ?? {}).map(
|
||||
([key, edgeFunction]) => {
|
||||
return {
|
||||
key,
|
||||
edgeFunction,
|
||||
type: 'function' as const,
|
||||
};
|
||||
}
|
||||
),
|
||||
];
|
||||
|
||||
if (middlewareManifest && sortedFunctions.length > 0) {
|
||||
const workerConfigs = await Promise.all(
|
||||
middlewareManifest.sortedMiddleware.map(async key => {
|
||||
const middleware = middlewareManifest.middleware[key];
|
||||
sortedFunctions.map(async ({ key, edgeFunction, type }) => {
|
||||
try {
|
||||
const wrappedModuleSource = await getNextjsEdgeFunctionSource(
|
||||
middleware.files,
|
||||
edgeFunction.files,
|
||||
{
|
||||
name: middleware.name,
|
||||
name: edgeFunction.name,
|
||||
staticRoutes: routesManifest.staticRoutes,
|
||||
dynamicRoutes: routesManifest.dynamicRoutes.filter(
|
||||
r => !('isMiddleware' in r)
|
||||
@@ -2171,18 +2190,19 @@ export async function getMiddlewareBundle({
|
||||
},
|
||||
},
|
||||
path.resolve(entryPath, outputDirectory),
|
||||
middleware.wasm
|
||||
edgeFunction.wasm
|
||||
);
|
||||
|
||||
return {
|
||||
page: middlewareManifest.middleware[key].page,
|
||||
type,
|
||||
page: edgeFunction.page,
|
||||
edgeFunction: (() => {
|
||||
const { source, map } = wrappedModuleSource.sourceAndMap();
|
||||
const transformedMap = stringifySourceMap(
|
||||
transformSourceMap(map)
|
||||
);
|
||||
|
||||
const wasmFiles = (middleware.wasm ?? []).reduce(
|
||||
const wasmFiles = (edgeFunction.wasm ?? []).reduce(
|
||||
(acc: Files, { filePath, name }) => {
|
||||
const fullFilePath = path.join(
|
||||
entryPath,
|
||||
@@ -2201,7 +2221,7 @@ export async function getMiddlewareBundle({
|
||||
|
||||
return new EdgeFunction({
|
||||
deploymentTarget: 'v8-worker',
|
||||
name: middleware.name,
|
||||
name: edgeFunction.name,
|
||||
files: {
|
||||
'index.js': new FileBlob({
|
||||
data: source,
|
||||
@@ -2218,13 +2238,10 @@ export async function getMiddlewareBundle({
|
||||
...wasmFiles,
|
||||
},
|
||||
entrypoint: 'index.js',
|
||||
envVarsInUse: middleware.env,
|
||||
envVarsInUse: edgeFunction.env,
|
||||
});
|
||||
})(),
|
||||
routeSrc: getRouteSrc(
|
||||
middlewareManifest.middleware[key],
|
||||
routesManifest
|
||||
),
|
||||
routeSrc: getRouteSrc(edgeFunction, routesManifest),
|
||||
};
|
||||
} catch (e: any) {
|
||||
e.message = `Can't build edge function ${key}: ${e.message}`;
|
||||
@@ -2245,15 +2262,23 @@ export async function getMiddlewareBundle({
|
||||
|
||||
for (const worker of workerConfigs.values()) {
|
||||
const edgeFile = worker.edgeFunction.name;
|
||||
worker.edgeFunction.name = edgeFile.replace(/^pages\//, '');
|
||||
source.edgeFunctions[edgeFile] = worker.edgeFunction;
|
||||
const route = {
|
||||
const shortPath = edgeFile.replace(/^pages\//, '');
|
||||
worker.edgeFunction.name = shortPath;
|
||||
source.edgeFunctions[shortPath] = worker.edgeFunction;
|
||||
const route: Route = {
|
||||
continue: true,
|
||||
override: true,
|
||||
middlewarePath: edgeFile,
|
||||
src: worker.routeSrc,
|
||||
};
|
||||
|
||||
if (worker.type === 'function') {
|
||||
route.dest = shortPath;
|
||||
} else {
|
||||
route.middlewarePath = shortPath;
|
||||
if (isCorrectMiddlewareOrder) {
|
||||
route.override = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (routesManifest.version > 3 && isDynamicRoute(worker.page)) {
|
||||
source.dynamicRouteMap.set(worker.page, route);
|
||||
} else {
|
||||
@@ -2276,7 +2301,7 @@ export async function getMiddlewareBundle({
|
||||
* location. If the manifest can't be found it will resolve to
|
||||
* undefined.
|
||||
*/
|
||||
async function getMiddlewareManifest(
|
||||
export async function getMiddlewareManifest(
|
||||
entryPath: string,
|
||||
outputDirectory: string
|
||||
): Promise<MiddlewareManifest | undefined> {
|
||||
@@ -2308,7 +2333,7 @@ async function getMiddlewareManifest(
|
||||
* @returns A regexp string for the middleware route.
|
||||
*/
|
||||
function getRouteSrc(
|
||||
{ regexp, page }: MiddlewareInfo,
|
||||
{ regexp, page }: EdgeFunctionInfo,
|
||||
{ basePath = '', i18n }: RoutesManifest
|
||||
): string {
|
||||
if (page === '/') {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"path": "/redirect-me",
|
||||
"status": 307,
|
||||
"responseHeaders": {
|
||||
"Location": "/from-next-config/"
|
||||
"Location": "/from-middleware/"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
|
||||
@@ -47,6 +47,11 @@ export function middleware(request) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (url.pathname === '/somewhere') {
|
||||
url.pathname = '/from-middleware';
|
||||
return NextResponse.redirect(url);
|
||||
}
|
||||
|
||||
if (url.pathname === '/logs') {
|
||||
console.clear();
|
||||
for (let i = 0; i < 3; i++) console.count();
|
||||
|
||||
@@ -11,6 +11,23 @@
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/rewrite-before-files",
|
||||
"status": 404,
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/somewhere",
|
||||
"status": 307,
|
||||
"responseHeaders": {
|
||||
"Location": "/from-middleware/"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ describe('Middleware simple project', () => {
|
||||
expect(typeof beforeFilesIndex).toBe('number');
|
||||
expect(redirectIndex).toBeLessThan(middlewareIndex);
|
||||
expect(redirectIndex).toBeLessThan(beforeFilesIndex);
|
||||
expect(beforeFilesIndex).toBeLessThan(middlewareIndex);
|
||||
expect(middlewareIndex).toBeLessThan(beforeFilesIndex);
|
||||
expect(middlewareIndex).toBeLessThan(handleFileSystemIndex);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/node",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.0",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
|
||||
@@ -45,9 +45,10 @@
|
||||
"@types/etag": "1.8.0",
|
||||
"@types/jest": "27.4.1",
|
||||
"@types/test-listen": "1.1.0",
|
||||
"@vercel/build-utils": "4.0.0",
|
||||
"@vercel/build-utils": "4.1.0",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@vercel/nft": "0.19.1",
|
||||
"@vercel/static-config": "2.0.1",
|
||||
"content-type": "1.0.4",
|
||||
"cookie": "0.4.0",
|
||||
"etag": "1.8.1",
|
||||
|
||||
@@ -16,18 +16,15 @@ import {
|
||||
sep,
|
||||
parse as parsePath,
|
||||
} from 'path';
|
||||
import { Project } from 'ts-morph';
|
||||
import once from '@tootallnate/once';
|
||||
import { nodeFileTrace } from '@vercel/nft';
|
||||
import {
|
||||
File,
|
||||
Files,
|
||||
Meta,
|
||||
Config,
|
||||
StartDevServerOptions,
|
||||
glob,
|
||||
download,
|
||||
FileBlob,
|
||||
FileFsRef,
|
||||
EdgeFunction,
|
||||
NodejsLambda,
|
||||
runNpmInstall,
|
||||
runPackageJsonScript,
|
||||
@@ -37,11 +34,20 @@ import {
|
||||
debug,
|
||||
isSymbolicLink,
|
||||
walkParentDirs,
|
||||
} from '@vercel/build-utils';
|
||||
import type {
|
||||
File,
|
||||
Files,
|
||||
Meta,
|
||||
Config,
|
||||
StartDevServerOptions,
|
||||
BuildV3,
|
||||
PrepareCache,
|
||||
StartDevServer,
|
||||
NodeVersion,
|
||||
BuildResultV3,
|
||||
} from '@vercel/build-utils';
|
||||
import { getConfig } from '@vercel/static-config';
|
||||
|
||||
import { Register, register } from './typescript';
|
||||
|
||||
@@ -69,6 +75,8 @@ function isPortInfo(v: any): v is PortInfo {
|
||||
return v && typeof v.port === 'number';
|
||||
}
|
||||
|
||||
const ALLOWED_RUNTIMES = ['nodejs', 'experimental-edge'];
|
||||
|
||||
const require_ = eval('require');
|
||||
|
||||
const tscPath = resolve(dirname(require_.resolve('typescript')), '../bin/tsc');
|
||||
@@ -187,7 +195,10 @@ async function compile(
|
||||
if (cached === null) return null;
|
||||
try {
|
||||
let source: string | Buffer = readFileSync(fsPath);
|
||||
if (fsPath.endsWith('.ts') || fsPath.endsWith('.tsx')) {
|
||||
if (
|
||||
(fsPath.endsWith('.ts') && !fsPath.endsWith('.d.ts')) ||
|
||||
fsPath.endsWith('.tsx')
|
||||
) {
|
||||
source = compileTypeScript(fsPath, source.toString());
|
||||
}
|
||||
const { mode } = lstatSync(fsPath);
|
||||
@@ -362,20 +373,52 @@ export const build: BuildV3 = async ({
|
||||
);
|
||||
debug(`Trace complete [${Date.now() - traceTime}ms]`);
|
||||
|
||||
const shouldAddHelpers = !(
|
||||
config.helpers === false || process.env.NODEJS_HELPERS === '0'
|
||||
);
|
||||
const project = new Project();
|
||||
const staticConfig = getConfig(project, entrypointPath);
|
||||
|
||||
const lambda = new NodejsLambda({
|
||||
files: preparedFiles,
|
||||
handler: renameTStoJS(relative(baseDir, entrypointPath)),
|
||||
runtime: nodeVersion.runtime,
|
||||
shouldAddHelpers,
|
||||
shouldAddSourcemapSupport,
|
||||
awsLambdaHandler,
|
||||
});
|
||||
let output: BuildResultV3['output'] | undefined;
|
||||
const handler = renameTStoJS(relative(baseDir, entrypointPath));
|
||||
|
||||
return { output: lambda };
|
||||
if (staticConfig?.runtime) {
|
||||
if (!ALLOWED_RUNTIMES.includes(staticConfig.runtime)) {
|
||||
throw new Error(
|
||||
`Unsupported "runtime" property in \`config\`: ${JSON.stringify(
|
||||
staticConfig.runtime
|
||||
)} (must be one of: ${JSON.stringify(ALLOWED_RUNTIMES)})`
|
||||
);
|
||||
}
|
||||
if (staticConfig.runtime === 'experimental-edge') {
|
||||
const name = config.zeroConfig
|
||||
? handler.substring(0, handler.length - 3)
|
||||
: handler;
|
||||
output = new EdgeFunction({
|
||||
entrypoint: handler,
|
||||
files: preparedFiles,
|
||||
|
||||
// TODO: remove - these two properties should not be required
|
||||
name,
|
||||
deploymentTarget: 'v8-worker',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!output) {
|
||||
// "nodejs" runtime is the default
|
||||
const shouldAddHelpers = !(
|
||||
config.helpers === false || process.env.NODEJS_HELPERS === '0'
|
||||
);
|
||||
|
||||
output = new NodejsLambda({
|
||||
files: preparedFiles,
|
||||
handler,
|
||||
runtime: nodeVersion.runtime,
|
||||
shouldAddHelpers,
|
||||
shouldAddSourcemapSupport,
|
||||
awsLambdaHandler,
|
||||
});
|
||||
}
|
||||
|
||||
return { output };
|
||||
};
|
||||
|
||||
export const prepareCache: PrepareCache = ({ repoRootPath, workPath }) => {
|
||||
|
||||
9
packages/node/test/fixtures/05-ts-declaration-asset/index.ts
vendored
Normal file
9
packages/node/test/fixtures/05-ts-declaration-asset/index.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { join } from 'path';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
const filePath = join(__dirname, 'test.d.ts');
|
||||
const fileContent = readFileSync(filePath, 'utf8');
|
||||
|
||||
export default function handler(_req: any, res: any) {
|
||||
res.end(fileContent);
|
||||
}
|
||||
6
packages/node/test/fixtures/05-ts-declaration-asset/package.json
vendored
Normal file
6
packages/node/test/fixtures/05-ts-declaration-asset/package.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^16.0.0"
|
||||
}
|
||||
}
|
||||
3
packages/node/test/fixtures/05-ts-declaration-asset/test.d.ts
vendored
Normal file
3
packages/node/test/fixtures/05-ts-declaration-asset/test.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare namespace Test {
|
||||
// example .d.ts file
|
||||
}
|
||||
10
packages/node/test/fixtures/05-ts-declaration-asset/vercel.json
vendored
Normal file
10
packages/node/test/fixtures/05-ts-declaration-asset/vercel.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [{ "src": "index.ts", "use": "@vercel/node" }],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/",
|
||||
"mustContain": "declare namespace Test"
|
||||
}
|
||||
]
|
||||
}
|
||||
7
packages/node/test/fixtures/61-edge-function/api/edge.js
vendored
Normal file
7
packages/node/test/fixtures/61-edge-function/api/edge.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export const config = {
|
||||
runtime: 'experimental-edge',
|
||||
};
|
||||
|
||||
export default req => {
|
||||
return new Response(`RANDOMNESS_PLACEHOLDER:edge`);
|
||||
};
|
||||
9
packages/node/test/fixtures/61-edge-function/vercel.json
vendored
Normal file
9
packages/node/test/fixtures/61-edge-function/vercel.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"builds": [{ "src": "api/**/*.js", "use": "@vercel/node" }],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/api/edge.js",
|
||||
"mustContain": "RANDOMNESS_PLACEHOLDER:edge"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/python",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"main": "./dist/index.js",
|
||||
"license": "MIT",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
||||
@@ -23,7 +23,7 @@
|
||||
"devDependencies": {
|
||||
"@types/execa": "^0.9.0",
|
||||
"@types/jest": "27.4.1",
|
||||
"@vercel/build-utils": "4.0.0",
|
||||
"@vercel/build-utils": "4.1.0",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"execa": "^1.0.0",
|
||||
"typescript": "4.3.4"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/redwood",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"main": "./dist/index.js",
|
||||
"license": "MIT",
|
||||
"homepage": "https://vercel.com/docs",
|
||||
@@ -28,6 +28,6 @@
|
||||
"@types/aws-lambda": "8.10.19",
|
||||
"@types/node": "*",
|
||||
"@types/semver": "6.0.0",
|
||||
"@vercel/build-utils": "4.0.0"
|
||||
"@vercel/build-utils": "4.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/remix",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"homepage": "https://vercel.com/docs",
|
||||
@@ -27,7 +27,7 @@
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/node": "*",
|
||||
"@vercel/build-utils": "4.0.0",
|
||||
"@vercel/build-utils": "4.1.0",
|
||||
"typescript": "4.6.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@vercel/ruby",
|
||||
"author": "Nathan Cahill <nathan@nathancahill.com>",
|
||||
"version": "1.3.8",
|
||||
"version": "1.3.9",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",
|
||||
@@ -23,7 +23,7 @@
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "8.0.0",
|
||||
"@types/semver": "6.0.0",
|
||||
"@vercel/build-utils": "4.0.0",
|
||||
"@vercel/build-utils": "4.1.0",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"execa": "2.0.4",
|
||||
"fs-extra": "^7.0.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/static-build",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/build-step",
|
||||
@@ -37,7 +37,7 @@
|
||||
"@types/ms": "0.7.31",
|
||||
"@types/node-fetch": "2.5.4",
|
||||
"@types/promise-timeout": "1.3.0",
|
||||
"@vercel/build-utils": "4.0.0",
|
||||
"@vercel/build-utils": "4.1.0",
|
||||
"@vercel/frameworks": "1.0.1",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@vercel/routing-utils": "1.13.4",
|
||||
|
||||
@@ -50,6 +50,11 @@ export function createBuildOutput(
|
||||
else if (framework) buildCommandName = framework.name;
|
||||
else buildCommandName = 'the "build" script';
|
||||
|
||||
if (meta.isDev) {
|
||||
throw new Error(
|
||||
`Detected Build Output v3 from ${buildCommandName}, but it is not supported for \`vercel dev\`. Please set the Development Command in your Project Settings.`
|
||||
);
|
||||
}
|
||||
throw new Error(
|
||||
`Detected Build Output v3 from ${buildCommandName}, but this Deployment is not using \`vercel build\`.\nPlease set the \`ENABLE_VC_BUILD=1\` environment variable.`
|
||||
);
|
||||
|
||||
32
packages/static-build/test/build.test.ts
vendored
32
packages/static-build/test/build.test.ts
vendored
@@ -17,6 +17,7 @@ describe('build()', () => {
|
||||
const buildResult = await build({
|
||||
files: {},
|
||||
entrypoint: 'package.json',
|
||||
repoRootPath: workPath,
|
||||
workPath,
|
||||
config: {},
|
||||
meta: {
|
||||
@@ -46,6 +47,7 @@ describe('build()', () => {
|
||||
const buildResult = await build({
|
||||
files: {},
|
||||
entrypoint: 'package.json',
|
||||
repoRootPath: workPath,
|
||||
workPath,
|
||||
config: {},
|
||||
meta: {
|
||||
@@ -76,6 +78,7 @@ describe('build()', () => {
|
||||
const buildResult = await build({
|
||||
files: {},
|
||||
entrypoint: 'package.json',
|
||||
repoRootPath: workPath,
|
||||
workPath,
|
||||
config: {},
|
||||
meta: {
|
||||
@@ -105,6 +108,7 @@ describe('build()', () => {
|
||||
const buildResult = await build({
|
||||
files: {},
|
||||
entrypoint: 'package.json',
|
||||
repoRootPath: workPath,
|
||||
workPath,
|
||||
config: {},
|
||||
meta: {
|
||||
@@ -132,6 +136,7 @@ describe('build()', () => {
|
||||
await build({
|
||||
files: {},
|
||||
entrypoint: 'package.json',
|
||||
repoRootPath: workPath,
|
||||
workPath,
|
||||
config: {},
|
||||
meta: {
|
||||
@@ -145,5 +150,32 @@ describe('build()', () => {
|
||||
`Detected Build Output v3 from the "build" script, but this Deployment is not using \`vercel build\`.\nPlease set the \`ENABLE_VC_BUILD=1\` environment variable.`
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw an Error when `vercel dev` is used with `@vercel/static-build`', async () => {
|
||||
let err;
|
||||
const workPath = path.join(
|
||||
__dirname,
|
||||
'build-fixtures',
|
||||
'09-build-output-v3'
|
||||
);
|
||||
try {
|
||||
await build({
|
||||
files: {},
|
||||
entrypoint: 'package.json',
|
||||
repoRootPath: workPath,
|
||||
workPath,
|
||||
config: {},
|
||||
meta: {
|
||||
skipDownload: true,
|
||||
isDev: true,
|
||||
},
|
||||
});
|
||||
} catch (_err: any) {
|
||||
err = _err;
|
||||
}
|
||||
expect(err.message).toEqual(
|
||||
`Detected Build Output v3 from the "build" script, but it is not supported for \`vercel dev\`. Please set the Development Command in your Project Settings.`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/static-config",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"repository": {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { validate } from './validation';
|
||||
export const BaseFunctionConfigSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
use: { type: 'string' },
|
||||
runtime: { type: 'string' },
|
||||
memory: { type: 'number' },
|
||||
maxDuration: { type: 'number' },
|
||||
regions: {
|
||||
|
||||
2
packages/static-config/test/fixtures/deno.ts
vendored
2
packages/static-config/test/fixtures/deno.ts
vendored
@@ -2,7 +2,7 @@ import ms from 'https://denopkg.com/TooTallNate/ms';
|
||||
import { readerFromStreamReader } from 'https://deno.land/std@0.107.0/io/streams.ts';
|
||||
|
||||
export const config = {
|
||||
use: 'deno',
|
||||
runtime: 'deno',
|
||||
location: 'https://example.com/page',
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export const config = {
|
||||
use: 0,
|
||||
runtime: 0,
|
||||
};
|
||||
|
||||
2
packages/static-config/test/fixtures/node.js
vendored
2
packages/static-config/test/fixtures/node.js
vendored
@@ -1,7 +1,7 @@
|
||||
import fs from 'fs';
|
||||
|
||||
export const config = {
|
||||
use: 'node',
|
||||
runtime: 'nodejs',
|
||||
memory: 1024,
|
||||
};
|
||||
|
||||
|
||||
4
packages/static-config/test/index.test.ts
vendored
4
packages/static-config/test/index.test.ts
vendored
@@ -10,7 +10,7 @@ describe('getConfig()', () => {
|
||||
expect(config).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"memory": 1024,
|
||||
"use": "node",
|
||||
"runtime": "nodejs",
|
||||
}
|
||||
`);
|
||||
});
|
||||
@@ -27,7 +27,7 @@ describe('getConfig()', () => {
|
||||
expect(config).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"location": "https://example.com/page",
|
||||
"use": "deno",
|
||||
"runtime": "deno",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
4
packages/static-config/test/swc.test.ts
vendored
4
packages/static-config/test/swc.test.ts
vendored
@@ -57,7 +57,7 @@ describe('getConfig for swc', () => {
|
||||
expect(config).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"memory": 1024,
|
||||
"use": "node",
|
||||
"runtime": "nodejs",
|
||||
}
|
||||
`);
|
||||
});
|
||||
@@ -73,7 +73,7 @@ describe('getConfig for swc', () => {
|
||||
expect(config).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"location": "https://example.com/page",
|
||||
"use": "deno",
|
||||
"runtime": "deno",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
26
yarn.lock
26
yarn.lock
@@ -2426,6 +2426,14 @@
|
||||
"@types/minimatch" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/glob@7.2.0":
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb"
|
||||
integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==
|
||||
dependencies:
|
||||
"@types/minimatch" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/glob@^7.1.1":
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.2.tgz#06ca26521353a545d94a0adc74f38a59d232c987"
|
||||
@@ -6641,17 +6649,16 @@ glob@7.1.2:
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@7.1.3:
|
||||
version "7.1.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
|
||||
integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
|
||||
glob@8.0.3:
|
||||
version "8.0.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-8.0.3.tgz#415c6eb2deed9e502c68fa44a272e6da6eeca42e"
|
||||
integrity sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
minimatch "^5.0.1"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^7.0.3, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4:
|
||||
version "7.1.6"
|
||||
@@ -9138,6 +9145,13 @@ minimatch@5.0.1:
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minimatch@^5.0.1:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7"
|
||||
integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minimist-options@^3.0.1:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954"
|
||||
|
||||
Reference in New Issue
Block a user