Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I am getting a required error using graphql tools

I am building a gql server application using apollo server.

When I try to load my .graphql files using import { loadFilesSync } from '@graphql-tools/load-files', this works very well, but when I load my resolver files, i get an error

node:internal/errors:464
    ErrorCaptureStackTrace(err);
    ^

Error [ERR_REQUIRE_ESM]: require() of ES Module /userpath/index.js from /userpath/server-gql/noop.js not supported.
Instead change the require of index.js in /userpath/server-gql/noop.js to a dynamic import() which is available in all CommonJS modules.
    at Object.newLoader [as .js] (/userpath/server-gql/node_modules/pirates/lib/index.js:141:7)
    at file:///userpath/server-gql/node_modules/@graphql-tools/load-files/esm/index.js:104:33
    at Array.map (<anonymous>)
    at loadFilesSync (file:///userpath/server-gql/node_modules/@graphql-tools/load-files/esm/index.js:95:10)
    at file:///userpath/server-gql/schema.js:20:24
    at async Promise.all (index 0) {
  code: 'ERR_REQUIRE_ESM'
}

I am using "type": "module" in my package.json.

Here's my code snippet for where i get the error

import path from 'path'
import { fileURLToPath } from 'url'

import { loadFilesSync } from '@graphql-tools/load-files'
import { mergeTypeDefs, mergeResolvers } from '@graphql-tools/merge'


const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

const typesArray = loadFilesSync(path.join(__dirname, '.'), {
  recursive: true,
  extensions: ['graphql'],
})



const resolversArray = loadFilesSync(path.join(__dirname, './graphql/**/*.resolvers.js'), {
  recursive: true,
  extensions: ['js'],
})



const newResolversArray = resolversArray.slice(1)



export const typeDefs = mergeTypeDefs(typesArray)
export const resolvers = mergeResolvers(newResolversArray)

I think the error occurs in the resolvers array.

like image 307
merlin Avatar asked Oct 23 '25 14:10

merlin


1 Answers

ESM(ECMAScript modules - import/export) loading logic is asynchronous, so it seems like you can't use loadFilesSync when using ESM.

The following code will technically work but won't be right because it will use require to load the modules.

const resolversArray = await loadFiles(resolversPath);

So I think a more correct version will be:

import { pathToFileURL } from 'url';

const resolversArray = await loadFiles(resolversPath, {
        requireMethod: async (path) => {
            console.debug('Using resolver at:', path);
            return await import(pathToFileURL(path));
        }
});

Now, apparently if you're using the mjs file extension for your modules, you will need to also specify a useRequire option to load the file using the requireMethod no matter the file's extension:

import { pathToFileURL } from 'url';

const resolversArray = await loadFiles(resolversPath, {
        useRequire: true,
        requireMethod: async (path) => {
            console.debug('Using resolver at:', path);
            return await import(pathToFileURL(path));
        }
});

+You'll need to specify the extension in either the path or the extensions option

You can see the default extensions here

I just used the extension in the path, like so:

import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const resolversPath = path.join(
        __dirname, 'resolvers', '**', '*.resolvers.mjs'
);

So now every file(recursively) inside the resolvers folder that's inside the folder of the current file with the file extension of resolvers.mjs will be loaded.

Oh, on an unrelated note, you can use mergeResolvers from the @graphql-tools/merge package to merge needed resolvers gracefully(resolvers under Query for example).

Full example:

import { loadFiles } from '@graphql-tools/load-files';

import path from 'path';
import { fileURLToPath, pathToFileURL } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

async function getResolvers() {
    const resolversPath = path.join(
        __dirname, 'resolvers', '**', '*.resolvers.mjs'
    );
    const resolversArray = await loadFiles(resolversPath, {
        useRequire: true,
        requireMethod: async (path) => {
            console.debug('Using resolver at:', path);
            return await import(pathToFileURL(path));
        }
    });
    return mergeResolvers(resolversArray);
}

const resolvers = await getResolvers();
console.debug('GraphQL used resolvers:');
console.debug(resolvers);
like image 195
Barni Avatar answered Oct 26 '25 11:10

Barni



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!