Skip to content

Commit b26d4fb

Browse files
committed
Revert "perf(aws-serverless): Speed up Lambda layer build with tarball-based install"
This reverts commit 7203205.
1 parent b57849c commit b26d4fb

1 file changed

Lines changed: 36 additions & 75 deletions

File tree

packages/aws-serverless/scripts/buildLambdaLayer.ts

Lines changed: 36 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { nodeFileTrace } from '@vercel/nft';
33
import * as childProcess from 'child_process';
44
import * as fs from 'fs';
5+
import * as os from 'os';
56
import * as path from 'path';
67
import { version } from '../package.json';
78

@@ -21,14 +22,21 @@ function run(cmd: string, options?: childProcess.ExecSyncOptions): string {
2122
*/
2223
async function buildLambdaLayer(): Promise<void> {
2324
console.log('Building Lambda layer.');
24-
const tarballDir = buildTarballsAndPackageJson();
25-
console.log('Installing @sentry/aws-serverless from tarballs into build/aws/dist-serverless/nodejs.');
26-
run('yarn install --prod --cwd ./build/aws/dist-serverless/nodejs');
25+
buildPackageJson();
26+
console.log('Installing local @sentry/aws-serverless into build/aws/dist-serverless/nodejs.');
27+
// Use a temporary cache folder to avoid stale cache references to local file: packages.
28+
// Yarn's global cache can contain outdated references to build artifacts from other
29+
// @sentry/* packages (e.g., build/node_modules paths that no longer exist), causing
30+
// ENOENT errors during file copying.
31+
// The cache folder must be outside the monorepo to avoid recursive nesting when Yarn
32+
// follows file: links and copies package directories.
33+
const cacheFolder = path.join(os.tmpdir(), `sentry-lambda-build-cache-${Date.now()}`);
34+
run(`yarn install --prod --cwd ./build/aws/dist-serverless/nodejs --cache-folder "${cacheFolder}"`);
2735

2836
await pruneNodeModules();
2937
fs.rmSync('./build/aws/dist-serverless/nodejs/package.json', { force: true });
3038
fs.rmSync('./build/aws/dist-serverless/nodejs/yarn.lock', { force: true });
31-
fs.rmSync(tarballDir, { recursive: true, force: true });
39+
fs.rmSync(cacheFolder, { recursive: true, force: true });
3240

3341
// The layer also includes `awslambda-auto.js`, a helper file which calls `Sentry.init()` and wraps the lambda
3442
// handler. It gets run when Node is launched inside the lambda, using the environment variable
@@ -162,90 +170,43 @@ function getAllFiles(dir: string): string[] {
162170
return files;
163171
}
164172

165-
/**
166-
* Pack @sentry/* packages into tarballs and generate a package.json that references them.
167-
*
168-
* Using tarballs instead of `file:` directory references avoids stale yarn cache issues
169-
* (where yarn's global cache retains outdated build artifact paths from previous builds)
170-
* and allows us to use yarn's global cache for faster installs.
171-
*
172-
* Only packs packages that are transitive dependencies of @sentry/aws-serverless to keep
173-
* the packing step fast.
174-
*/
175-
function buildTarballsAndPackageJson(): string {
176-
const tarballDir = path.resolve('./build/aws/tarballs');
177-
fsForceMkdirSync(tarballDir);
178-
173+
function buildPackageJson(): void {
174+
console.log('Building package.json');
179175
const packagesDir = path.resolve(__dirname, '../..');
180-
const sentryPackages = collectSentryDependencies(packagesDir);
181-
182-
console.log(`Packing ${sentryPackages.size} @sentry/* packages into tarballs.`);
176+
const packageDirs = fs
177+
.readdirSync(packagesDir, { withFileTypes: true })
178+
.filter(dirent => dirent.isDirectory())
179+
.map(dirent => dirent.name)
180+
.filter(name => !name.startsWith('.')) // Skip hidden directories
181+
.sort();
183182

184183
const resolutions: Record<string, string> = {};
185184

186-
for (const [packageName, packageDir] of sentryPackages) {
187-
run(`npm pack --pack-destination "${tarballDir}"`, {
188-
cwd: path.join(packagesDir, packageDir),
189-
stdio: 'pipe',
190-
});
191-
const tarballName = `${packageName.replace('@', '').replace('/', '-')}-${version}.tgz`;
192-
resolutions[packageName] = `file:${path.join(tarballDir, tarballName)}`;
193-
}
194-
195-
const awsServerlessTarball = resolutions['@sentry/aws-serverless'];
196-
if (!awsServerlessTarball) {
197-
throw new Error('Failed to pack @sentry/aws-serverless');
185+
for (const packageDir of packageDirs) {
186+
const packageJsonPath = path.join(packagesDir, packageDir, 'package.json');
187+
if (fs.existsSync(packageJsonPath)) {
188+
try {
189+
const packageContent = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')) as { name?: string };
190+
const packageName = packageContent.name;
191+
if (typeof packageName === 'string' && packageName) {
192+
resolutions[packageName] = `file:../../../../../../packages/${packageDir}`;
193+
}
194+
} catch {
195+
console.warn(`Warning: Could not read package.json for ${packageDir}`);
196+
}
197+
}
198198
}
199199

200200
const packageJson = {
201201
dependencies: {
202-
'@sentry/aws-serverless': awsServerlessTarball,
202+
'@sentry/aws-serverless': 'file:../../../../../../packages/aws-serverless',
203203
},
204204
resolutions,
205205
};
206206

207207
fsForceMkdirSync('./build/aws/dist-serverless/nodejs');
208-
fs.writeFileSync('./build/aws/dist-serverless/nodejs/package.json', JSON.stringify(packageJson, null, 2));
209-
210-
return tarballDir;
211-
}
212-
213-
/**
214-
* Collect all @sentry/* and @sentry-internal/* packages that are transitive
215-
* dependencies of @sentry/aws-serverless.
216-
* Returns a Map of packageName -> directory name.
217-
*/
218-
function collectSentryDependencies(packagesDir: string): Map<string, string> {
219-
const result = new Map<string, string>();
220-
221-
// Build a lookup of package name -> directory name
222-
const nameToDir = new Map<string, string>();
223-
for (const dirent of fs.readdirSync(packagesDir, { withFileTypes: true })) {
224-
if (!dirent.isDirectory() || dirent.name.startsWith('.')) continue;
225-
const pkgPath = path.join(packagesDir, dirent.name, 'package.json');
226-
if (!fs.existsSync(pkgPath)) continue;
227-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as { name?: string };
228-
if (pkg.name) {
229-
nameToDir.set(pkg.name, dirent.name);
230-
}
231-
}
232-
233-
function collect(packageName: string): void {
234-
if (result.has(packageName)) return;
235-
const dir = nameToDir.get(packageName);
236-
if (!dir) return;
237-
result.set(packageName, dir);
238-
const pkgPath = path.join(packagesDir, dir, 'package.json');
239-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as { dependencies?: Record<string, string> };
240-
for (const dep of Object.keys(pkg.dependencies || {})) {
241-
if (dep.startsWith('@sentry/') || dep.startsWith('@sentry-internal/')) {
242-
collect(dep);
243-
}
244-
}
245-
}
246-
247-
collect('@sentry/aws-serverless');
248-
return result;
208+
const packageJsonPath = './build/aws/dist-serverless/nodejs/package.json';
209+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
249210
}
250211

251212
function replaceSDKSource(): void {

0 commit comments

Comments
 (0)