@netlify/build
Version:
Netlify build module
112 lines (109 loc) • 5.41 kB
JavaScript
import path from 'path';
import { log, logArray, logError, logErrorSubHeader, logWarningSubHeader } from '../logger.js';
import { THEME } from '../theme.js';
const logBundleResultFunctions = ({ functions, headerMessage, logs, error }) => {
const functionNames = functions.map(({ path: functionPath }) => path.basename(functionPath));
if (error) {
logErrorSubHeader(logs, headerMessage);
}
else {
logWarningSubHeader(logs, headerMessage);
}
logArray(logs, functionNames);
};
/**
* Logs the result of bundling functions
*
* @param {object} options
* @param {any} options.logs
* @param {import("@netlify/zip-it-and-ship-it").FunctionResult[]} options.results
*/
export const logBundleResults = ({ logs, results = [] }) => {
const resultsWithErrors = results.filter(({ bundlerErrors }) => bundlerErrors && bundlerErrors.length !== 0);
const resultsWithWarnings = results.filter(({ bundler, bundlerWarnings }) => bundler === 'esbuild' && bundlerWarnings && bundlerWarnings.length !== 0);
const modulesWithDynamicImports = [
...new Set(results.flatMap((result) => result.nodeModulesWithDynamicImports || [])),
];
if (resultsWithErrors.length !== 0) {
logBundleResultFunctions({
functions: resultsWithErrors,
headerMessage: 'Failed to bundle functions with selected bundler (fallback used):',
logs,
error: true,
});
}
if (resultsWithWarnings.length !== 0) {
logBundleResultFunctions({
functions: resultsWithWarnings,
headerMessage: 'Functions bundled with warnings:',
logs,
error: false,
});
}
if (modulesWithDynamicImports.length !== 0) {
logModulesWithDynamicImports({ logs, modulesWithDynamicImports });
}
};
export const logFunctionsNonExistingDir = function (logs, relativeFunctionsSrc) {
log(logs, `The Netlify Functions setting targets a non-existing directory: ${relativeFunctionsSrc}`);
};
// Print the list of Netlify Functions about to be bundled
export const logFunctionsToBundle = function ({ logs, userFunctions, userFunctionsSrc, userFunctionsSrcExists, internalFunctions, internalFunctionsSrc, frameworkFunctions, type = 'Functions', }) {
if (internalFunctions.length !== 0) {
log(logs, `Packaging ${type} from ${THEME.highlightWords(internalFunctionsSrc)} directory:`);
logArray(logs, internalFunctions, { indent: false });
}
if (frameworkFunctions.length !== 0) {
if (internalFunctions.length !== 0) {
log(logs, '');
}
log(logs, `Packaging ${type} generated by your framework:`);
logArray(logs, frameworkFunctions, { indent: false });
}
if (!userFunctionsSrcExists) {
return;
}
if (userFunctions.length === 0) {
log(logs, `No ${type} were found in ${THEME.highlightWords(userFunctionsSrc)} directory`);
return;
}
if (internalFunctions.length !== 0 || frameworkFunctions.length !== 0) {
log(logs, '');
}
log(logs, `Packaging ${type} from ${THEME.highlightWords(userFunctionsSrc)} directory:`);
logArray(logs, userFunctions, { indent: false });
};
const logModulesWithDynamicImports = ({ logs, modulesWithDynamicImports }) => {
const externalNodeModules = modulesWithDynamicImports.map((moduleName) => `"${moduleName}"`).join(', ');
logWarningSubHeader(logs, `The following Node.js modules use dynamic expressions to include files:`);
logArray(logs, modulesWithDynamicImports);
log(logs, `\n Because files included with dynamic expressions aren't bundled with your serverless functions by default,
this may result in an error when invoking a function. To resolve this error, you can mark these Node.js
modules as external in the [functions] section of your \`netlify.toml\` configuration file:
[functions]
external_node_modules = [${externalNodeModules}]
Visit https://ntl.fyi/dynamic-imports for more information.
`);
};
export const logSecretsScanSkipMessage = function (logs, msg) {
log(logs, msg, { color: THEME.warningHighlightWords });
};
export const logSecretsScanSuccessMessage = function (logs, msg) {
log(logs, msg, { color: THEME.highlightWords });
};
export const logSecretsScanFailBuildMessage = function ({ logs, scanResults, groupedResults }) {
logErrorSubHeader(logs, `Scanning complete. ${scanResults.scannedFilesCount} file(s) scanned. Secrets scanning found ${scanResults.matches.length} instance(s) of secrets in build output or repo code.\n`);
Object.keys(groupedResults).forEach((key) => {
logError(logs, `Secret env var "${key}"'s value detected:`);
groupedResults[key]
.sort((a, b) => {
return a.file > b.file ? 0 : 1;
})
.forEach(({ lineNumber, file }) => {
logError(logs, `found value at line ${lineNumber} in ${file}`, { indent: true });
});
});
logError(logs, `\nTo prevent exposing secrets, the build will fail until these secret values are not found in build output or repo files.`);
logError(logs, `If these are expected, use SECRETS_SCAN_OMIT_PATHS, SECRETS_SCAN_OMIT_KEYS, or SECRETS_SCAN_ENABLED to prevent detecting.`);
logError(logs, `For more information on secrets scanning, see the Netlify Docs: https://ntl.fyi/configure-secrets-scanning`);
};