Skip to content
This repository has been archived by the owner on Mar 20, 2023. It is now read-only.

use with ES6 modules triggers assertion in graphql #425

Open
stevvvn opened this issue Apr 7, 2018 · 4 comments
Open

use with ES6 modules triggers assertion in graphql #425

stevvvn opened this issue Apr 7, 2018 · 4 comments

Comments

@stevvvn
Copy link

stevvvn commented Apr 7, 2018

The following does not work, though it seems to me it should (node@9.8.0):

import graphqlHTTP from 'express-graphql'; // @0.6.12
import { buildSchema } from 'graphql'; // @1.13.2
import express from 'express';

const app = express();
app.use('/graphql', graphqlHTTP({
  'schema': buildSchema('type Query { hello: String }'),
  'rootValue': { 'hello': () => 'Hello, world!' }
}));
app.listen(4000);
$ curl -s -X POST -H "Content-type: application/json" http://localhost:4000/graphql --data '{ "query": "{ hello }" }'|jq
{
  "errors": [
    {
      "message": "Cannot use GraphQLSchema \"[object Object]\" from another module or realm.\n\nEnsure that there is only one instance of \"graphql\" in the node_modules\ndirectory. If different versions of \"graphql\" are the dependencies of other\nrelied on modules, use \"resolutions\" to ensure only one version is installed.\n\nhttps://yarnpkg.com/en/docs/selective-version-resolutions\n\nDuplicate \"graphql\" modules cannot be used at the same time since different\nversions may have different capabilities and behavior. The data from one\nversion used in the function from another could produce confusing and\nspurious results."
    }
  ]
}

Creating a wrapper to require buildSchema instead:

req.js

module.exports = require('graphql').buildSchema;

And changing the initial example:

//import { buildSchema } from 'graphql';
import buildSchema from './req';

works as expected:

$ curl -s -X POST -H "Content-type: application/json" http://localhost:4000/graphql --data '{ "query": "{ hello }" }'|jq
{
  "data": {
    "hello": "Hello, world!"
  }
}
@scinos
Copy link

scinos commented Apr 22, 2018

I've been investigating this and I don't have a solution, but I'll share what I found.

The core of the problem is that there are two different ways to get a GraphQLSchema:

  • import { buildSchema } from 'graphql' ends up using node_modules/graphql/type/schema.mjs (an ES6 module).
  • import graphqlHTTP from 'express-graphql' does require('graphql'), which ends up loading node_modules/graphql/type/schema.js (a CJS module).

When passing a schema created with buildSchema (so an instance of GraphQLSchema defined as a ES6 module) to express-graphql, it validates that the schema is instanceOf GraphQLSchema. But because express-graphql uses the CJS version, GraphQLSchema is a different class and therefore the passed schema is not an instance of such class.

I think that the solution would be to have a index.mjs that uses import to load everything related to Graphql, so both modules end up using the same GraphQLSchema, but I'm not 100% sure

@jaydenseric
Copy link

Ideally two things should happen:

  1. Add native ESM support to this package via .mjs, similar to graphql: Use .mjs for module code graphql-js#1244. This would fix this bug when the consumer uses express-graphql directly with --experimental-modules. It will not fix the issue when other packages such as koa-graphql that do not yet support native ESM use express-graphql internally via CJS.
  2. Somehow fix the graphql assertion to detect and allow simultaneous use of the CJS and ESM versions of itself if they are from the same package, or just remove it. This will be pretty desirable for true CJS/ESM cross compatibility as other packages should be able to use either or both versions simultaneously.

jaydenseric added a commit to jaydenseric/graphql-react that referenced this issue May 2, 2018
- Test and example updates:
  - Use fake-tag for GraphQL template literals due to prettier/prettier#4360.
  - Use express instead of Koa packages.
  - Use express-graphql instead of Apollo packages.
- Example updates:
  - Stop using esm due to graphql/express-graphql#425.
  - Enabled GraphiQL and added a link to it on the homepage.
jaydenseric added a commit to jaydenseric/graphql-react that referenced this issue May 2, 2018
- Test and example updates:
  - Use fake-tag for GraphQL template literals due to prettier/prettier#4360.
  - Use express instead of Koa packages.
  - Use express-graphql instead of Apollo packages.
- Test updates:
  - Removed apollo-upload-server as there are no upload tests yet.
- Example updates:
  - Stop using esm due to graphql/express-graphql#425.
  - Enabled GraphiQL and added a link to it on the homepage.
jaydenseric added a commit to jaydenseric/express-graphql that referenced this issue May 2, 2018
Relates to graphql#425.

- Swapped deprecated babel-preset-es2015 for babel-preset-env.
- Added package.json engines field.
- Configured babel-preset-env to target the Node.js version defined in package.json engines field.
- Kept Babel at v6, but moved config into a v7 ready .babelrc.js file for dynamic config via env.
- Tidied the package.json scripts, added an ESM build step that generates .mjs dist files. Follow the lead of graphql/graphql-js#1244, although I do things quite different for my own projects with Babel v7.
- Updated package.json main field for ESM/CJS cross compatibility.
- Added a package.json module field for tree-shaking bundlers.
@martinkadlec0
Copy link

martinkadlec0 commented Dec 11, 2018

Until the smart people figure this out, I managed to work around this issue by using custom module loader:

export function resolve(specifier, parentModuleURL, defaultResolver) {
	const resolvedModule = defaultResolver(specifier, parentModuleURL);
	if (specifier === 'graphql') {
		resolvedModule.url = resolvedModule.url.replace('index.mjs', 'index.js');
		resolvedModule.format = 'cjs';
	}
	return resolvedModule;
}

This will force the cjs version of grahql. (see https://nodejs.org/api/esm.html#esm_loader_hooks on how to use it).

You can actually extend the module loader further to force esm in your project. This will allow you to use js extension instead of mjs until the ESM api is less experimental and the mjs extension is hopefully no longer needed.

RyanWooldridge added a commit to RyanWooldridge/React-graphql that referenced this issue Aug 21, 2019
- Test and example updates:
  - Use fake-tag for GraphQL template literals due to prettier/prettier#4360.
  - Use express instead of Koa packages.
  - Use express-graphql instead of Apollo packages.
- Test updates:
  - Removed apollo-upload-server as there are no upload tests yet.
- Example updates:
  - Stop using esm due to graphql/express-graphql#425.
  - Enabled GraphiQL and added a link to it on the homepage.
@enisdenjo
Copy link
Member

This library has been deprecated and this repo will be archived soon. It has been superseded by graphql-http.

Furthermore, if you seek a fully-featured, well-maintained and performant server - I heavily recommend GraphQL Yoga!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants