Skip to content

Commit

Permalink
Merge branch 'main' into feat/go-1.18
Browse files Browse the repository at this point in the history
  • Loading branch information
sorcererxw committed Apr 14, 2022
2 parents bb887f7 + 9225246 commit c3bc045
Show file tree
Hide file tree
Showing 39 changed files with 480 additions and 217 deletions.
3 changes: 2 additions & 1 deletion .vercelignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
!.yarnrc
!yarn.lock
!package.json
!turbo.json

# api
!api/
Expand All @@ -14,4 +15,4 @@
# packages
!packages/
!packages/frameworks
!packages/frameworks/**
!packages/frameworks/**
2 changes: 1 addition & 1 deletion errors/domain-verification.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ If you would not like to verify your domain, you can remove it from your account

#### Resources

- [Vercel Custom Domains Documentation](https://vercel.com/docs/v2/custom-domains)
- [Vercel Custom Domains Documentation](https://vercel.com/docs/concepts/projects/custom-domains)
4 changes: 2 additions & 2 deletions errors/missing-env-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#### Why This Error Occurred

You ran `vercel dev` inside a project that contains a `vercel.json` file with `env` or `build.env` properties that use [Vercel Secrets](https://vercel.com/docs/v2/build-step#environment-variables).
You ran `vercel dev` inside a project that contains a `vercel.json` file with `env` or `build.env` properties that use [Vercel Secrets](https://vercel.com/docs/concepts/projects/environment-variables).

In order to use environment variables in your project locally that have values defined using the Vercel Secrets format (e.g. `@my-secret-value`), you will need to provide the value as an environment variable using a `.env`.

Expand All @@ -24,4 +24,4 @@ TEST=value

In the above example, `TEST` represents the name of the environment variable and `value` its value.

For more information on Environment Variables in development, [see the documentation](https://vercel.com/docs/v2/build-step#environment-variables).
For more information on Environment Variables in development, [see the documentation](https://vercel.com/docs/concepts/projects/environment-variables).
15 changes: 1 addition & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,6 @@
"dependencies": {
"lerna": "3.16.4"
},
"turbo": {
"baseBranch": "origin/main",
"pipeline": {
"build": {
"dependsOn": [
"^build"
],
"outputs": [
"dist/**"
]
}
}
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "4.28.0",
"@typescript-eslint/parser": "4.28.0",
Expand All @@ -44,7 +31,7 @@
"prettier": "2.3.1",
"ts-eager": "2.0.2",
"ts-jest": "27.0.4",
"turbo": "1.1.9"
"turbo": "1.2.2"
},
"scripts": {
"lerna": "lerna",
Expand Down
4 changes: 2 additions & 2 deletions packages/build-utils/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vercel/build-utils",
"version": "2.15.1-canary.0",
"version": "2.15.2-canary.1",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",
Expand Down Expand Up @@ -30,7 +30,7 @@
"@types/node-fetch": "^2.1.6",
"@types/semver": "6.0.0",
"@types/yazl": "^2.4.1",
"@vercel/frameworks": "0.7.1-canary.0",
"@vercel/frameworks": "0.7.1",
"@vercel/ncc": "0.24.0",
"aggregate-error": "3.0.1",
"async-retry": "1.2.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/build-utils/src/detect-builders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ function getMissingBuildScriptError() {
code: 'missing_build_script',
message:
'Your `package.json` file is missing a `build` property inside the `scripts` property.' +
'\nLearn More: https://vercel.com/docs/v2/platform/frequently-asked-questions#missing-build-script',
'\nLearn More: https://vercel.link/missing-build-script',
};
}

Expand Down
116 changes: 79 additions & 37 deletions packages/build-utils/src/fs/run-user-scripts.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
import assert from 'assert';
import fs from 'fs-extra';
import path from 'path';
import debug from '../debug';
import Sema from 'async-sema';
import spawn from 'cross-spawn';
import { SpawnOptions } from 'child_process';
import { deprecate } from 'util';
import debug from '../debug';
import { NowBuildError } from '../errors';
import { Meta, PackageJson, NodeVersion, Config } from '../types';
import { getSupportedNodeVersion, getLatestNodeVersion } from './node-version';
import { readConfigFile } from './read-config-file';

// Only allow one `runNpmInstall()` invocation to run concurrently
const runNpmInstallSema = new Sema(1);

export type CliType = 'yarn' | 'npm' | 'pnpm';

export interface ScanParentDirsResult {
/**
* "yarn", "npm", or "pnpm" depending on the presence of lockfiles.
*/
cliType: CliType;
/**
* The file path of found `package.json` file, or `undefined` if none was
* found.
*/
packageJsonPath?: string;
/**
* The contents of found `package.json` file, when the `readPackageJson`
* option is enabled.
Expand Down Expand Up @@ -237,12 +246,13 @@ export async function scanParentDirs(

let cliType: CliType = 'yarn';
let packageJson: PackageJson | undefined;
let packageJsonPath: string | undefined;
let currentDestPath = destPath;
let lockfileVersion: number | undefined;

// eslint-disable-next-line no-constant-condition
while (true) {
const packageJsonPath = path.join(currentDestPath, 'package.json');
packageJsonPath = path.join(currentDestPath, 'package.json');
// eslint-disable-next-line no-await-in-loop
if (await fs.pathExists(packageJsonPath)) {
// Only read the contents of the *first* `package.json` file found,
Expand Down Expand Up @@ -293,7 +303,7 @@ export async function scanParentDirs(
currentDestPath = newDestPath;
}

return { cliType, packageJson, lockfileVersion };
return { cliType, packageJson, lockfileVersion, packageJsonPath };
}

export async function walkParentDirs({
Expand All @@ -319,55 +329,87 @@ export async function walkParentDirs({
return null;
}

function isSet<T>(v: any): v is Set<T> {
return v?.constructor?.name === 'Set';
}

export async function runNpmInstall(
destPath: string,
args: string[] = [],
spawnOpts?: SpawnOptions,
meta?: Meta,
nodeVersion?: NodeVersion
) {
): Promise<boolean> {
if (meta?.isDev) {
debug('Skipping dependency installation because dev mode is enabled');
return;
return false;
}

assert(path.isAbsolute(destPath));
debug(`Installing to ${destPath}`);

const { cliType, lockfileVersion } = await scanParentDirs(destPath);
const opts: SpawnOptionsExtended = { cwd: destPath, ...spawnOpts };
const env = opts.env ? { ...opts.env } : { ...process.env };
delete env.NODE_ENV;
opts.env = getEnvForPackageManager({
cliType,
lockfileVersion,
nodeVersion,
env,
});
let commandArgs: string[];
try {
await runNpmInstallSema.acquire();
const { cliType, packageJsonPath, lockfileVersion } = await scanParentDirs(
destPath
);

// Only allow `runNpmInstall()` to run once per `package.json`
// when doing a default install (no additional args)
if (meta && packageJsonPath && args.length === 0) {
if (!isSet<string>(meta.runNpmInstallSet)) {
meta.runNpmInstallSet = new Set<string>();
}
if (isSet<string>(meta.runNpmInstallSet)) {
if (meta.runNpmInstallSet.has(packageJsonPath)) {
return false;
} else {
meta.runNpmInstallSet.add(packageJsonPath);
}
}
}

if (cliType === 'npm') {
opts.prettyCommand = 'npm install';
commandArgs = args
.filter(a => a !== '--prefer-offline')
.concat(['install', '--no-audit', '--unsafe-perm']);
} else if (cliType === 'pnpm') {
// PNPM's install command is similar to NPM's but without the audit nonsense
// @see options https://pnpm.io/cli/install
opts.prettyCommand = 'pnpm install';
commandArgs = args
.filter(a => a !== '--prefer-offline')
.concat(['install', '--unsafe-perm']);
} else {
opts.prettyCommand = 'yarn install';
commandArgs = ['install', ...args];
}
const installTime = Date.now();
console.log('Installing dependencies...');
debug(`Installing to ${destPath}`);

if (process.env.NPM_ONLY_PRODUCTION) {
commandArgs.push('--production');
}
const opts: SpawnOptionsExtended = { cwd: destPath, ...spawnOpts };
const env = opts.env ? { ...opts.env } : { ...process.env };
delete env.NODE_ENV;
opts.env = getEnvForPackageManager({
cliType,
lockfileVersion,
nodeVersion,
env,
});
let commandArgs: string[];

if (cliType === 'npm') {
opts.prettyCommand = 'npm install';
commandArgs = args
.filter(a => a !== '--prefer-offline')
.concat(['install', '--no-audit', '--unsafe-perm']);
} else if (cliType === 'pnpm') {
// PNPM's install command is similar to NPM's but without the audit nonsense
// @see options https://pnpm.io/cli/install
opts.prettyCommand = 'pnpm install';
commandArgs = args
.filter(a => a !== '--prefer-offline')
.concat(['install', '--unsafe-perm']);
} else {
opts.prettyCommand = 'yarn install';
commandArgs = ['install', ...args];
}

return spawnAsync(cliType, commandArgs, opts);
if (process.env.NPM_ONLY_PRODUCTION) {
commandArgs.push('--production');
}

await spawnAsync(cliType, commandArgs, opts);
debug(`Install complete [${Date.now() - installTime}ms]`);
return true;
} finally {
runNpmInstallSema.release();
}
}

export function getEnvForPackageManager({
Expand Down
26 changes: 25 additions & 1 deletion packages/build-utils/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,29 @@ export interface Images {
formats?: ImageFormat[];
}

export interface BuildResultV2 {
/**
* If a Builder ends up creating filesystem outputs conforming to
* the Build Output API, then the Builder should return this type.
*/
export interface BuildResultBuildOutput {
/**
* Version number of the Build Output API that was created.
* Currently only `3` is a valid value.
* @example 3
*/
buildOutputVersion: 3;
/**
* Filesystem path to the Build Output directory.
* @example "/path/to/.vercel/output"
*/
buildOutputPath: string;
}

