evanw / esbuild

An extremely fast bundler for the web
https://esbuild.github.io/
MIT License
38.22k stars 1.16k forks source link

Built-in dependencies working with --bundle --platform=node sometimes. Suggested regex to work #3888

Open admartinez-edicom opened 3 months ago

admartinez-edicom commented 3 months ago

I'm trying to use esbuild in order to bundle into a single file our production node code. However we are having some troubles with the built-in modules of node (http, https and fs but I believe it will happen with all of them).

After analyzing the generated bundle I came up with a very silly solution that is applying this regex to the final bundle: sed 's/moduleName = filename;/moduleName = filename;\\n basedir = \\x27core:\\x27;/g'

While writing this issue we realize that it happens sometimes but I cannot determinate the reason.

I have created a repo with a sample code that behaves similar to my production code.

There are 3 files in this repo and 4 scripts:

The error when failing is:

Error: Cannot find module '/home/admartinez/Desktop/esbuild/modules/http.js' Require stack: - /home/admartinez/Desktop/esbuild/app-ko.js at Module._resolveFilename (node:internal/modules/cjs/loader:1140:15) at Module._load (node:internal/modules/cjs/loader:981:27) at Module.require (node:internal/modules/cjs/loader:1231:19) at Module.patchedRequire (/home/admartinez/Desktop/esbuild/app-ko.js:16470:39) at Hook._require.Module.require (/home/admartinez/Desktop/esbuild/app-ko.js:16438:31) at require (node:internal/modules/helpers:177:18) at Instrumentation._patchModule (/home/admartinez/Desktop/esbuild/app-ko.js:22303:23) at /home/admartinez/Desktop/esbuild/app-ko.js:22243:24 at Module.patchedRequire (/home/admartinez/Desktop/esbuild/app-ko.js:16546:32) at Hook._require.Module.require (/home/admartinez/Desktop/esbuild/app-ko.js:16438:31) at require (node:internal/modules/helpers:177:18) at node_modules/methods/index.js (/home/admartinez/Desktop/esbuild/app-ko.js:61564:16) at require (/home/admartinez/Desktop/esbuild/app-ko.js:11:50) at node_modules/express/lib/router/route.js (/home/admartinez/Desktop/esbuild/app-ko.js:61611:19) at __require (/home/admartinez/Desktop/esbuild/app-ko.js:11:50) at node_modules/express/lib/router/index.js (/home/admartinez/Desktop/esbuild/app-ko.js:61734:17) at require (/home/admartinez/Desktop/esbuild/app-ko.js:11:50) at node_modules/express/lib/application.js (/home/admartinez/Desktop/esbuild/app-ko.js:64408:18) at require (/home/admartinez/Desktop/esbuild/app-ko.js:11:50) at node_modules/express/lib/express.js (/home/admartinez/Desktop/esbuild/app-ko.js:66164:17) at __require (/home/admartinez/Desktop/esbuild/app-ko.js:11:50) at node_modules/express/index.js (/home/admartinez/Desktop/esbuild/app-ko.js:66230:23) at require (/home/admartinez/Desktop/esbuild/app-ko.js:11:50) at Object. (/home/admartinez/Desktop/esbuild/app-ko.js:66236:30) at Module._compile (node:internal/modules/cjs/loader:1364:14) at Module._extensions..js (node:internal/modules/cjs/loader:1422:10) at Module.load (node:internal/modules/cjs/loader:1203:32) at Module._load (node:internal/modules/cjs/loader:1019:12) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:128:12) at node:internal/main/run_main_module:28:49 { code: 'MODULE_NOT_FOUND', requireStack: [ '/home/admartinez/Desktop/esbuild/app-ko.js' ] }

I came up with this solution after realizing that when the variable basediris empty, the generated file use the current working directory to resolve modules. So in the "core-module-branch" I set this variable to 'core:'

if (core === true) { if (hasWhitelist === true && modules.includes(filename) === false) { debug("ignoring core module not on whitelist: %s", filename); return exports3; } moduleName = filename; basedir = 'core:'; // new code } else if (hasWhitelist === true && modules.includes(filename)) { const parsedPath = path.parse(filename); moduleName = parsedPath.name; basedir = parsedPath.dir; } else {

Could you please give me any feedback? We try the --target argument with all sorts of value but all of them generate the same code

hyrious commented 3 months ago

That error was because elastic-apm-node adds a custom hook to replace some builtin and thrid-party modules. It redirects the require call to modules like http and replace that with the file under itself. This code pattern is not bundle-able since it relies on a real file structure during runtime.

Your ok1 script works because it just doesn't hit those hooks. However, when express imports http, it hits and cannot find a ./modules/http.js relative to the bundled file.

In summary, you'd better not bundle elastic-apm-node with either --external:elastic-apm-node or --packages=external.