#Convert require into import problem

136 messages · Page 1 of 1 (latest)

opal pelicanBOT
  • Consider reading #how-to-get-help to improve your question!
  • Explain what exactly your issue is.
  • Post the full error stack trace, not just the top part!
  • Show your code!
  • Issue solved? Press the button!
leaden marlin

i Know that const {blabla} = require("discordjs") is converted to import {blabla} from "discordjs", but idk how to convert this code

raw crane

import fun from <path>
fun(client) maybe

Idk if yoy can do one liners

import <path>(client) maybe but I doubt it

leaden marlin

ok thanks

leaden marlin
raw crane import <path>(client) *maybe* but I doubt it

actually, I can't import. It's in a for loop:

const functionFolders = readdirSync("./src/functions");
for (const folder of functionFolders) {
  const functionFiles = readdirSync(`./src/functions/${folder}`).filter(
    (file) => file.endsWith(".js")
  );
  for (const file of functionFiles)
    require(`./functions/${folder}/${file}`)(client);
}

ohh wait

raw crane

const { default } = await import(<path>)
default(client)

Or similar, idk your setup

leaden marlin

im getting this error:
TypeError: client.handleEvents is not a function
at file:///C:/Users/Waggerra/Documents/Discord/BOTS%20Discord/Tobor/src/index.js:28:8
at ModuleJob.run (node:internal/modules/esm/module_job:218:25)
at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)
at async loadESM (node:internal/process/esm_loader:28:7)
at async handleMainPromise (node:internal/modules/run_main:113:12)

Node.js v20.11.1

I have this script:

import "dotenv/config";
const { TOKEN, databaseToken } = process.env;
import { connect } from "mongoose";
import { Client, Collection } from "discord.js";
import { readdirSync } from "fs";

const client = new Client({ intents: 32767 /* GatewayIntentBits.Guilds */ });
client.commands = new Collection();
client.buttons = new Collection();
client.selectMenus = new Collection();
client.modals = new Collection();
client.commandArray = [];

const functionFolders = readdirSync("./src/functions");
for (const folder of functionFolders) {
  const functionFiles = readdirSync(`./src/functions/${folder}`).filter(
    (file) => file.endsWith(".js")
  );

  for (const file of functionFiles) {
    //require(`./functions/${folder}/${file}`)(client);
    import(`./functions/${folder}/${file}`).then((module) => {
      module.default(client);
    });
  }
}

client.handleEvents();
client.handleCommands();
client.handleComponents();
client.login(TOKEN);

(async () => {
  await connect(databaseToken).catch(console.error);
})();

So it's an import problem.

it's a problem with the for (file of functionFiles) loop

Convert require into import problem

raw crane

Show how you export that file

leaden marlin
import "dotenv/config";
import { REST } from "@discordjs/rest";
import { Routes } from "discord-api-types/v9";
import { readdirSync } from "fs";

export default (client) => {
  client.handleCommands = async () => {
    const commandFolders = readdirSync("./src/commands");
    for (const folder of commandFolders) {
      const commandFiles = readdirSync(`./src/commands/${folder}`)
        .filter((file) => file.endsWith(".js"));

      const { commands, commandArray } = client;
      for (const file of commandFiles) {
        const command = require(`../../commands/${folder}/${file}`);
        commands.set(command.data.name, command);
        commandArray.push(command.data.toJSON());
        console.log(
          `Command: ${command.data.name} has passed through the handler.`
        );
      }
    }

    const clientId = "983040401747365888";
    const guildId = "1107327478332145684";
    const rest = new REST({ version: "9" }).setToken(process.env.TOKEN);
    try {
      console.log("Started refreshing application (/) commands.");

      /*//*TEST / SINGLE SERVER
      await rest.put(Routes.applicationGuildCommands(clientId, guildId), {
        body: client.commandArray,
      });*/

      //!GLOBAL
      await rest.put(Routes.applicationCommands(clientId), {
        body: client.commandArray,
      })

      console.log("Successfully reloaded application (/) commands.");
    } catch (error) {
      console.log(error);
    }
  };
};

