Skip to content
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

Loading files with require() in an ESM context does not load them as expected #3145

Closed
oliversalzburg opened this issue Jun 5, 2023 · 6 comments

Comments

@oliversalzburg
Copy link

I'm trying to integrate @sentry/profiling-node into our project, which comes with native binaries that I need to copy to my output directory. So achieve this, I followed the instructions at: https://github.com/getsentry/profiling-node#bundling When I build my project, I don't end up with any copied files in the output directory.

While troubleshooting, I realized that the behavior is dependent on the file extension of our entrypoint (and likely the module loaders being used within). I'm sure this could easily just be a misunderstanding on my part, or a configuration issue, but the inability to solve this leads me to report this behavior here.

@JonasBa
Copy link

JonasBa commented Jun 5, 2023

This seems related to using a .mts extension getsentry/profiling-node#157 (comment)

@evanw
Copy link
Owner

evanw commented Jun 5, 2023

The easiest way to do this is to make your packages external to your bundle: https://esbuild.github.io/api/#packages. This is covered in the "getting started" instructions for node: https://esbuild.github.io/getting-started/#bundling-for-node. If you don't want all of your packages to be external, you can mark individual ones as external instead: https://esbuild.github.io/api/#external.

@oliversalzburg
Copy link
Author

I understand that I can mark the module as external, but I wanted to benefit from the copy loader behavior to avoid having to extract the relevant files from node_modules myself.

It also just isn't clear to me why the behavior differs between the two approaches. When I look at the resulting, bundled code, I can see a require statement with a string literal. I couldn't make sense of why it's not working as expected.

@hyrious
Copy link

hyrious commented Jun 5, 2023

This happens because the ESM entry of @sentry/profiling-node uses a way of importing these .node files which cannot be analyzed by esbuild. Specifically, esbuild knows which files are bundled by detecting direct imports on them:

// ESM
import './somefile.node'
new URL('./somefile.node', import.meta.url) // tracked in #2508

// CJS
require('./somefile.node') // 'require' must be a global name

However, the ESM version of @sentry/profiling-node does not use any of the code above. Instead it polyfills its own require:

import { createRequire as aliasedCreateRequire } from "module";
var require2 = aliasedCreateRequire(import.meta.url);

require2('./somefile.node');

Such code pattern cannot be analyzed in esbuild.


Knowing above, you could come up with a solution to slightly modify the ESM entry of the package into this pattern:

import somefile_node from './somefile.node'

require2(somefile_node)

You can do that either with yarn patch or through an esbuild plugin's onLoad callback.

@adesso-os
Copy link

adesso-os commented Jun 6, 2023

@hyrious Thanks a lot for the detailed explanation ♥

I understand now that this is nothing to be fixed in esbuild, and I will follow the given guidance to find the appropriate solution for us. Thanks all.

I don't have access to my other account right now. Please feel free to close this :D

@JonasBa
Copy link

JonasBa commented Jun 6, 2023

@hyrious I am actually the author of the profiling package, first of all, thank you so much for the detailed explanation and sorry for the mistake. I will make sure that we use the correct import logic so that it gets properly resolved for ESM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants