diff --git a/dev-packages/e2e-tests/test-applications/node-profiling/build-cjs.mjs b/dev-packages/e2e-tests/test-applications/node-profiling/build-cjs.mjs deleted file mode 100644 index 4a9aa83d0eec..000000000000 --- a/dev-packages/e2e-tests/test-applications/node-profiling/build-cjs.mjs +++ /dev/null @@ -1,20 +0,0 @@ -// Because bundlers can now predetermine a static set of binaries we need to ensure those binaries -// actually exists, else we risk a compile time error when bundling the package. This could happen -// if we added a new binary in cpu_profiler.ts, but forgot to prebuild binaries for it. Because CI -// only runs integration and unit tests, this change would be missed and could end up in a release. -// Therefor, once all binaries are precompiled in CI and tests pass, run esbuild with bundle:true -// which will copy all binaries to the outfile folder and throw if any of them are missing. -import esbuild from 'esbuild'; - -console.log('Running build using esbuild version', esbuild.version); - -esbuild.buildSync({ - platform: 'node', - entryPoints: ['./index.ts'], - outfile: './dist/cjs/index.js', - target: 'esnext', - format: 'cjs', - bundle: true, - loader: { '.node': 'copy' }, - external: ['@sentry/node', '@sentry/profiling-node'], -}); diff --git a/dev-packages/e2e-tests/test-applications/node-profiling/build-esm.mjs b/dev-packages/e2e-tests/test-applications/node-profiling/build-esm.mjs deleted file mode 100644 index 294e53d50635..000000000000 --- a/dev-packages/e2e-tests/test-applications/node-profiling/build-esm.mjs +++ /dev/null @@ -1,20 +0,0 @@ -// Because bundlers can now predetermine a static set of binaries we need to ensure those binaries -// actually exists, else we risk a compile time error when bundling the package. This could happen -// if we added a new binary in cpu_profiler.ts, but forgot to prebuild binaries for it. Because CI -// only runs integration and unit tests, this change would be missed and could end up in a release. -// Therefor, once all binaries are precompiled in CI and tests pass, run esbuild with bundle:true -// which will copy all binaries to the outfile folder and throw if any of them are missing. -import esbuild from 'esbuild'; - -console.log('Running build using esbuild version', esbuild.version); - -esbuild.buildSync({ - platform: 'node', - entryPoints: ['./index.ts'], - outfile: './dist/esm/index.mjs', - target: 'esnext', - format: 'esm', - bundle: true, - loader: { '.node': 'copy' }, - external: ['@sentry/node', '@sentry/profiling-node'], -}); diff --git a/dev-packages/e2e-tests/test-applications/node-profiling/esbuild.mjs b/dev-packages/e2e-tests/test-applications/node-profiling/esbuild.mjs new file mode 100644 index 000000000000..6a7a20d8c9d0 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/node-profiling/esbuild.mjs @@ -0,0 +1,16 @@ +import esbuild from 'esbuild'; + +console.log('Running build using esbuild version', esbuild.version); + +const output = esbuild.buildSync({ + logLevel: 'debug', + platform: 'node', + entryPoints: ['./index.js'], + outfile: './dist/esbuild/index.js', + target: 'esnext', + format: 'cjs', + bundle: true, + loader: { '.node': 'copy' }, +}); + +process.exit(output.errors.length); diff --git a/dev-packages/e2e-tests/test-applications/node-profiling/index.js b/dev-packages/e2e-tests/test-applications/node-profiling/index.js new file mode 100644 index 000000000000..e692b4cb6317 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/node-profiling/index.js @@ -0,0 +1,31 @@ +const Sentry = require('@sentry/node'); +const { nodeProfilingIntegration } = require('@sentry/profiling-node'); +const { inspect } = require('util'); + +const wait = ms => new Promise(resolve => setTimeout(resolve, ms)); + +function transport(_) { + return { + send(envelope) { + // eslint-disable-next-line no-console + console.log(inspect(envelope, false, null, true)); + return Promise.resolve({ statusCode: 200 }); + }, + flush() { + return new Promise(resolve => setTimeout(() => resolve(true), 1000)); + }, + }; +} + +Sentry.init({ + debug: true, + dsn: 'https://7fa19397baaf433f919fbe02228d5470@o1137848.ingest.sentry.io/6625302', + integrations: [nodeProfilingIntegration()], + tracesSampleRate: 1.0, + profilesSampleRate: 1.0, + transport, +}); + +Sentry.startSpan({ name: 'Precompile test' }, async () => { + await wait(500); +}); diff --git a/dev-packages/e2e-tests/test-applications/node-profiling/index.ts b/dev-packages/e2e-tests/test-applications/node-profiling/index.ts deleted file mode 100644 index e956a1d9de33..000000000000 --- a/dev-packages/e2e-tests/test-applications/node-profiling/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as Sentry from '@sentry/node'; -import { nodeProfilingIntegration } from '@sentry/profiling-node'; - -const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); - -Sentry.init({ - dsn: 'https://7fa19397baaf433f919fbe02228d5470@o1137848.ingest.sentry.io/6625302', - integrations: [nodeProfilingIntegration()], - tracesSampleRate: 1.0, - profilesSampleRate: 1.0, -}); - -Sentry.startSpan({ name: 'Precompile test' }, async () => { - await wait(500); -}); diff --git a/dev-packages/e2e-tests/test-applications/node-profiling/package.json b/dev-packages/e2e-tests/test-applications/node-profiling/package.json index d78ca10fa25d..a4e704ce7cba 100644 --- a/dev-packages/e2e-tests/test-applications/node-profiling/package.json +++ b/dev-packages/e2e-tests/test-applications/node-profiling/package.json @@ -3,13 +3,15 @@ "version": "1.0.0", "private": true, "scripts": { - "typecheck": "tsc --noEmit", - "build": "node build-cjs.mjs && node build-esm.mjs", - "test": "node dist/cjs/index.js && node --experimental-require-module dist/cjs/index.js && node dist/esm/index.mjs", + "test": "node dist/cjs/index.js && node dist/cjs/index.js && node dist/esm/index.mjs", "clean": "npx rimraf node_modules dist", "test:electron": "$(pnpm bin)/electron-rebuild && playwright test", - "test:build": "pnpm run typecheck && pnpm run build", - "test:assert": "pnpm run test && pnpm run test:electron" + "test:build": "npm run test:build:esbuild && npm run test:build:webpack", + "test:build:webpack": "webpack --config webpack.config.mjs", + "test:build:esbuild": "node esbuild.mjs", + "test:assert": "npm run test:assert:esbuild && npm run test:assert:webpack", + "test:assert:esbuild": "node dist/esbuild/index.js", + "test:assert:webpack": "node dist/webpack/index.js" }, "dependencies": { "@electron/rebuild": "^3.7.0", @@ -18,7 +20,10 @@ "@sentry/node": "latest || *", "@sentry/profiling-node": "latest || *", "electron": "^33.2.0", - "esbuild": "0.20.0" + "esbuild": "0.24.2", + "webpack": "5.97.1", + "webpack-cli": "6.0.1", + "node-loader": "2.1.0" }, "volta": { "extends": "../../package.json" diff --git a/dev-packages/e2e-tests/test-applications/node-profiling/webpack.config.mjs b/dev-packages/e2e-tests/test-applications/node-profiling/webpack.config.mjs new file mode 100644 index 000000000000..a8026318c1af --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/node-profiling/webpack.config.mjs @@ -0,0 +1,24 @@ +import * as path from 'path'; + +const __dirname = path.dirname(new URL(import.meta.url).pathname); + +export default { + mode: 'production', + entry: './index.js', + target: 'node', + output: { + path: path.resolve(__dirname, 'dist', 'webpack'), + filename: 'index.js', + }, + resolve: { + extensions: ['.js', '.node'], + }, + module: { + rules: [ + { + test: /\.node$/, + loader: 'node-loader', + }, + ], + }, +}; diff --git a/packages/profiling-node/lib/esm/index.js b/packages/profiling-node/lib/esm/index.js new file mode 100644 index 000000000000..e4a4d45ef49d --- /dev/null +++ b/packages/profiling-node/lib/esm/index.js @@ -0,0 +1,2 @@ +import { nodeProfilingIntegration } from '../cjs/index.js'; +export { nodeProfilingIntegration }; diff --git a/packages/profiling-node/lib/esm/package.json b/packages/profiling-node/lib/esm/package.json new file mode 100644 index 000000000000..3dbc1ca591c0 --- /dev/null +++ b/packages/profiling-node/lib/esm/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/packages/profiling-node/rollup.npm.config.mjs b/packages/profiling-node/rollup.npm.config.mjs index a9c148306709..dbedf9e8ae19 100644 --- a/packages/profiling-node/rollup.npm.config.mjs +++ b/packages/profiling-node/rollup.npm.config.mjs @@ -17,4 +17,7 @@ export default makeNPMConfigVariants( ], }, }), + { + emitEsm: false, + }, ); diff --git a/packages/profiling-node/src/cpu_profiler.ts b/packages/profiling-node/src/cpu_profiler.ts index a9a6d65ce191..6e3eb8f442e0 100644 --- a/packages/profiling-node/src/cpu_profiler.ts +++ b/packages/profiling-node/src/cpu_profiler.ts @@ -1,9 +1,6 @@ -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'; import { env, versions } from 'node:process'; -import { fileURLToPath, pathToFileURL } from 'node:url'; import { threadId } from 'node:worker_threads'; import { familySync } from 'detect-libc'; import { getAbi } from 'node-abi'; @@ -18,8 +15,6 @@ import type { } from './types'; import type { ProfileFormat } from './types'; -declare const __IMPORT_META_URL_REPLACEMENT__: string; - const stdlib = familySync(); const platform = process.env['BUILD_PLATFORM'] || _platform(); const arch = process.env['BUILD_ARCH'] || _arch(); @@ -31,27 +26,16 @@ const identifier = [platform, arch, stdlib, abi].filter(c => c !== undefined && */ // eslint-disable-next-line complexity export function importCppBindingsModule(): PrivateV8CpuProfilerBindings { - // We need to work around using import.meta.url directly with __IMPORT_META_URL_REPLACEMENT__ because jest complains about it. - const importMetaUrl = - typeof __IMPORT_META_URL_REPLACEMENT__ !== 'undefined' - ? // This case is always hit when the SDK is built - __IMPORT_META_URL_REPLACEMENT__ - : // This case is hit when the tests are run - pathToFileURL(__filename).href; - - const createdRequire = createRequire(importMetaUrl); - 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 require(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 require(`${binaryPath}.node`); } // We need the fallthrough so that in the end, we can fallback to the dynamic require. @@ -59,31 +43,31 @@ export function importCppBindingsModule(): PrivateV8CpuProfilerBindings { if (platform === 'darwin') { if (arch === 'x64') { if (abi === '93') { - return createdRequire('../sentry_cpu_profiler-darwin-x64-93.node'); + return require('../sentry_cpu_profiler-darwin-x64-93.node'); } if (abi === '108') { - return createdRequire('../sentry_cpu_profiler-darwin-x64-108.node'); + return require('../sentry_cpu_profiler-darwin-x64-108.node'); } if (abi === '115') { - return createdRequire('../sentry_cpu_profiler-darwin-x64-115.node'); + return require('../sentry_cpu_profiler-darwin-x64-115.node'); } if (abi === '127') { - return createdRequire('../sentry_cpu_profiler-darwin-x64-127.node'); + return require('../sentry_cpu_profiler-darwin-x64-127.node'); } } if (arch === 'arm64') { if (abi === '93') { - return createdRequire('../sentry_cpu_profiler-darwin-arm64-93.node'); + return require('../sentry_cpu_profiler-darwin-arm64-93.node'); } if (abi === '108') { - return createdRequire('../sentry_cpu_profiler-darwin-arm64-108.node'); + return require('../sentry_cpu_profiler-darwin-arm64-108.node'); } if (abi === '115') { - return createdRequire('../sentry_cpu_profiler-darwin-arm64-115.node'); + return require('../sentry_cpu_profiler-darwin-arm64-115.node'); } if (abi === '127') { - return createdRequire('../sentry_cpu_profiler-darwin-arm64-127.node'); + return require('../sentry_cpu_profiler-darwin-arm64-127.node'); } } } @@ -91,16 +75,16 @@ export function importCppBindingsModule(): PrivateV8CpuProfilerBindings { if (platform === 'win32') { if (arch === 'x64') { if (abi === '93') { - return createdRequire('../sentry_cpu_profiler-win32-x64-93.node'); + return require('../sentry_cpu_profiler-win32-x64-93.node'); } if (abi === '108') { - return createdRequire('../sentry_cpu_profiler-win32-x64-108.node'); + return require('../sentry_cpu_profiler-win32-x64-108.node'); } if (abi === '115') { - return createdRequire('../sentry_cpu_profiler-win32-x64-115.node'); + return require('../sentry_cpu_profiler-win32-x64-115.node'); } if (abi === '127') { - return createdRequire('../sentry_cpu_profiler-win32-x64-127.node'); + return require('../sentry_cpu_profiler-win32-x64-127.node'); } } } @@ -109,68 +93,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 require('../sentry_cpu_profiler-linux-x64-musl-93.node'); } if (abi === '108') { - return createdRequire('../sentry_cpu_profiler-linux-x64-musl-108.node'); + return require('../sentry_cpu_profiler-linux-x64-musl-108.node'); } if (abi === '115') { - return createdRequire('../sentry_cpu_profiler-linux-x64-musl-115.node'); + return require('../sentry_cpu_profiler-linux-x64-musl-115.node'); } if (abi === '127') { - return createdRequire('../sentry_cpu_profiler-linux-x64-musl-127.node'); + return require('../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 require('../sentry_cpu_profiler-linux-x64-glibc-93.node'); } if (abi === '108') { - return createdRequire('../sentry_cpu_profiler-linux-x64-glibc-108.node'); + return require('../sentry_cpu_profiler-linux-x64-glibc-108.node'); } if (abi === '115') { - return createdRequire('../sentry_cpu_profiler-linux-x64-glibc-115.node'); + return require('../sentry_cpu_profiler-linux-x64-glibc-115.node'); } if (abi === '127') { - return createdRequire('../sentry_cpu_profiler-linux-x64-glibc-127.node'); + return require('../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 require('../sentry_cpu_profiler-linux-arm64-musl-93.node'); } if (abi === '108') { - return createdRequire('../sentry_cpu_profiler-linux-arm64-musl-108.node'); + return require('../sentry_cpu_profiler-linux-arm64-musl-108.node'); } if (abi === '115') { - return createdRequire('../sentry_cpu_profiler-linux-arm64-musl-115.node'); + return require('../sentry_cpu_profiler-linux-arm64-musl-115.node'); } if (abi === '127') { - return createdRequire('../sentry_cpu_profiler-linux-arm64-musl-127.node'); + return require('../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 require('../sentry_cpu_profiler-linux-arm64-glibc-93.node'); } if (abi === '108') { - return createdRequire('../sentry_cpu_profiler-linux-arm64-glibc-108.node'); + return require('../sentry_cpu_profiler-linux-arm64-glibc-108.node'); } if (abi === '115') { - return createdRequire('../sentry_cpu_profiler-linux-arm64-glibc-115.node'); + return require('../sentry_cpu_profiler-linux-arm64-glibc-115.node'); } if (abi === '127') { - return createdRequire('../sentry_cpu_profiler-linux-arm64-glibc-127.node'); + return require('../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`); + const built_from_source_path = resolve(__dirname, '..', `sentry_cpu_profiler-${identifier}`); + return require(`${built_from_source_path}.node`); } const PrivateCpuProfilerBindings: PrivateV8CpuProfilerBindings = importCppBindingsModule();