/**
* When a Builder implements `version: 2`, the `build()` function is expected
* to return this type.
*/
export interface BuildResultV2Typical {
// TODO: use proper `Route` type from `routing-utils` (perhaps move types to a common package)
routes?: any[];
images?: Images;
Expand All @@ -369,6 +391,8 @@ export interface BuildResultV2 {
}>;
}

export type BuildResultV2 = BuildResultV2Typical | BuildResultBuildOutput;

export interface BuildResultV3 {
output: Lambda;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


37 changes: 37 additions & 0 deletions packages/build-utils/test/unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
runPackageJsonScript,
scanParentDirs,
FileBlob,
Meta,
} from '../src';

async function expectBuilderError(promise: Promise<any>, pattern: string) {
Expand Down Expand Up @@ -413,3 +414,39 @@ it('should detect pnpm Workspaces', async () => {
expect(result.cliType).toEqual('pnpm');
expect(result.lockfileVersion).toEqual(5.3);
});

it('should only invoke `runNpmInstall()` once per `package.json` file (serial)', async () => {
const meta: Meta = {};
const fixture = path.join(__dirname, 'fixtures', '02-zero-config-api');
const apiDir = path.join(fixture, 'api');
const run1 = await runNpmInstall(apiDir, [], undefined, meta);
expect(run1).toEqual(true);
expect(
(meta.runNpmInstallSet as Set<string>).has(
path.join(fixture, 'package.json')
)
).toEqual(true);
const run2 = await runNpmInstall(apiDir, [], undefined, meta);
expect(run2).toEqual(false);
const run3 = await runNpmInstall(fixture, [], undefined, meta);
expect(run3).toEqual(false);
});

it('should only invoke `runNpmInstall()` once per `package.json` file (parallel)', async () => {
const meta: Meta = {};
const fixture = path.join(__dirname, 'fixtures', '02-zero-config-api');
const apiDir = path.join(fixture, 'api');
const [run1, run2, run3] = await Promise.all([
runNpmInstall(apiDir, [], undefined, meta),
runNpmInstall(apiDir, [], undefined, meta),
runNpmInstall(fixture, [], undefined, meta),
]);
expect(run1).toEqual(true);
expect(run2).toEqual(false);
expect(run3).toEqual(false);
expect(
(meta.runNpmInstallSet as Set<string>).has(
path.join(fixture, 'package.json')
)
).toEqual(true);
});
Loading

0 comments on commit c3bc045

Please sign in to comment.