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

Bug: Cannot find module when running with esbuild #7032

Closed
StevenGBrown opened this issue Nov 25, 2021 · 12 comments · Fixed by #7034
Closed

Bug: Cannot find module when running with esbuild #7032

StevenGBrown opened this issue Nov 25, 2021 · 12 comments · Fixed by #7034

Comments

@StevenGBrown
Copy link

Issue description

I'm using esbuild to bundle my code, along with a dependency on discord.js, before deploying it to AWS Lambda.

https://esbuild.github.io/

Read this comment on why bundling is important for some use cases other than Web Development. (thanks @nrauschcom)

It fails due to the imports in src/client/websocket/handlers/index.js which are generated from Constants.WSEvents. If that is fixed or commented out, then it fails due to the imports in ActionsManager.js which are generated from a directory listing.

How to reproduce

  1. Create package.json file:
{
  "dependencies": {
    "discord.js": "13.3.1"
  },
  "devDependencies": {
    "esbuild": "0.13.14"
  }
}
  1. Create index.js file:
const { Client, Intents } = require("discord.js");
new Client({ intents: [Intents.FLAGS.GUILDS] });
  1. Bundle index.js with esbuild and then run with it node:
$ npm install
$ ./node_modules/.bin/esbuild index.js --bundle --platform=node --target=node16 | node
  1. node fails with "Error: Cannot find module" thrown from src/client/websocket/handlers/index.js:
node:internal/modules/cjs/loader:936
  throw err;
  ^

Error: Cannot find module './READY.js'
Require stack:
- /Users/stevengbrown/Documents/discordjstest/[stdin]
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at node_modules/discord.js/src/client/websocket/handlers/index.js ([stdin]:19177:24)
    at __require ([stdin]:21:44)
    at node_modules/discord.js/src/client/websocket/WebSocketManager.js ([stdin]:19191:26)
    at __require ([stdin]:21:44)
    at node_modules/discord.js/src/client/Client.js ([stdin]:28474:28)
    at __require ([stdin]:21:44) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [ '/Users/stevengbrown/Documents/discordjstest/[stdin]' ]
}

Workaround

discord.js can be marked as external when using esbuild which means it isn't included in the bundle and discord.js along with all of its direct and transitive dependencies must be copied across from the node_modules directory instead. It is possible to have a script do this, but of course it would nicer if discord.js worked out of the box.

https://esbuild.github.io/api/#non-analyzable-imports

History

Related to issues #6680 and #6681.

PR #6102 changed ActionsManager.js to generate the imports from a directory listing, unintentionally breaking bundlers (it was intended as a refactor).

PR #6682 proposed to revert ActionsManager.js to use manual imports, but was closed without merging due to maintainability concerns.

PR #6709 fixed this issue for Webpack by making use of require.context, but not for other bundlers such as esbuild.

Possible solutions

esbuild requires the import paths to be string literals. This would make discord.js compatible with both esbuild and Webpack.

Either:

  1. Update src/client/websocket/handlers/index.js and ActionsManager.js to use manual imports.

OR

  1. Have a script automatically generate those imports from the directory listings during commit, npm install, npm test and npm publish.

With either solution, a check would be added to make sure that every entry in Constants.WSEvents has an associated event handler.

I'm happy to prepare a PR.

Code sample

const { Client, Intents } = require("discord.js");
new Client({ intents: [Intents.FLAGS.GUILDS] });

discord.js version

13.3.1

Node.js version

16.13.0

Operating system

macOS Big Sur

Priority this issue should have

Medium (should be fixed soon)

Which partials do you have configured?

No Partials

Which gateway intents are you subscribing to?

GUILDS

I have tested this issue on a development release

802a5ac

@StevenGBrown
Copy link
Author

Another possible solution:

  1. Use Webpack to build discord.js before publishing it to npm.

@kyranet
Copy link
Member

kyranet commented Nov 25, 2021

We'll most likely just revert the dynamic import thing, too bothersome to keep up and has only given us problems.

What once was "simple", turned out to be extremely complex and complicated.

@xrzhuang
Copy link

