@vercel/build-utils 2.15.2-canary.0 → 2.15.2-canary.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -40,6 +40,9 @@ function getDiscontinuedNodeVersions() {
40
40
  exports.getDiscontinuedNodeVersions = getDiscontinuedNodeVersions;
41
41
  async function getSupportedNodeVersion(engineRange, isAuto = false) {
42
42
  let selection = getLatestNodeVersion();
43
+ if (process.env.ENABLE_EXPERIMENTAL_NODE16 === '1') {
44
+ return { major: 16, range: '16.x', runtime: 'nodejs16.x' };
45
+ }
43
46
  if (engineRange) {
44
47
  const found = semver_1.validRange(engineRange) &&
45
48
  allOptions.some(o => {
@@ -7,6 +7,11 @@ export interface ScanParentDirsResult {
7
7
  * "yarn", "npm", or "pnpm" depending on the presence of lockfiles.
8
8
  */
9
9
  cliType: CliType;
10
+ /**
11
+ * The file path of found `package.json` file, or `undefined` if none was
12
+ * found.
13
+ */
14
+ packageJsonPath?: string;
10
15
  /**
11
16
  * The contents of found `package.json` file, when the `readPackageJson`
12
17
  * option is enabled.
@@ -56,7 +61,7 @@ export declare function getSpawnOptions(meta: Meta, nodeVersion: NodeVersion): S
56
61
  export declare function getNodeVersion(destPath: string, _nodeVersion?: string, config?: Config, meta?: Meta): Promise<NodeVersion>;
57
62
  export declare function scanParentDirs(destPath: string, readPackageJson?: boolean): Promise<ScanParentDirsResult>;
58
63
  export declare function walkParentDirs({ base, start, filename, }: WalkParentDirsProps): Promise<string | null>;
59
- export declare function runNpmInstall(destPath: string, args?: string[], spawnOpts?: SpawnOptions, meta?: Meta, nodeVersion?: NodeVersion): Promise<void>;
64
+ export declare function runNpmInstall(destPath: string, args?: string[], spawnOpts?: SpawnOptions, meta?: Meta, nodeVersion?: NodeVersion): Promise<boolean>;
60
65
  export declare function getEnvForPackageManager({ cliType, lockfileVersion, nodeVersion, env, }: {
61
66
  cliType: CliType;
62
67
  lockfileVersion: number | undefined;
@@ -7,12 +7,15 @@ exports.installDependencies = exports.getScriptName = exports.runPipInstall = ex
7
7
  const assert_1 = __importDefault(require("assert"));
8
8
  const fs_extra_1 = __importDefault(require("fs-extra"));
9
9
  const path_1 = __importDefault(require("path"));
10
- const debug_1 = __importDefault(require("../debug"));
10
+ const async_sema_1 = __importDefault(require("async-sema"));
11
11
  const cross_spawn_1 = __importDefault(require("cross-spawn"));
12
12
  const util_1 = require("util");
13
+ const debug_1 = __importDefault(require("../debug"));
13
14
  const errors_1 = require("../errors");
14
15
  const node_version_1 = require("./node-version");
15
16
  const read_config_file_1 = require("./read-config-file");
17
+ // Only allow one `runNpmInstall()` invocation to run concurrently
18
+ const runNpmInstallSema = new async_sema_1.default(1);
16
19
  function spawnAsync(command, args, opts = {}) {
17
20
  return new Promise((resolve, reject) => {
18
21
  const stderrLogs = [];
@@ -151,11 +154,12 @@ async function scanParentDirs(destPath, readPackageJson = false) {
151
154
  assert_1.default(path_1.default.isAbsolute(destPath));
152
155
  let cliType = 'yarn';
153
156
  let packageJson;
157
+ let packageJsonPath;
154
158
  let currentDestPath = destPath;
155
159
  let lockfileVersion;
156
160
  // eslint-disable-next-line no-constant-condition
157
161
  while (true) {
158
- const packageJsonPath = path_1.default.join(currentDestPath, 'package.json');
162
+ packageJsonPath = path_1.default.join(currentDestPath, 'package.json');
159
163
  // eslint-disable-next-line no-await-in-loop
160
164
  if (await fs_extra_1.default.pathExists(packageJsonPath)) {
161
165
  // Only read the contents of the *first* `package.json` file found,
@@ -199,7 +203,7 @@ async function scanParentDirs(destPath, readPackageJson = false) {
199
203
  break;
200
204
  currentDestPath = newDestPath;
201
205
  }
202
- return { cliType, packageJson, lockfileVersion };
206
+ return { cliType, packageJson, lockfileVersion, packageJsonPath };
203
207
  }
204
208
  exports.scanParentDirs = scanParentDirs;
205
209
  async function walkParentDirs({ base, start, filename, }) {
@@ -217,46 +221,75 @@ async function walkParentDirs({ base, start, filename, }) {
217
221
  return null;
218
222
  }
219
223
  exports.walkParentDirs = walkParentDirs;
224
+ function isSet(v) {
225
+ var _a;
226
+ return ((_a = v === null || v === void 0 ? void 0 : v.constructor) === null || _a === void 0 ? void 0 : _a.name) === 'Set';
227
+ }
220
228
  async function runNpmInstall(destPath, args = [], spawnOpts, meta, nodeVersion) {
221
229
  if (meta === null || meta === void 0 ? void 0 : meta.isDev) {
222
230
  debug_1.default('Skipping dependency installation because dev mode is enabled');
223
- return;
231
+ return false;
224
232
  }
225
233
  assert_1.default(path_1.default.isAbsolute(destPath));
226
- debug_1.default(`Installing to ${destPath}`);
227
- const { cliType, lockfileVersion } = await scanParentDirs(destPath);
228
- const opts = { cwd: destPath, ...spawnOpts };
229
- const env = opts.env ? { ...opts.env } : { ...process.env };
230
- delete env.NODE_ENV;
231
- opts.env = getEnvForPackageManager({
232
- cliType,
233
- lockfileVersion,
234
- nodeVersion,
235
- env,
236
- });
237
- let commandArgs;
238
- if (cliType === 'npm') {
239
- opts.prettyCommand = 'npm install';
240
- commandArgs = args
241
- .filter(a => a !== '--prefer-offline')
242
- .concat(['install', '--no-audit', '--unsafe-perm']);
243
- }
244
- else if (cliType === 'pnpm') {
245
- // PNPM's install command is similar to NPM's but without the audit nonsense
246
- // @see options https://pnpm.io/cli/install
247
- opts.prettyCommand = 'pnpm install';
248
- commandArgs = args
249
- .filter(a => a !== '--prefer-offline')
250
- .concat(['install', '--unsafe-perm']);
251
- }
252
- else {
253
- opts.prettyCommand = 'yarn install';
254
- commandArgs = ['install', ...args];
234
+ try {
235
+ await runNpmInstallSema.acquire();
236
+ const { cliType, packageJsonPath, lockfileVersion } = await scanParentDirs(destPath);
237
+ // Only allow `runNpmInstall()` to run once per `package.json`
238
+ // when doing a default install (no additional args)
239
+ if (meta && packageJsonPath && args.length === 0) {
240
+ if (!isSet(meta.runNpmInstallSet)) {
241
+ meta.runNpmInstallSet = new Set();
242
+ }
243
+ if (isSet(meta.runNpmInstallSet)) {
244
+ if (meta.runNpmInstallSet.has(packageJsonPath)) {
245
+ return false;
246
+ }
247
+ else {
248
+ meta.runNpmInstallSet.add(packageJsonPath);
249
+ }
250
+ }
251
+ }
252
+ const installTime = Date.now();
253
+ console.log('Installing dependencies...');
254
+ debug_1.default(`Installing to ${destPath}`);
255
+ const opts = { cwd: destPath, ...spawnOpts };
256
+ const env = opts.env ? { ...opts.env } : { ...process.env };
257
+ delete env.NODE_ENV;
258
+ opts.env = getEnvForPackageManager({
259
+ cliType,
260
+ lockfileVersion,
261
+ nodeVersion,
262
+ env,
263
+ });
264
+ let commandArgs;
265
+ if (cliType === 'npm') {
266
+ opts.prettyCommand = 'npm install';
267
+ commandArgs = args
268
+ .filter(a => a !== '--prefer-offline')
269
+ .concat(['install', '--no-audit', '--unsafe-perm']);
270
+ }
271
+ else if (cliType === 'pnpm') {
272
+ // PNPM's install command is similar to NPM's but without the audit nonsense
273
+ // @see options https://pnpm.io/cli/install
274
+ opts.prettyCommand = 'pnpm install';
275
+ commandArgs = args
276
+ .filter(a => a !== '--prefer-offline')
277
+ .concat(['install', '--unsafe-perm']);
278
+ }
279
+ else {
280
+ opts.prettyCommand = 'yarn install';
281
+ commandArgs = ['install', ...args];
282
+ }
283
+ if (process.env.NPM_ONLY_PRODUCTION) {
284
+ commandArgs.push('--production');
285
+ }
286
+ await spawnAsync(cliType, commandArgs, opts);
287
+ debug_1.default(`Install complete [${Date.now() - installTime}ms]`);
288
+ return true;
255
289
  }
256
- if (process.env.NPM_ONLY_PRODUCTION) {
257
- commandArgs.push('--production');
290
+ finally {
291
+ runNpmInstallSema.release();
258
292
  }
259
- return spawnAsync(cliType, commandArgs, opts);
260
293
  }
261
294
  exports.runNpmInstall = runNpmInstall;
262
295
  function getEnvForPackageManager({ cliType, lockfileVersion, nodeVersion, env, }) {
package/dist/index.js CHANGED
@@ -26617,6 +26617,7 @@ exports.frameworks = [
26617
26617
  slug: 'nextjs',
26618
26618
  demo: 'https://nextjs-template.vercel.app',
26619
26619
  logo: 'https://raw.githubusercontent.com/vercel/vercel/main/packages/frameworks/logos/next.svg',
26620
+ darkModeLogo: 'https://raw.githubusercontent.com/vercel/vercel/main/packages/frameworks/logos/next-dark.svg',
26620
26621
  screenshot: 'https://assets.vercel.com/image/upload/v1647366075/front/import/nextjs.png',
26621
26622
  tagline: 'Next.js makes you productive with React instantly — whether you want to build static or dynamic sites.',
26622
26623
  description: 'A Next.js app and a Serverless Function API.',
@@ -34483,6 +34484,9 @@ function getDiscontinuedNodeVersions() {
34483
34484
  exports.getDiscontinuedNodeVersions = getDiscontinuedNodeVersions;
34484
34485
  async function getSupportedNodeVersion(engineRange, isAuto = false) {
34485
34486
  let selection = getLatestNodeVersion();
34487
+ if (process.env.ENABLE_EXPERIMENTAL_NODE16 === '1') {
34488
+ return { major: 16, range: '16.x', runtime: 'nodejs16.x' };
34489
+ }
34486
34490
  if (engineRange) {
34487
34491
  const found = semver_1.validRange(engineRange) &&
34488
34492
  allOptions.some(o => {
@@ -34621,12 +34625,15 @@ exports.installDependencies = exports.getScriptName = exports.runPipInstall = ex
34621
34625
  const assert_1 = __importDefault(__webpack_require__(2357));
34622
34626
  const fs_extra_1 = __importDefault(__webpack_require__(5392));
34623
34627
  const path_1 = __importDefault(__webpack_require__(5622));
34624
- const debug_1 = __importDefault(__webpack_require__(1868));
34628
+ const async_sema_1 = __importDefault(__webpack_require__(5758));
34625
34629
  const cross_spawn_1 = __importDefault(__webpack_require__(7618));
34626
34630
  const util_1 = __webpack_require__(1669);
34631
+ const debug_1 = __importDefault(__webpack_require__(1868));
34627
34632
  const errors_1 = __webpack_require__(3983);
34628
34633
  const node_version_1 = __webpack_require__(7903);
34629
34634
  const read_config_file_1 = __webpack_require__(7792);
34635
+ // Only allow one `runNpmInstall()` invocation to run concurrently
34636
+ const runNpmInstallSema = new async_sema_1.default(1);
34630
34637
  function spawnAsync(command, args, opts = {}) {
34631
34638
  return new Promise((resolve, reject) => {
34632
34639
  const stderrLogs = [];
@@ -34765,11 +34772,12 @@ async function scanParentDirs(destPath, readPackageJson = false) {
34765
34772
  assert_1.default(path_1.default.isAbsolute(destPath));
34766
34773
  let cliType = 'yarn';
34767
34774
  let packageJson;
34775
+ let packageJsonPath;
34768
34776
  let currentDestPath = destPath;
34769
34777
  let lockfileVersion;
34770
34778
  // eslint-disable-next-line no-constant-condition
34771
34779
  while (true) {
34772
- const packageJsonPath = path_1.default.join(currentDestPath, 'package.json');
34780
+ packageJsonPath = path_1.default.join(currentDestPath, 'package.json');
34773
34781
  // eslint-disable-next-line no-await-in-loop
34774
34782
  if (await fs_extra_1.default.pathExists(packageJsonPath)) {
34775
34783
  // Only read the contents of the *first* `package.json` file found,
@@ -34813,7 +34821,7 @@ async function scanParentDirs(destPath, readPackageJson = false) {
34813
34821
  break;
34814
34822
  currentDestPath = newDestPath;
34815
34823
  }
34816
- return { cliType, packageJson, lockfileVersion };
34824
+ return { cliType, packageJson, lockfileVersion, packageJsonPath };
34817
34825
  }
34818
34826
  exports.scanParentDirs = scanParentDirs;
34819
34827
  async function walkParentDirs({ base, start, filename, }) {
@@ -34831,46 +34839,75 @@ async function walkParentDirs({ base, start, filename, }) {
34831
34839
  return null;
34832
34840
  }
34833
34841
  exports.walkParentDirs = walkParentDirs;
34842
+ function isSet(v) {
34843
+ var _a;
34844
+ return ((_a = v === null || v === void 0 ? void 0 : v.constructor) === null || _a === void 0 ? void 0 : _a.name) === 'Set';
34845
+ }
34834
34846
  async function runNpmInstall(destPath, args = [], spawnOpts, meta, nodeVersion) {
34835
34847
  if (meta === null || meta === void 0 ? void 0 : meta.isDev) {
34836
34848
  debug_1.default('Skipping dependency installation because dev mode is enabled');
34837
- return;
34849
+ return false;
34838
34850
  }
34839
34851
  assert_1.default(path_1.default.isAbsolute(destPath));
34840
- debug_1.default(`Installing to ${destPath}`);
34841
- const { cliType, lockfileVersion } = await scanParentDirs(destPath);
34842
- const opts = { cwd: destPath, ...spawnOpts };
34843
- const env = opts.env ? { ...opts.env } : { ...process.env };
34844
- delete env.NODE_ENV;
34845
- opts.env = getEnvForPackageManager({
34846
- cliType,
34847
- lockfileVersion,
34848
- nodeVersion,
34849
- env,
34850
- });
34851
- let commandArgs;
34852
- if (cliType === 'npm') {
34853
- opts.prettyCommand = 'npm install';
34854
- commandArgs = args
34855
- .filter(a => a !== '--prefer-offline')
34856
- .concat(['install', '--no-audit', '--unsafe-perm']);
34857
- }
34858
- else if (cliType === 'pnpm') {
34859
- // PNPM's install command is similar to NPM's but without the audit nonsense
34860
- // @see options https://pnpm.io/cli/install
34861
- opts.prettyCommand = 'pnpm install';
34862
- commandArgs = args
34863
- .filter(a => a !== '--prefer-offline')
34864
- .concat(['install', '--unsafe-perm']);
34865
- }
34866
- else {
34867
- opts.prettyCommand = 'yarn install';
34868
- commandArgs = ['install', ...args];
34852
+ try {
34853
+ await runNpmInstallSema.acquire();
34854
+ const { cliType, packageJsonPath, lockfileVersion } = await scanParentDirs(destPath);
34855
+ // Only allow `runNpmInstall()` to run once per `package.json`
34856
+ // when doing a default install (no additional args)
34857
+ if (meta && packageJsonPath && args.length === 0) {
34858
+ if (!isSet(meta.runNpmInstallSet)) {
34859
+ meta.runNpmInstallSet = new Set();
34860
+ }
34861
+ if (isSet(meta.runNpmInstallSet)) {
34862
+ if (meta.runNpmInstallSet.has(packageJsonPath)) {
34863
+ return false;
34864
+ }
34865
+ else {
34866
+ meta.runNpmInstallSet.add(packageJsonPath);
34867
+ }
34868
+ }
34869
+ }
34870
+ const installTime = Date.now();
34871
+ console.log('Installing dependencies...');
34872
+ debug_1.default(`Installing to ${destPath}`);
34873
+ const opts = { cwd: destPath, ...spawnOpts };
34874
+ const env = opts.env ? { ...opts.env } : { ...process.env };
34875
+ delete env.NODE_ENV;
34876
+ opts.env = getEnvForPackageManager({
34877
+ cliType,
34878
+ lockfileVersion,
34879
+ nodeVersion,
34880
+ env,
34881
+ });
34882
+ let commandArgs;
34883
+ if (cliType === 'npm') {
34884
+ opts.prettyCommand = 'npm install';
34885
+ commandArgs = args
34886
+ .filter(a => a !== '--prefer-offline')
34887
+ .concat(['install', '--no-audit', '--unsafe-perm']);
34888
+ }
34889
+ else if (cliType === 'pnpm') {
34890
+ // PNPM's install command is similar to NPM's but without the audit nonsense
34891
+ // @see options https://pnpm.io/cli/install
34892
+ opts.prettyCommand = 'pnpm install';
34893
+ commandArgs = args
34894
+ .filter(a => a !== '--prefer-offline')
34895
+ .concat(['install', '--unsafe-perm']);
34896
+ }
34897
+ else {
34898
+ opts.prettyCommand = 'yarn install';
34899
+ commandArgs = ['install', ...args];
34900
+ }
34901
+ if (process.env.NPM_ONLY_PRODUCTION) {
34902
+ commandArgs.push('--production');
34903
+ }
34904
+ await spawnAsync(cliType, commandArgs, opts);
34905
+ debug_1.default(`Install complete [${Date.now() - installTime}ms]`);
34906
+ return true;
34869
34907
  }
34870
- if (process.env.NPM_ONLY_PRODUCTION) {
34871
- commandArgs.push('--production');
34908
+ finally {
34909
+ runNpmInstallSema.release();
34872
34910
  }
34873
- return spawnAsync(cliType, commandArgs, opts);
34874
34911
  }
34875
34912
  exports.runNpmInstall = runNpmInstall;
34876
34913
  function getEnvForPackageManager({ cliType, lockfileVersion, nodeVersion, env, }) {
package/dist/types.d.ts CHANGED
@@ -294,6 +294,7 @@ export interface ProjectSettings {
294
294
  sourceFilesOutsideRootDirectory?: boolean;
295
295
  directoryListing?: boolean;
296
296
  gitForkProtection?: boolean;
297
+ commandForIgnoringBuildStep?: string | null;
297
298
  }
298
299
  export interface BuilderV2 {
299
300
  version: 2;
@@ -313,7 +314,28 @@ export interface Images {
313
314
  minimumCacheTTL?: number;
314
315
  formats?: ImageFormat[];
315
316
  }
316
- export interface BuildResultV2 {
317
+ /**
318
+ * If a Builder ends up creating filesystem outputs conforming to
319
+ * the Build Output API, then the Builder should return this type.
320
+ */
321
+ export interface BuildResultBuildOutput {
322
+ /**
323
+ * Version number of the Build Output API that was created.
324
+ * Currently only `3` is a valid value.
325
+ * @example 3
326
+ */
327
+ buildOutputVersion: 3;
328
+ /**
329
+ * Filesystem path to the Build Output directory.
330
+ * @example "/path/to/.vercel/output"
331
+ */
332
+ buildOutputPath: string;
333
+ }
334
+ /**
335
+ * When a Builder implements `version: 2`, the `build()` function is expected
336
+ * to return this type.
337
+ */
338
+ export interface BuildResultV2Typical {
317
339
  routes?: any[];
318
340
  images?: Images;
319
341
  output: {
@@ -324,6 +346,7 @@ export interface BuildResultV2 {
324
346
  value: string;
325
347
  }>;
326
348
  }
349
+ export declare type BuildResultV2 = BuildResultV2Typical | BuildResultBuildOutput;
327
350
  export interface BuildResultV3 {
328
351
  output: Lambda;
329
352
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/build-utils",
3
- "version": "2.15.2-canary.0",
3
+ "version": "2.15.2-canary.3",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.js",
@@ -30,7 +30,7 @@
30
30
  "@types/node-fetch": "^2.1.6",
31
31
  "@types/semver": "6.0.0",
32
32
  "@types/yazl": "^2.4.1",
33
- "@vercel/frameworks": "0.7.1",
33
+ "@vercel/frameworks": "0.7.2-canary.0",
34
34
  "@vercel/ncc": "0.24.0",
35
35
  "aggregate-error": "3.0.1",
36
36
  "async-retry": "1.2.3",
@@ -49,5 +49,5 @@
49
49
  "typescript": "4.3.4",
50
50
  "yazl": "2.4.3"
51
51
  },
52
- "gitHead": "e7f524defba3bbf2db750dea3235e6699584c424"
52
+ "gitHead": "698b89a2ba83d98b5fa0773142e4f5df3a2c4a9a"
53
53
  }