I converted all the files. It's just the index.js file that burn my balls 🔥 😡

import { readdirSync } from "fs";

export default (client) => {
 BLABLA
};

@raw crane

regal bough

what did you end up with when trying to convert it?

leaden marlin

no It don't work.

raw crane

Can you show the updated code and maybe log what the import returns with?

leaden marlin

What I want, is to run client.handleEvents(). The problem is that it says "client.handleEvents" is not a function

regal bough

import(...) is async, you need to await it

raw crane

They use .then

regal bough

yeah but it seems like the rest of the code depends on what happens in the .then

so maybe try moving the rest of the code in the .then

or use await

leaden marlin
const functionFolders = readdirSync("./src/functions");
for (const folder of functionFolders) {
  const functionFiles = readdirSync(`./src/functions/${folder}`).filter(
    (file) => file.endsWith(".js")
  );

  for (const file of functionFiles) {
    //require(`./functions/${folder}/${file}`)(client);
    await import(`./functions/${folder}/${file}`)
  .then(module => {
    module.default(client);
  });
  }
}

//import {handleEvents} from "./functions/handlers/handleEvents";
client.handleEvents();
client.handleCommands();
client.handleComponents();
client.login(TOKEN);

I also get this error:
import { connection } from "mongoose";

raw crane

That’s not an error

leaden marlin

SyntaxError: Named export 'connection' not found. The requested module 'mongoose' is a CommonJS module, which may not support all module.exports as named exports.

man, I have to switch to ESM, and now I have to use CommonJS. What the hell is doing discordjs ?

raw crane

discordjs is fine, it’s everything else

What is the client.handleEvents function

leaden marlin
import { readdirSync } from "fs";
import { connection } from "mongoose";

export default client => {
  client.handleEvents = async () => {
    const eventFolders = readdirSync("./src/events");
    for (const folder of eventFolders) {
      const eventFiles = readdirSync(`./src/events/${folder}`)
        .filter((file) => file.endsWith(".js"));
      switch (folder) {
        case "client":
          for (const file of eventFiles) {
            const event = require(`../../events/${folder}/${file}`);
            if (event.once)
              client.once(event.name, (...args) =>
                event.execute(...args, client)
              );
            else
              client.on(event.name, (...args) =>
                event.execute(...args, client)
              );
          }
          break;

        case "mongo":
          for (const file of eventFiles) {
            const event = require(`../../events/${folder}/${file}`);
            if (event.once)
              connection.once(event.name, (...args) =>
                event.execute(...args, client)
              );
            else
              connection.on(event.name, (...args) =>
                event.execute(...args, client)
              );
          }
          break;

        default:
          break;
      }
    }
  };
};

raw crane

Honestly I ain’t too sure. I’m not very very familiar with import export syntax so you’ll have to wait for someone else

regal bough

this kind of mutation is awkward

leaden marlin

?

the thing is that I have like a double problem. One with the mongodb support and one with the import / export problem

uhhh I don't understand

how do other devs do ?

regal bough

if you really need it to be like this, move all your initialisation code into an async function just to make things easier to write:

async function start() {
  const functionFolders = readdirSync("./src/functions");
  for (const folder of functionFolders) {
    const functionFiles = readdirSync(`./src/functions/${folder}`).filter(
      (file) => file.endsWith(".js")
    );
  
    for (const file of functionFiles) {
      const { default } = await import(`./functions/${folder}/${file}`);
      default(client);
    }
  }

  client.handleEvents();
  client.handleCommands();
  client.handleComponents();
  client.login(TOKEN);
}

start();

for mongoose, what version are you using?

leaden marlin

how can I know ?? I tried npm version but it don't show the version

regal bough

type npm ls mongoose

leaden marlin

thanks: mongoose@8.3.2

regal bough

that seems to be the latest version

lemme try something on my side

leaden marlin

ok 👍

regal bough

this is my current repro, and the importing seems to work just fine