hi following up here i recently migrated my aws lambda to use esbuild as well and discord.js seems to be breaking

not sure if it's related to this issue or if you would like a new issue:

errorMessage    
Cannot read properties of undefined (reading 'handle')
errorType    
TypeError
stack.0    
TypeError: Cannot read properties of undefined (reading 'handle')
stack.1    
at Object.qye.exports (/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_CREATE.js:4:32)
stack.2    
at ZU.handlePacket (/node_modules/discord.js/src/client/websocket/WebSocketManager.js:352:29)
stack.3    
at $U.onPacket (/node_modules/discord.js/src/client/websocket/WebSocketShard.js:481:22)
stack.4    
at $U.onMessage (/node_modules/discord.js/src/client/websocket/WebSocketShard.js:321:10)
stack.5    
at pt.s (/node_modules/ws/lib/event-target.js:199:18)
stack.6    
at pt.emit (node:events:527:28)
stack.7    
at PU.llt (/node_modules/ws/lib/websocket.js:1178:20)
stack.8    
at PU.emit (node:events:527:28)
stack.9    
at PU.dataMessage (/node_modules/ws/lib/receiver.js:528:14)
stack.10    
at PU.getData (/node_modules/ws/lib/receiver.js:446:17)

@rumblefrog
Copy link
Contributor

Hey @xrzhuang , I seem to have the same issue building with ESBuild. Did you ever figure out the cause?

@xrzhuang
Copy link

xrzhuang commented Apr 2, 2023

@rumblefrog no bruh i talked to a bunch of the engineers at discord and they told me to workaround instead. i did something weird where the specific fargate task using the lib isn't bundling with esbuild. i know it's whack

@rumblefrog
Copy link
Contributor

@rumblefrog no bruh i talked to a bunch of the engineers at discord and they told me to workaround instead. i did something weird where the specific fargate task using the lib isn't bundling with esbuild. i know it's whack

Hm alright, yeah it's not ideal. I worked around it with setting packages external and archiving my node_modules directory to ship with the bundle.

@xrzhuang
Copy link

xrzhuang commented Apr 2, 2023

jesus im so sorry lmao

@nrauschcom
Copy link
Contributor

@rumblefrog what version of d.js are you using?
In current versions, there are no file system imports and rollup should be able to pick up the correct handlers.

@rumblefrog
Copy link
Contributor

rumblefrog commented Apr 2, 2023

@rumblefrog what version of d.js are you using? In current versions, there are no file system imports and rollup should be able to pick up the correct handlers.

I'm currently on d.js 14.8.0

This is my esbuild config if it helps.

import { build, analyzeMetafile } from 'esbuild';

async function main() {
    const result = await build({
        entryPoints: ['src/index.ts'],
        bundle: true,
        outfile: 'build/index.js',
        platform: 'node',
        target: ['node18'],
        sourcemap: 'inline',
        minify: true,
        minifyWhitespace: true,
        minifyIdentifiers: true,
        legalComments: 'none',
        metafile: true,
        alias: {
            '@': './src',
        },
    });

    console.log(await analyzeMetafile(result.metafile));
}

main();

@nrauschcom
Copy link
Contributor

It seems like you need to specify keepNames: true (or maybe minifyIdentifiers: false) for esbuild to keep d.js intact.

d.js relies on some class names, but your bundler is trying to minify the code, changing MessageCreateAction to some random string, so the call to actions['MessageCreate'] will fail.

@rumblefrog
Copy link
Contributor

It seems like you need to specify keepNames: true (or maybe minifyIdentifiers: false) for esbuild to keep d.js intact.

d.js relies on some class names, but your bundler is trying to minify the code, changing MessageCreateAction to some random string, so the call to actions['MessageCreate'] will fail.

Oh, thank you, @nrauschcom , that seems to have worked!

@kyranet
Copy link
Member

kyranet commented Apr 2, 2023

I'm locking this issue since the issues you mentioned are a completely different one. Feel free to open a new issue if you encounter an issue, I'll be locking this one since it was resolved over a year ago.

@discordjs discordjs locked as resolved and limited conversation to collaborators Apr 2, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants