Open P4sca1 opened 1 month ago
This should be fixed by our import-in-the-middle
fixes. @P4sca1 could you try using the patch we have to validate this: https://github.com/getsentry/sentry-javascript/issues/12242#issuecomment-2133993135
If the patch works, fix is released with https://github.com/open-telemetry/opentelemetry-js/pull/4745
I tried to apply the following patch file using ppm, but still have the same issue.
diff --git a/hook.js b/hook.js
index 79a2e5b..9539e87 100644
--- a/hook.js
+++ b/hook.js
@@ -3,6 +3,7 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.
const { randomBytes } = require('crypto')
+const { URL } = require('url')
const specifiers = new Map()
const isWin = process.platform === 'win32'
@@ -91,6 +92,24 @@ function isStarExportLine (line) {
return /^\* from /.test(line)
}
+function isBareSpecifier (specifier) {
+ // Relative and absolute paths are not bare specifiers.
+ if (
+ specifier.startsWith('.') ||
+ specifier.startsWith('/')) {
+ return false
+ }
+
+ // Valid URLs are not bare specifiers. (file:, http:, node:, etc.)
+ try {
+ // eslint-disable-next-line no-new
+ new URL(specifier)
+ return false
+ } catch (err) {
+ return true
+ }
+}
+
/**
* @typedef {object} ProcessedModule
* @property {string[]} imports A set of ESM import lines to be added to the
@@ -128,6 +147,7 @@ async function processModule ({
srcUrl,
context,
parentGetSource,
+ parentResolve,
ns = 'namespace',
defaultAs = 'default'
}) {
@@ -154,13 +174,22 @@ async function processModule ({
if (isStarExportLine(n) === true) {
const [, modFile] = n.split('* from ')
const normalizedModName = normalizeModName(modFile)
- const modUrl = new URL(modFile, srcUrl).toString()
const modName = Buffer.from(modFile, 'hex') + Date.now() + randomBytes(4).toString('hex')
+ let modUrl
+ if (isBareSpecifier(modFile)) {
+ // Bare specifiers need to be resolved relative to the parent module.
+ const result = await parentResolve(modFile, { parentURL: srcUrl })
+ modUrl = result.url
+ } else {
+ modUrl = new URL(modFile, srcUrl).toString()
+ }
+
const data = await processModule({
srcUrl: modUrl,
context,
parentGetSource,
+ parentResolve,
ns: `$${modName}`,
defaultAs: normalizedModName
})
@@ -180,7 +209,7 @@ async function processModule ({
// needs to utilize that new name while being initialized from the
// corresponding origin namespace.
const renamedExport = matches[2]
- setters.set(`$${renamedExport}${ns}`, `
+ setters.set(`$${renamedExport}`, `
let $${renamedExport} = ${ns}.default
export { $${renamedExport} as ${renamedExport} }
set.${renamedExport} = (v) => {
@@ -191,7 +220,7 @@ async function processModule ({
continue
}
- setters.set(`$${n}` + ns, `
+ setters.set(`$${n}`, `
let $${n} = ${ns}.${n}
export { $${n} as ${n} }
set.${n} = (v) => {
@@ -229,7 +258,19 @@ function addIitm (url) {
}
function createHook (meta) {
+ let cachedResolve
+ const iitmURL = new URL('lib/register.js', meta.url).toString()
+
async function resolve (specifier, context, parentResolve) {
+ cachedResolve = parentResolve
+ // See github.com/DataDog/import-in-the-middle/pull/76.
+ if (specifier === iitmURL) {
+ return {
+ url: specifier,
+ shortCircuit: true
+ }
+ }
+
const { parentURL = '' } = context
const newSpecifier = deleteIitm(specifier)
if (isWin && parentURL.indexOf('file:node') === 0) {
@@ -253,6 +294,15 @@ function createHook (meta) {
return url
}
+ // If the file is referencing itself, we need to skip adding the iitm search params
+ if (url.url === parentURL) {
+ return {
+ url: url.url,
+ shortCircuit: true,
+ format: url.format
+ }
+ }
+
specifiers.set(url.url, specifier)
return {
@@ -262,14 +312,14 @@ function createHook (meta) {
}
}
- const iitmURL = new URL('lib/register.js', meta.url).toString()
async function getSource (url, context, parentGetSource) {
if (hasIitm(url)) {
const realUrl = deleteIitm(url)
const { imports, namespaces, setters: mapSetters } = await processModule({
srcUrl: realUrl,
context,
- parentGetSource
+ parentGetSource,
+ parentResolve: cachedResolve
})
const setters = Array.from(mapSetters.values())
"pnpm": {
"patchedDependencies": {
"import-in-the-middle@1.7.4": "patches/import-in-the-middle@1.7.4.patch"
}
}
Here is how I import prisma:
const require = createRequire(import.meta.url)
const client = require('@prisma/client').PrismaClient as typeof PrismaClient
Shoot. one last thing to try then, could you override import-in-the-middle
to use 1.8.0
to see if that fixes it?
package.json
{
"pnpm": {
"overrides": {
"import-in-the-middle": "^1.8.0",
}
}
}
if this doesn't work, it's def another bug we have to look into. We'll investigate and fix asap. Sorry for the trouble.
It looks like this might be a different bug caused by the CJS evaluation of import-in-the-middle
. I found something similar but different here with the util-deprecate
package.
@P4sca1 is there any reason you're doing this:
const require = createRequire(import.meta.url)
const client = require('@prisma/client').PrismaClient as typeof PrismaClient
Rather than this?
import { PrismaClient } from '@prisma/client'
Prisma is a CJS package and does not support ESM yet. I think you can't just import CJS packages in an ESM environment, but I will try if it works that way.
you can't just import CJS packages in an ESM environment
import { X } from 'some-cjs-lib'
and import * as lib from 'some-cjs-lib'
is supported by Node but it can sometimes be tricky with certain kinds of default exports, especially when a bundler is being used.
It is require(esm)
that is currently behind an experimental flag.
I think this is the cause: https://github.com/DataDog/import-in-the-middle/issues/95
Working on a fix!
Importing Prisma using import { PrismaClient } from '@prisma/client'
in an ESM environment works. The workaround using createRequire
is not (or no longer?) required.
The issue with import-in-the-middle persists, no matter how Prisma is imported. Thank you for working on a fix! :)
I've just tested import { PrismaClient } from '@prisma/client'
directly with import-in-the-middle@1.8.0
and it handles it correctly without error.
Are you using TypeScript and transpiling to CommonJs? Is there anything else about your setup that might help me reproduce this?
Here's my tsconfig.json:
{
"extends": ["@tsconfig/node-lts", "@tsconfig/strictest"],
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
// Use ESM
"module": "nodenext",
"moduleResolution": "nodenext",
// Use helpers from tslib, instead of inlining them
"noEmitHelpers": true,
"importHelpers": true,
// Generate inline source maps
"sourceMap": true,
"inlineSources": true,
"sourceRoot": "/",
// Don not require exact optional property types. The generated prisma client does not work with it.
"exactOptionalPropertyTypes": false
},
"include": ["src/**/*.ts", "./types/**/*.d.ts"]
}
I run pnpm run build && pnpm run start
for testing. My (stripped down) package.json looks like this:
{
"scripts": {
"tsc:build": "tsc --project ./tsconfig.json",
"build": "prisma generate && pnpm run tsc:build",
"start": "node --import ./instrument.js ./dist/main.js",
},
"type": "module",
"dependencies": {
"@prisma/client": "5.14.0",
"@sentry/node": "8.7.0",
"@sentry/profiling-node": "8.7.0",
"prisma": "5.14.0",
"tslib": "2.6.2",
},
"devDependencies": {
"@sentry/cli": "2.32.1",
"@swc-node/register": "1.9.0",
"@tsconfig/node-lts": "20.1.3",
"@tsconfig/strictest": "2.0.5",
"typescript": "5.4.5"
},
"packageManager": "pnpm@9.1.4",
"pnpm": {
"overrides": {
"import-in-the-middle": "1.8.0"
}
}
}
@timfish I created a minimal reproduction here: https://codesandbox.io/p/devbox/sentry-issue-12325-z9jfx7
Run node --import ./instrument.js index.js
to reproduce the error.
Because prisma is CJS, I think this is fixed by https://github.com/DataDog/import-in-the-middle/pull/96 but I need to confirm
This should hopefully have been fixed by the numerous PRs recently merged at import-in-the-middle
.
While we wait for this to be released, there is a patch available that combines all the fixes. If anyone can confirm this patch fixes this issue that would be super helpful!
The issue persists with import-in-the-middle@1.8.1
. I updated my reproduction with the latest version.
Is there an existing issue for this?
How do you use Sentry?
Sentry Saas (sentry.io)
Which SDK are you using?
@sentry/node
SDK Version
8.7.0
Framework Version
No response
Link to Sentry event
No response
SDK Setup
Steps to Reproduce
I migrated my code to Sentry v8 and can no longer start my application. I start my app using
node --import ./instrument.js ./dist/main.js
. I usepnpm
as my package manager.Expected Result
Prisma v8 should work using ESM, pnpm, and prisma.
Actual Result