import { Mongoose } from 'mongoose';
import { Client } from 'discord.js';
import fs from 'fs/promises';

async function start() {
  const mongoose = new Mongoose();

  await mongoose.connect('mongodb://192.168.0.177:27017');

  const client = new Client({
    intents: [],
  });

  const configRaw = await fs.readFile('./config.json');

  const config = JSON.parse(configRaw);

  const { token } = config;

  client.login(token);

  client.on('ready', () => {
    console.log('Connected.');
  });
}

start();
flat sigil

I was just going to say, I converted one of my larger projects to ESM just a week or so ago and haven't had any issues with mongoose

leaden marlin

hi. How can I convert this into ESM ?

const event = require(`../../events/${folder}/${file}`);```

@flat sigil

flat sigil

you'll need to define require

leaden marlin

Cause when I do

import event from `../../events/${folder}/${file}`

It says taht I can import only outside the module

flat sigil

so, import createRequire from node:module

and then const require = createRequire(import.meta.url);

leaden marlin

whatt the hell...
So I do
import createRequire from WHAT ?

flat sigil

and then you can use require dynamically where a module doesn't export properly for ESM

leaden marlin

import { createRequire } from "module"; ?

flat sigil

node:fs node:path node:process and so on

but thats what I had to do when I coverted to ESM because a package I use is CJS only

with no ESM alternative that I liked enough

leaden marlin
flat sigil and then `const require = createRequire(import.meta.url);`

It throws an error at:
const event = createRequire(`../../events/${folder}/${file}`);

      throw new ERR_INVALID_ARG_VALUE('filename', filename,
            ^

TypeError [ERR_INVALID_ARG_VALUE]: The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received '../../events/client/interactionCreate.js'      
    at createRequire (node:internal/modules/cjs/loader:1514:13)
    at client.handleEvents (file:///C:/Users/Waggerra/Documents/Discord/BOTS%20Discord/Tobor/src/functions/handlers/handleEvents.js:15:27)
    at start (file:///C:/Users/Waggerra/Documents/Discord/BOTS%20Discord/Tobor/src/index.js:30:10) {
  code: 'ERR_INVALID_ARG_VALUE'
}
flat sigil

hmm

whats the context of that require in your CJS code

is it like top level? or inside a function somewhere?

leaden marlin

Inside a for loop

import { readdirSync } from "fs";
import { Mongoose } from "mongoose";
import { Client } from 'discord.js';
import { createRequire } from "module";

export default client => {
  client.handleEvents = async () => {
    const eventFolders = readdirSync("./src/events");
    for (const folder of eventFolders) {
      const eventFiles = readdirSync(`./src/events/${folder}`)
        .filter((file) => file.endsWith(".js"));
      switch (folder) {
        case "client":
          for (const file of eventFiles) {
            const event = createRequire(`../../events/${folder}/${file}`);
            if (event.once)
              client.once(event.name, (...args) =>
                event.execute(...args, client)
              );
            else
              client.on(event.name, (...args) =>
                event.execute(...args, client)
              );
          }
          break;

        case "mongo":
          for (const file of eventFiles) {
            const event = createRequire(`../../events/${folder}/${file}`);
            if (event.once)
              connection.once(event.name, (...args) =>
                event.execute(...args, client)
              );
            else
              connection.on(event.name, (...args) =>
                event.execute(...args, client)
              );
          }
          break;

        default:
          break;
      }
    }
  };
};
flat sigil

ohhh

then just use import

import(<thepathhere>)

leaden marlin

just that ?

flat sigil

you may need to use another ESM to CJS hack to get __dirname back as well

leaden marlin

but I need to get the "event" value from the import

so I can do const event = import("`../../events/${folder}/${file}`")

or ```import event from ../../events/${folder}/${file}

flat sigil

neither

hold on

leaden marlin

🤯 🫡

flat sigil

well technically the first one

but you'll need to await it

is event a named export in the file? or does it have a default export?

leaden marlin

Srry but I don't understand (im new).

Actual code:

