@netlify/build 35.13.8 → 35.14.0

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.
@@ -2,6 +2,14 @@ export function logBundleResults({ logs, results }: {
2
2
  logs: any;
3
3
  results: import("@netlify/zip-it-and-ship-it").FunctionResult[];
4
4
  }): void;
5
+ export function trackBundleResults({ results, systemLog }: {
6
+ results: import("@netlify/zip-it-and-ship-it").FunctionResult[];
7
+ systemLog: (...args: unknown[]) => void;
8
+ }): {
9
+ bundlers: import("@netlify/zip-it-and-ship-it").NodeBundlerName[];
10
+ fallbackCount: number;
11
+ warningsCount: number;
12
+ };
5
13
  export function logFunctionsNonExistingDir(logs: any, relativeFunctionsSrc: any): void;
6
14
  export function logFunctionsToBundle({ logs, userFunctions, userFunctionsSrc, userFunctionsSrcExists, internalFunctions, internalFunctionsSrc, frameworkFunctions, generatedFunctions, type, }: {
7
15
  logs: any;
@@ -1,4 +1,6 @@
1
1
  import path from 'path';
2
+ import { RUNTIME } from '@netlify/zip-it-and-ship-it';
3
+ import { trace } from '@opentelemetry/api';
2
4
  import { log, logArray, logError, logErrorSubHeader, logWarningSubHeader } from '../logger.js';
3
5
  import { THEME } from '../theme.js';
4
6
  const logBundleResultFunctions = ({ functions, headerMessage, logs, error }) => {
@@ -12,7 +14,7 @@ const logBundleResultFunctions = ({ functions, headerMessage, logs, error }) =>
12
14
  logArray(logs, functionNames);
13
15
  };
14
16
  /**
15
- * Logs the result of bundling functions
17
+ * Logs the result of bundling functions (user facing)
16
18
  *
17
19
  * @param {object} options
18
20
  * @param {any} options.logs
@@ -44,6 +46,58 @@ export const logBundleResults = ({ logs, results = [] }) => {
44
46
  logModulesWithDynamicImports({ logs, modulesWithDynamicImports });
45
47
  }
46
48
  };
49
+ /**
50
+ * Sibling of `logBundleResults`. Derives structured telemetry from the same
51
+ * `results` array and emits it to the system log and the active span. Returns
52
+ * summary stats the caller can use for metric tags.
53
+ *
54
+ * @param {object} options
55
+ * @param {import("@netlify/zip-it-and-ship-it").FunctionResult[]} options.results
56
+ * @param {(...args: unknown[]) => void} options.systemLog
57
+ * @returns {{
58
+ * bundlers: import("@netlify/zip-it-and-ship-it").NodeBundlerName[],
59
+ * fallbackCount: number,
60
+ * warningsCount: number,
61
+ * }}
62
+ */
63
+ export const trackBundleResults = ({ results = [], systemLog }) => {
64
+ // `bundlerErrors` is only set when the user requested `esbuild_zisi` (esbuild
65
+ // with zisi fallback), esbuild failed, and zisi succeeded. The final
66
+ // `bundler` reflects the fallback, so this is our "silent fallback" signal.
67
+ const perFunction = results.map((result) => ({
68
+ name: result.name,
69
+ runtime: result.runtime,
70
+ bundler: result.runtime === RUNTIME.JAVASCRIPT ? result.bundler : null,
71
+ hadFallback: (result.bundlerErrors?.length ?? 0) > 0,
72
+ hadWarnings: (result.bundlerWarnings?.length ?? 0) > 0,
73
+ }));
74
+ // Exclude both `null` (non-JS runtimes) and `undefined` (prebuilt `.zip`
75
+ // JS functions, which zip-it-and-ship-it passes through with no bundler).
76
+ const jsResults = perFunction.filter((p) => p.bundler != null);
77
+ const bundlers = [...new Set(jsResults.map((p) => p.bundler))];
78
+ const bundlerCounts = jsResults.reduce((acc, p) => ({ ...acc, [p.bundler]: (acc[p.bundler] ?? 0) + 1 }), {});
79
+ const fallbackCount = perFunction.filter((p) => p.hadFallback).length;
80
+ const warningsCount = perFunction.filter((p) => p.hadWarnings).length;
81
+ systemLog({
82
+ msg: 'Functions bundling completed',
83
+ bundlers,
84
+ bundlerCounts,
85
+ fallbackCount,
86
+ warningsCount,
87
+ functions: perFunction,
88
+ });
89
+ const span = trace.getActiveSpan();
90
+ if (span) {
91
+ span.setAttribute('build.execution.step.bundler', bundlers);
92
+ span.setAttribute('build.execution.step.functions_count', perFunction.length);
93
+ span.setAttribute('build.execution.step.bundler.fallback_count', fallbackCount);
94
+ span.setAttribute('build.execution.step.bundler.warnings_count', warningsCount);
95
+ for (const [bundler, count] of Object.entries(bundlerCounts)) {
96
+ span.setAttribute(`build.execution.step.bundler.${bundler}.count`, count);
97
+ }
98
+ }
99
+ return { bundlers, fallbackCount, warningsCount };
100
+ };
47
101
  export const logFunctionsNonExistingDir = function (logs, relativeFunctionsSrc) {
48
102
  log(logs, `The Netlify Functions setting targets a non-existing directory: ${relativeFunctionsSrc}`);
49
103
  };
@@ -1,40 +1,8 @@
1
1
  import { zipFunctions, type FunctionResult } from '@netlify/zip-it-and-ship-it';
2
+ import type { CoreStepFunction } from '../types.js';
2
3
  export declare const bundleFunctions: {
3
4
  event: string;
4
- coreStep: ({ childEnv, constants: { INTERNAL_FUNCTIONS_SRC: relativeInternalFunctionsSrc, IS_LOCAL: isRunningLocally, FUNCTIONS_SRC: relativeFunctionsSrc, FUNCTIONS_DIST: relativeFunctionsDist, }, buildDir, branch, packagePath, logs, netlifyConfig, featureFlags, repositoryRoot, userNodeVersion, systemLog, returnValues, }: {
5
- childEnv: any;
6
- constants: {
7
- INTERNAL_FUNCTIONS_SRC: any;
8
- IS_LOCAL: any;
9
- FUNCTIONS_SRC: any;
10
- FUNCTIONS_DIST: any;
11
- };
12
- buildDir: any;
13
- branch: any;
14
- packagePath: any;
15
- logs: any;
16
- netlifyConfig: any;
17
- featureFlags: any;
18
- repositoryRoot: any;
19
- userNodeVersion: any;
20
- systemLog: any;
21
- returnValues: any;
22
- }) => Promise<{
23
- tags?: undefined;
24
- metrics?: undefined;
25
- } | {
26
- tags: {
27
- bundler: ("zisi" | "nft" | "esbuild" | "none" | "esbuild_zisi")[];
28
- };
29
- metrics: {
30
- type: string;
31
- name: string;
32
- value: number;
33
- tags: {
34
- type: string;
35
- };
36
- }[];
37
- }>;
5
+ coreStep: CoreStepFunction;
38
6
  coreStepId: string;
39
7
  coreStepName: string;
40
8
  coreStepDescription: () => string;
@@ -1,20 +1,14 @@
1
1
  import { resolve } from 'path';
2
- import { RUNTIME, zipFunctions } from '@netlify/zip-it-and-ship-it';
2
+ import { zipFunctions } from '@netlify/zip-it-and-ship-it';
3
3
  import { pathExists } from 'path-exists';
4
4
  import { addErrorInfo } from '../../error/info.js';
5
5
  import { log } from '../../log/logger.js';
6
6
  import { getGeneratedFunctions } from '../../steps/return_values.js';
7
- import { logBundleResults, logFunctionsNonExistingDir, logFunctionsToBundle } from '../../log/messages/core_steps.js';
7
+ import { logBundleResults, logFunctionsNonExistingDir, logFunctionsToBundle, trackBundleResults, } from '../../log/messages/core_steps.js';
8
8
  import { FRAMEWORKS_API_FUNCTIONS_PATH } from '../../utils/frameworks_api.js';
9
9
  import { getZipError } from './error.js';
10
10
  import { getUserAndInternalFunctions, validateFunctionsSrc } from './utils.js';
11
11
  import { getZisiParameters } from './zisi.js';
12
- // Get a list of all unique bundlers in this run
13
- const getBundlers = (results = []) =>
14
- // using a Set to filter duplicates
15
- new Set(results
16
- .map((bundle) => (bundle.runtime === RUNTIME.JAVASCRIPT ? bundle.bundler : null))
17
- .filter(Boolean));
18
12
  // see https://docs.netlify.com/functions/trigger-on-events/#available-triggers
19
13
  const eventTriggeredFunctions = new Set([
20
14
  'deploy-building',
@@ -74,9 +68,9 @@ const zipFunctionsAndLogResults = async ({ branch, buildDir, childEnv, featureFl
74
68
  },
75
69
  }, functionsDist, zisiParameters);
76
70
  validateCustomRoutes(results);
77
- const bundlers = Array.from(getBundlers(results));
78
71
  logBundleResults({ logs, results });
79
- return { bundlers };
72
+ const summary = trackBundleResults({ results, systemLog });
73
+ return summary;
80
74
  }
81
75
  catch (error) {
82
76
  throw await getZipError(error, functionsSrc);
@@ -86,7 +80,7 @@ const zipFunctionsAndLogResults = async ({ branch, buildDir, childEnv, featureFl
86
80
  const coreStep = async function ({ childEnv, constants: { INTERNAL_FUNCTIONS_SRC: relativeInternalFunctionsSrc, IS_LOCAL: isRunningLocally, FUNCTIONS_SRC: relativeFunctionsSrc, FUNCTIONS_DIST: relativeFunctionsDist, }, buildDir, branch, packagePath, logs, netlifyConfig, featureFlags, repositoryRoot, userNodeVersion, systemLog, returnValues, }) {
87
81
  const functionsSrc = relativeFunctionsSrc === undefined ? undefined : resolve(buildDir, relativeFunctionsSrc);
88
82
  const functionsDist = resolve(buildDir, relativeFunctionsDist);
89
- const internalFunctionsSrc = resolve(buildDir, relativeInternalFunctionsSrc);
83
+ const internalFunctionsSrc = resolve(buildDir, relativeInternalFunctionsSrc ?? '');
90
84
  const internalFunctionsSrcExists = await pathExists(internalFunctionsSrc);
91
85
  const frameworkFunctionsSrc = resolve(buildDir, packagePath || '', FRAMEWORKS_API_FUNCTIONS_PATH);
92
86
  const frameworkFunctionsSrcExists = await pathExists(frameworkFunctionsSrc);
@@ -123,7 +117,7 @@ const coreStep = async function ({ childEnv, constants: { INTERNAL_FUNCTIONS_SRC
123
117
  generatedFunctions.length === 0) {
124
118
  return {};
125
119
  }
126
- const { bundlers } = await zipFunctionsAndLogResults({
120
+ const { bundlers, fallbackCount, warningsCount } = await zipFunctionsAndLogResults({
127
121
  branch,
128
122
  buildDir,
129
123
  childEnv,
@@ -140,10 +134,14 @@ const coreStep = async function ({ childEnv, constants: { INTERNAL_FUNCTIONS_SRC
140
134
  systemLog,
141
135
  generatedFunctions: generatedFunctions.map((func) => func.path),
142
136
  });
143
- const metrics = getMetrics(internalFunctions, userFunctions);
137
+ const fallback = fallbackCount > 0 ? 'true' : 'false';
138
+ const warnings = warningsCount > 0 ? 'true' : 'false';
139
+ const metrics = getMetrics(internalFunctions, userFunctions, { bundlers, fallback, warnings });
144
140
  return {
145
141
  tags: {
146
142
  bundler: bundlers,
143
+ fallback,
144
+ warnings,
147
145
  },
148
146
  metrics,
149
147
  };
@@ -203,19 +201,19 @@ export const zipItAndShipIt = {
203
201
  return await zipFunctions(...args);
204
202
  },
205
203
  };
206
- const getMetrics = (internalFunctions, userFunctions) => {
204
+ const getMetrics = (internalFunctions, userFunctions, { bundlers, fallback, warnings }) => {
207
205
  return [
208
206
  {
209
207
  type: 'increment',
210
208
  name: 'buildbot.build.functions',
211
209
  value: internalFunctions.length,
212
- tags: { type: 'lambda:generated' },
210
+ tags: { type: 'lambda:generated', bundler: bundlers, fallback, warnings },
213
211
  },
214
212
  {
215
213
  type: 'increment',
216
214
  name: 'buildbot.build.functions',
217
215
  value: userFunctions.length,
218
- tags: { type: 'lambda:user' },
216
+ tags: { type: 'lambda:user', bundler: bundlers, fallback, warnings },
219
217
  },
220
218
  ];
221
219
  };
@@ -1,7 +1,8 @@
1
1
  import { type DynamicMethods } from 'packages/js-client/lib/types.js';
2
- import { NetlifyPluginConstants } from '../core/constants.js';
3
- import { BufferedLogs } from '../log/logger.js';
4
- import { NetlifyConfig } from '../types/config/netlify_config.js';
2
+ import type { NetlifyPluginConstants } from '../core/constants.js';
3
+ import type { BufferedLogs } from '../log/logger.js';
4
+ import type { NetlifyConfig } from '../types/config/netlify_config.js';
5
+ import type { ReturnValue } from '../steps/return_values.js';
5
6
  type $TSFixme = any;
6
7
  export type CoreStepFunctionArgs = {
7
8
  /**
@@ -46,6 +47,9 @@ export type CoreStepFunctionArgs = {
46
47
  isSecret: boolean;
47
48
  scopes: string[];
48
49
  }[];
50
+ userNodeVersion?: string;
51
+ childEnv: $TSFixme;
52
+ returnValues: Record<string, ReturnValue>;
49
53
  buildbotServerSocket?: string;
50
54
  api: DynamicMethods;
51
55
  };
@@ -1,9 +1,25 @@
1
1
  type GlobPattern = string;
2
2
  type FunctionsObject = {
3
+ /**
4
+ * marks the function as a [background function](https://docs.netlify.com/functions/background-functions/), which is invoked asynchronously and can run for up to 15 minutes.
5
+ */
6
+ background?: boolean;
3
7
  /**
4
8
  * a list of additional paths to include in the function bundle. Although our build system includes statically referenced files (like `import * from "./some-file.js"`) by default, `included_files` lets you specify additional files or directories and reference them dynamically in function code. You can use `*` to match any character or prefix an entry with `!` to exclude files. Paths are relative to the [base directory](https://docs.netlify.com/configure-builds/get-started/#definitions-1).
5
9
  */
6
10
  included_files?: string[];
11
+ /**
12
+ * the amount of memory allocated to the function, expressed either as a number of MB or as a string with a unit (e.g. `"2gb"`). Mutually exclusive with `vcpu`.
13
+ */
14
+ memory?: number | string;
15
+ /**
16
+ * the [region](https://docs.netlify.com/functions/optional-configuration/#region) the function should run in, identified by its airport code (e.g. `"cmh"`).
17
+ */
18
+ region?: string;
19
+ /**
20
+ * the number of vCPUs allocated to the function (between `0.5` and `2`). Mutually exclusive with `memory`.
21
+ */
22
+ vcpu?: number;
7
23
  } & ({
8
24
  /**
9
25
  * the function bundling method used in [`@netlify/zip-it-and-ship-it`](https://github.com/netlify/zip-it-and-ship-it).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/build",
3
- "version": "35.13.8",
3
+ "version": "35.14.0",
4
4
  "description": "Netlify build module",
5
5
  "type": "module",
6
6
  "exports": "./lib/index.js",
@@ -70,7 +70,7 @@
70
70
  "@netlify/blobs": "^10.4.4",
71
71
  "@netlify/cache-utils": "^6.0.5",
72
72
  "@netlify/config": "^24.6.0",
73
- "@netlify/edge-bundler": "14.10.2",
73
+ "@netlify/edge-bundler": "14.10.3",
74
74
  "@netlify/functions-utils": "^6.2.34",
75
75
  "@netlify/git-utils": "^6.0.4",
76
76
  "@netlify/opentelemetry-utils": "^2.0.2",
@@ -152,5 +152,5 @@
152
152
  "engines": {
153
153
  "node": ">=18.14.0"
154
154
  },
155
- "gitHead": "0e2b212c4ffae1e07159374df9991584e5b4bb0b"
155
+ "gitHead": "dc4e6c79ae03de4070f706c936ed7e177d8ffec3"
156
156
  }