Skip to content

fix(profiling): Make esbuild detect node binaries with CJS require #15056

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 54 additions & 16 deletions packages/profiling-node/rollup.npm.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,57 @@ import commonjs from '@rollup/plugin-commonjs';
import replace from '@rollup/plugin-replace';
import { makeBaseNPMConfig, makeNPMConfigVariants } from '@sentry-internal/rollup-utils';

export default makeNPMConfigVariants(
makeBaseNPMConfig({
packageSpecificConfig: {
output: { dir: 'lib', preserveModules: false },
plugins: [
commonjs(),
replace({
preventAssignment: false,
values: {
__IMPORT_META_URL_REPLACEMENT__: 'import.meta.url',
},
}),
],
},
}),
);
/**
* Skip resolving dynamic imports of node binaries (effectively marking it as external)
*/
const nodeBinariesLoader = () => ({
name: 'node-binaries-loader',
resolveDynamicImport(specifier) {
if (typeof specifier === 'string' && specifier.includes('sentry_cpu_profiler') && specifier.endsWith('.node')) {
return false;
}
return null; // defer to other resolvers
},
});

export default [
...makeNPMConfigVariants(
makeBaseNPMConfig({
packageSpecificConfig: {
output: { dir: 'lib', preserveModules: false },
plugins: [
commonjs(),
replace({
preventAssignment: false,
values: {
__IMPORT_META_URL_REPLACEMENT__: 'import.meta.url',
__CREATE_REQUIRE__: '', // empty, so the native CJS `require` can be used without getting renamed during build (because of a new assignment)
__LOAD_MODULE_REPLACEMENT__: 'require',
},
}),
],
},
}),
{ emitEsm: false },
),
...makeNPMConfigVariants(
makeBaseNPMConfig({
packageSpecificConfig: {
output: { dir: 'lib', preserveModules: false },
plugins: [
nodeBinariesLoader(),
commonjs(),
replace({
preventAssignment: false,
values: {
__IMPORT_META_URL_REPLACEMENT__: 'import.meta.url',
__CREATE_REQUIRE__: 'const require = createRequire(importMetaUrl);', // Variable assignment for the require replacement below
__LOAD_MODULE_REPLACEMENT__: 'require',
},
}),
],
},
}),
{ emitCjs: false },
),
];
70 changes: 37 additions & 33 deletions packages/profiling-node/src/cpu_profiler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { createRequire } from 'node:module';
import { arch as _arch, platform as _platform } from 'node:os';
import { join, resolve } from 'node:path';
import { dirname } from 'node:path';
Expand All @@ -19,6 +18,8 @@ import type {
import type { ProfileFormat } from './types';

declare const __IMPORT_META_URL_REPLACEMENT__: string;
declare const __CREATE_REQUIRE__: string;
declare const __LOAD_MODULE_REPLACEMENT__: (path: string) => PrivateV8CpuProfilerBindings;

const stdlib = familySync();
const platform = process.env['BUILD_PLATFORM'] || _platform();
Expand All @@ -39,68 +40,71 @@ export function importCppBindingsModule(): PrivateV8CpuProfilerBindings {
: // This case is hit when the tests are run
pathToFileURL(__filename).href;

const createdRequire = createRequire(importMetaUrl);
// During build-time in ESM, this is replaced with an assignment of `require`. In CJS, this line is empty, so we can use the native require.
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
__CREATE_REQUIRE__;

const esmCompatibleDirname = dirname(fileURLToPath(importMetaUrl));

// If a binary path is specified, use that.
if (env['SENTRY_PROFILER_BINARY_PATH']) {
const envPath = env['SENTRY_PROFILER_BINARY_PATH'];
return createdRequire(envPath);
return __LOAD_MODULE_REPLACEMENT__(envPath);
}

// If a user specifies a different binary dir, they are in control of the binaries being moved there
if (env['SENTRY_PROFILER_BINARY_DIR']) {
const binaryPath = join(resolve(env['SENTRY_PROFILER_BINARY_DIR']), `sentry_cpu_profiler-${identifier}`);
return createdRequire(`${binaryPath}.node`);
return __LOAD_MODULE_REPLACEMENT__(`${binaryPath}.node`);
}

// We need the fallthrough so that in the end, we can fallback to the dynamic require.
// This is for cases where precompiled binaries were not provided, but may have been compiled from source.
if (platform === 'darwin') {
if (arch === 'x64') {
if (abi === '93') {
return createdRequire('../sentry_cpu_profiler-darwin-x64-93.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-darwin-x64-93.node');
}
if (abi === '108') {
return createdRequire('../sentry_cpu_profiler-darwin-x64-108.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-darwin-x64-108.node');
}
if (abi === '115') {
return createdRequire('../sentry_cpu_profiler-darwin-x64-115.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-darwin-x64-115.node');
}
if (abi === '127') {
return createdRequire('../sentry_cpu_profiler-darwin-x64-127.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-darwin-x64-127.node');
}
}

if (arch === 'arm64') {
if (abi === '93') {
return createdRequire('../sentry_cpu_profiler-darwin-arm64-93.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-darwin-arm64-93.node');
}
if (abi === '108') {
return createdRequire('../sentry_cpu_profiler-darwin-arm64-108.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-darwin-arm64-108.node');
}
if (abi === '115') {
return createdRequire('../sentry_cpu_profiler-darwin-arm64-115.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-darwin-arm64-115.node');
}
if (abi === '127') {
return createdRequire('../sentry_cpu_profiler-darwin-arm64-127.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-darwin-arm64-127.node');
}
}
}

if (platform === 'win32') {
if (arch === 'x64') {
if (abi === '93') {
return createdRequire('../sentry_cpu_profiler-win32-x64-93.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-win32-x64-93.node');
}
if (abi === '108') {
return createdRequire('../sentry_cpu_profiler-win32-x64-108.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-win32-x64-108.node');
}
if (abi === '115') {
return createdRequire('../sentry_cpu_profiler-win32-x64-115.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-win32-x64-115.node');
}
if (abi === '127') {
return createdRequire('../sentry_cpu_profiler-win32-x64-127.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-win32-x64-127.node');
}
}
}
Expand All @@ -109,68 +113,68 @@ export function importCppBindingsModule(): PrivateV8CpuProfilerBindings {
if (arch === 'x64') {
if (stdlib === 'musl') {
if (abi === '93') {
return createdRequire('../sentry_cpu_profiler-linux-x64-musl-93.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-x64-musl-93.node');
}
if (abi === '108') {
return createdRequire('../sentry_cpu_profiler-linux-x64-musl-108.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-x64-musl-108.node');
}
if (abi === '115') {
return createdRequire('../sentry_cpu_profiler-linux-x64-musl-115.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-x64-musl-115.node');
}
if (abi === '127') {
return createdRequire('../sentry_cpu_profiler-linux-x64-musl-127.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-x64-musl-127.node');
}
}
if (stdlib === 'glibc') {
if (abi === '93') {
return createdRequire('../sentry_cpu_profiler-linux-x64-glibc-93.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-x64-glibc-93.node');
}
if (abi === '108') {
return createdRequire('../sentry_cpu_profiler-linux-x64-glibc-108.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-x64-glibc-108.node');
}
if (abi === '115') {
return createdRequire('../sentry_cpu_profiler-linux-x64-glibc-115.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-x64-glibc-115.node');
}
if (abi === '127') {
return createdRequire('../sentry_cpu_profiler-linux-x64-glibc-127.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-x64-glibc-127.node');
}
}
}
if (arch === 'arm64') {
if (stdlib === 'musl') {
if (abi === '93') {
return createdRequire('../sentry_cpu_profiler-linux-arm64-musl-93.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-arm64-musl-93.node');
}
if (abi === '108') {
return createdRequire('../sentry_cpu_profiler-linux-arm64-musl-108.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-arm64-musl-108.node');
}
if (abi === '115') {
return createdRequire('../sentry_cpu_profiler-linux-arm64-musl-115.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-arm64-musl-115.node');
}
if (abi === '127') {
return createdRequire('../sentry_cpu_profiler-linux-arm64-musl-127.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-arm64-musl-127.node');
}
}

if (stdlib === 'glibc') {
if (abi === '93') {
return createdRequire('../sentry_cpu_profiler-linux-arm64-glibc-93.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-arm64-glibc-93.node');
}
if (abi === '108') {
return createdRequire('../sentry_cpu_profiler-linux-arm64-glibc-108.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-arm64-glibc-108.node');
}
if (abi === '115') {
return createdRequire('../sentry_cpu_profiler-linux-arm64-glibc-115.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-arm64-glibc-115.node');
}
if (abi === '127') {
return createdRequire('../sentry_cpu_profiler-linux-arm64-glibc-127.node');
return __LOAD_MODULE_REPLACEMENT__('../sentry_cpu_profiler-linux-arm64-glibc-127.node');
}
}
}
}

const built_from_source_path = resolve(esmCompatibleDirname, '..', `sentry_cpu_profiler-${identifier}`);
return createdRequire(`${built_from_source_path}.node`);
return __LOAD_MODULE_REPLACEMENT__(`${built_from_source_path}.node`);
}

const PrivateCpuProfilerBindings: PrivateV8CpuProfilerBindings = importCppBindingsModule();
Expand Down
Loading