import { readdirSync } from "fs";
import { Mongoose } from "mongoose";
import { Client } from 'discord.js';
import { createRequire } from "module";

export default client => {
  client.handleEvents = async () => {
    const eventFolders = readdirSync("./src/events");
    for (const folder of eventFolders) {
      const eventFiles = readdirSync(`./src/events/${folder}`)
        .filter((file) => file.endsWith(".js"));
      switch (folder) {
        case "client":
          for (const file of eventFiles) {
            const event = import(`../../events/${folder}/${file}`)
            if (event.once)
              client.once(event.name, (...args) =>
                event.execute(...args, client)
              );
            else
              client.on(event.name, (...args) =>
                event.execute(...args, client)
              );
          }
          break;

        case "mongo":
          for (const file of eventFiles) {
            const event = import(`../../events/${folder}/${file}`)
            if (event.once)
              connection.once(event.name, (...args) =>
                event.execute(...args, client)
              );
            else
              connection.on(event.name, (...args) =>
                event.execute(...args, client)
              );
          }
          break;

        default:
          break;
      }
    }
  };
};
flat sigil

how do you export event in the event file?

leaden marlin

oh

export async function execute(interaction, client) {

export function execute() {

The first one for the "client" case, and the second one for mongo

flat sigil

you have two exported functions in the same file that are both called execute?

leaden marlin

no. I mean, the "case name" = a folder, and it do some actions for each file inside that folder. So the first one is the export of a file in "client" folder, the second one for the mongo.

flat sigil

oh I see. ok, I mean inside the actual files themselves. so each file has one export called execute, right?

leaden marlin

yes

oh well, InteractionCreate: (in client)

export async function execute(interaction, client) {```

ready:

export const once = true;
export async function execute(client) {```

In mongo:
Connected:

export function execute() {
    console.log("[Database Status]: Connected!");
}```

Connecting:
export const name = "connecting";
export async function execute() {

console.log("[Database Status]: Connecting...");

}

flat sigil

ok then yeah thats fine. so as far as I can tell, all you need to do is const event = await import(filePathHere) and then event.execute(...args or whatever you want to send through)

leaden marlin

ok thanks

flat sigil

let me know how you get on. I'm also still getting used to getting rid of stuff that can't be used in ESM

leaden marlin
flat sigil let me know how you get on. I'm also still getting used to getting rid of stuff ...

Thank you, it worked ! Now, I have a little mongodb problem. It says "connection" is not defined.
At line 34.

import { readdirSync } from "fs";
import { Mongoose } from "mongoose";
import { Client } from 'discord.js';

export default client => {
  client.handleEvents = async () => {
    const eventFolders = readdirSync("./src/events");
    for (const folder of eventFolders) {
      const eventFiles = readdirSync(`./src/events/${folder}`)
        .filter((file) => file.endsWith(".js"));
      switch (folder) {
        case "client":
          for (const file of eventFiles) {
            const event = await import(`../../events/${folder}/${file}`)
            if (event.once)
              client.once(event.name, (...args) =>
                event.execute(...args, client)
              );
            else
              client.on(event.name, (...args) =>
                event.execute(...args, client)
              );
          }
          break;

        case "mongo":
          for (const file of eventFiles) {
            const event = await import(`../../events/${folder}/${file}`)
            if (event.once)
              connection.once(event.name, (...args) =>
                event.execute(...args, client)
              );
            else
              connection.on(event.name, (...args) =>
                event.execute(...args, client)
              );
          }
          break;

        default:
          break;
      }
    }
  };
};

its at the end

I don't know how can I define it. Maybe ii can do something like const mongoose = Mongoose.new()

flat sigil

I don't see anywhere where you're defining it, yet you're importing Mongoose from mongoose and not using it. either use Mongoose.connection.on or just import connection from mongoose directly, thats what I do as I don't need all the other stuff

leaden marlin

ok thanks ill test it

flat sigil

thumbs_up

leaden marlin
leaden marlin
flat sigil I don't see anywhere where you're defining it, yet you're importing `Mongoose` f...

I'm getting this error:

    throw new ERR_MODULE_NOT_FOUND(
          ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'C:\Users\Waggerra\Documents\Discord\BOTS Discord\Tobor\src\schemas\guild' imported from C:\Users\Waggerra\Documents\Discord\BOTS Discord\Tobor\src\commands\tools\database.js
    at finalizeResolution (node:internal/modules/esm/resolve:264:11)
    at moduleResolve (node:internal/modules/esm/resolve:917:10)
    at defaultResolve (node:internal/modules/esm/resolve:1130:11)
    at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:396:12)
    at ModuleLoader.resolve (node:internal/modules/esm/loader:365:25)
    at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:240:38)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:85:39)
    at link (node:internal/modules/esm/module_job:84:36) {
  code: 'ERR_MODULE_NOT_FOUND',
  url: 'file:///C:/Users/Waggerra/Documents/Discord/BOTS%20Discord/Tobor/src/schemas/guild'
}```

The database.js script:

import { findOne, create } from "../../schemas/guild";
import { SlashCommandBuilder, Guild, PermissionFlagsBits } from "discord.js";
import { Types } from "mongoose";

export const data = new SlashCommandBuilder()
  .setName("database")
  .setDescription("Returns information from a database")
  .setDefaultMemberPermissions(PermissionFlagsBits.Administrator);
export async function execute(interaction, client) {
  let guildData = await findOne({ guildId: interaction.guildId });
  if (!guildData) {
    guildData = await create({
      _id: new Types.ObjectId(),
      guildId: interaction.guild.id,
      guildName: interaction.guild.name,
      guildIcon: interaction.guild.iconURL()
        ? interaction.guild.iconURL()
        : "None",
    });

    await guildData.save().catch(console.error);
    await interaction?.reply({
      content: `Server name: ${guildData.guildName}`,
    });
    console.log(guildData);
  } else {
    await interaction?.reply({
      content: `Server ID: ${guildData.guildId}`,
    });
    console.log(guildData);
  }
}
flat sigil

ESM modules need the file extension on the imports if the import is a local file

so import { findOne, create } from "../../schemas/guild"; becomes import { findOne, create } from "../../schemas/guild.js";

you'll need to do that with all imports in your project

but only where you import things you've eported in your own files

leaden marlin
import { findOne, create } from "../../schemas/guild.js";
                  ^^^^^^
SyntaxError: The requested module '../../schemas/guild.js' does not provide an export named 'create'
    at ModuleJob._instantiate (node:internal/modules/esm/module_job:132:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:214:5)
    at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)
    at async client.handleCommands (file:///C:/Users/Waggerra/Documents/Discord/BOTS%20Discord/Tobor/src/functions/handlers/handleCommands.js:15:25)```
[thinkgun](https://cdn.discordapp.com/emojis/1031569081696006164.webp?size=48&quality=lossless&name=thinkgun)
flat sigil

show the guild schema file

leaden marlin
const { Schema, model } = require("mongoose");
const guildSchema = new Schema({
  _id: Schema.Types.ObjectId,
  guildId: String,
  guildName: String,
  guildIcon: { type: String, default: null, required: false },
});

module.exports = model("Guild", guildSchema, "guilds");

I think its because im using module.exports

flat sigil

well you need to get rid that require statement, everything in your project needs to be ESM so that means using import

leaden marlin

so I remove the 'required' value ?

flat sigil

well const { variable } = require('module') is CJS syntax, your whole project needs to use the right syntax for ESM import { variable } from 'module'

at this point it might be better for you to find a good guide online that details how to move from CJS to ESM

I thought you were just having a few little after issues but it seems you still have lots of changes to make

leaden marlin

yup I think so 😅

flat sigil

don't be discouraged though. everntually ESM will be the norm and CJS will fade so it's good to keep up if you can :)

leaden marlin

thanks 🫡 😅

leaden marlin
flat sigil
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

const __dirname = dirname(fileURLToPath(import.meta.url));
leaden marlin

ok thanks !

flat sigil

That will replicate what __dirname does in CJS