UNPKG

aws-lambda-nodejs-esbuild

Version:

λ💨 AWS CDK Construct to bundle JavaScript and TypeScript AWS lambdas using extremely fast esbuild

152 lines (151 loc) 7.62 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.packExternalModules = void 0; const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const ramda_1 = require("ramda"); const Packagers = __importStar(require("./packagers")); function rebaseFileReferences(pathToPackageRoot, moduleVersion) { if (/^(?:file:[^/]{2}|\.\/|\.\.\/)/.test(moduleVersion)) { const filePath = ramda_1.replace(/^file:/, '', moduleVersion); return ramda_1.replace(/\\/g, '/', `${moduleVersion.startsWith('file:') ? 'file:' : ''}${pathToPackageRoot}/${filePath}`); } return moduleVersion; } /** * Add the given modules to a package json's dependencies. */ function addModulesToPackageJson(externalModules, packageJson, pathToPackageRoot) { ramda_1.forEach(externalModule => { var _a; const splitModule = externalModule.split('@'); // If we have a scoped module we have to re-add the @ if (externalModule.startsWith('@')) { splitModule.splice(0, 1); splitModule[0] = '@' + splitModule[0]; } let moduleVersion = ramda_1.join('@', ramda_1.tail(splitModule)); // We have to rebase file references to the target package.json moduleVersion = rebaseFileReferences(pathToPackageRoot, moduleVersion); packageJson.dependencies = packageJson.dependencies || {}; packageJson.dependencies[(_a = ramda_1.head(splitModule)) !== null && _a !== void 0 ? _a : ''] = moduleVersion; }, externalModules); } /** * Resolve the needed versions of production dependencies for external modules. */ function getProdModules(externalModules, packageJsonPath) { // eslint-disable-next-line @typescript-eslint/no-var-requires const packageJson = require(packageJsonPath); const prodModules = []; // only process the module stated in dependencies section if (!packageJson.dependencies) { return []; } // Get versions of all transient modules ramda_1.forEach(externalModule => { const moduleVersion = packageJson.dependencies[externalModule.external]; if (moduleVersion) { prodModules.push(`${externalModule.external}@${moduleVersion}`); // Check if the module has any peer dependencies and include them too try { const modulePackagePath = path.join(path.dirname(packageJsonPath), 'node_modules', externalModule.external, 'package.json'); const peerDependencies = require(modulePackagePath).peerDependencies; if (!ramda_1.isEmpty(peerDependencies)) { const peerModules = getProdModules(ramda_1.compose(ramda_1.map(([external]) => ({ external })), ramda_1.toPairs)(peerDependencies), packageJsonPath); Array.prototype.push.apply(prodModules, peerModules); } } catch (e) { console.log(`WARNING: Could not check for peer dependencies of ${externalModule.external}`); } } else { if (!packageJson.devDependencies || !packageJson.devDependencies[externalModule.external]) { prodModules.push(externalModule.external); } else { // To minimize the chance of breaking setups we whitelist packages available on AWS here. These are due to the previously missing check // most likely set in devDependencies and should not lead to an error now. const ignoredDevDependencies = ['aws-sdk']; if (!ramda_1.includes(externalModule.external, ignoredDevDependencies)) { // Runtime dependency found in devDependencies but not forcefully excluded throw new Error(`dependency error: ${externalModule.external}.`); } } } }, externalModules); return prodModules; } /** * We need a performant algorithm to install the packages for each single function. * (1) We fetch ALL packages needed by ALL functions in a first step * and use this as a base npm checkout. The checkout will be done to a * separate temporary directory with a package.json that contains everything. * (2) For each single compile we copy the whole node_modules to the compile * directory and create a (function) compile specific package.json and store * it in the compile directory. Now we start npm again there, and npm will just * remove the superfluous packages and optimize the remaining dependencies. * This will utilize the npm cache at its best and give us the needed results * and performance. */ function packExternalModules(externals, cwd, compositeModulePath, pkger) { if (!externals || !externals.length) { return; } // Read function package.json const packageJsonPath = path.join(cwd, 'package.json'); // Determine and create packager const packager = Packagers.get(cwd, pkger); // Fetch needed original package.json sections const packageJson = fs.readJsonSync(packageJsonPath); const packageSections = ramda_1.pick(packager.copyPackageSectionNames, packageJson); // (1) Generate dependency composition const externalModules = externals.map(external => ({ external })); const compositeModules = ramda_1.uniq(getProdModules(externalModules, packageJsonPath)); if (ramda_1.isEmpty(compositeModules)) { // The compiled code does not reference any external modules at all return; } // (1.a) Install all needed modules const compositePackageJsonPath = path.join(compositeModulePath, 'package.json'); // (1.a.1) Create a package.json const compositePackageJson = ramda_1.mergeRight({ name: 'externals', version: '1.0.0', private: true, }, packageSections); const relativePath = path.relative(compositeModulePath, path.dirname(packageJsonPath)); addModulesToPackageJson(compositeModules, compositePackageJson, relativePath); fs.writeJsonSync(compositePackageJsonPath, compositePackageJson); // (1.a.2) Copy package-lock.json if it exists, to prevent unwanted upgrades const packageLockPath = path.join(path.dirname(packageJsonPath), packager.lockfileName); if (fs.existsSync(packageLockPath)) { let packageLockFile = fs.readJsonSync(packageLockPath); packageLockFile = packager.rebaseLockfile(relativePath, packageLockFile); fs.writeJsonSync(path.join(compositeModulePath, packager.lockfileName), packageLockFile); } packager.install(compositeModulePath); // Prune extraneous packages - removes not needed ones packager.prune(compositeModulePath); } exports.packExternalModules = packExternalModules;