#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
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
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