graphql-js icon indicating copy to clipboard operation
graphql-js copied to clipboard

ESM named exports are not available with "type": "module"

Open javascriptlabs opened this issue 3 years ago • 40 comments

A package.json top-level field type with a value of module should make modules load as ES modules.

When I used that with graphql, I expected this to work (it didn't):

import { version } from "graphql"; // ❌ 

Importing from index.mjs works fine:

import { version } from "graphql/index.mjs"; // ✅ 

Shouldn't ESM named exports work out of the box when Node's package type is set to module?


Reproduce:

$ node -v
v14.6.0

$ echo '{ "name": "test", "version": "0.0.1", "type": "module" }' > package.json

$ npm i graphql
+ [email protected]

$ echo 'import { version } from "graphql"; console.log(version);' > test.js

$ node test.js
import { version } from "graphql"; console.log(version);
         ^^^^^^^
SyntaxError: The requested module 'graphql' is expected to be of type CommonJS, which does not support named exports. CommonJS modules can be imported by importing the default export.
For example:
import pkg from 'graphql';
const { version } = pkg;
    at ModuleJob._instantiate (internal/modules/esm/module_job.js:98:21)
    at async ModuleJob.run (internal/modules/esm/module_job.js:137:5)
    at async Loader.import (internal/modules/esm/loader.js:162:24)
    at async Object.loadESM (internal/process/esm_loader.js:68:5)

javascriptlabs avatar Jul 25 '20 18:07 javascriptlabs

Hey, @javascriptlabs.

It seems that the error message implies the graphql import hasn't been resolved to index.mjs, but to CommonJS build of the graphql module at node_modules/graphql/index.js:

SyntaxError: The requested module 'graphql' is expected to be of type CommonJS

I believe the issue is that while NodeJS treats your index.js as an ES module, it doesn't resolve the graphql import to its "module": "index.mjs" file. I'm searching NodeJS docs regarding this behavior, but cannot find it any mention that it would respect the module property of the package.json of the imported (third-party) module.

The module build file will work when you bundle your index.js with tools like webpack, as they respect the module field of GraphQL's package.json, and will include index.mjs instead of its CommonJS module.

kettanaito avatar Jul 27 '20 09:07 kettanaito

hi @kettanaito looks like webpack 5 doesn't resolve it anymore. I'm getting this error:

ERROR in ../../../node_modules/graphql/index.mjs 25:0-49
Module not found: Error: Can't resolve './version' in 'node_modules\graphql'
Did you mean 'version.js'?
BREAKING CHANGE: The request './version' failed to resolve only because it was resolved as fully specified
(probably because the origin is a '*.mjs' file or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.

ERROR in ../../../node_modules/graphql/index.mjs 27:0-49
Module not found: Error: Can't resolve './graphql' in 'node_modules\graphql'
Did you mean 'graphql.js'?
BREAKING CHANGE: The request './graphql' failed to resolve only because it was resolved as fully specified
(probably because the origin is a '*.mjs' file or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.

ERROR in ../../../node_modules/graphql/index.mjs 29:0-40:50
Module not found: Error: Can't resolve './type' in 'node_modules\graphql'
Did you mean 'index.js'?
BREAKING CHANGE: The request './type' failed to resolve only because it was resolved as fully specified
(probably because the origin is a '*.mjs' file or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.

ERROR in ../../../node_modules/graphql/index.mjs 42:0-48:205
Module not found: Error: Can't resolve './language' in 'node_modules\graphql'
Did you mean 'index.js'?
BREAKING CHANGE: The request './language' failed to resolve only because it was resolved as fully specified
(probably because the origin is a '*.mjs' file or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.

ERROR in ../../../node_modules/graphql/index.mjs 50:0-122
Module not found: Error: Can't resolve './execution' in 'node_modules\graphql'
Did you mean 'index.js'?
BREAKING CHANGE: The request './execution' failed to resolve only because it was resolved as fully specified
(probably because the origin is a '*.mjs' file or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.

GiancarlosIO avatar Oct 20 '20 06:10 GiancarlosIO

has happened to me as well when I removed yarn.lock and installed all modules from the scratch. returning back yarn.lock solved the problem even though I updated webpack as "webpack": "^5.2.0", "webpack-cli": "^4.1.0"

KEMBL avatar Oct 27 '20 05:10 KEMBL

I need to rebuild my package-lock.json file because I need packages to use @babel/runtime 7.12.5 instead of 7.11.2 to fix another webpack 5 issue.

Is there another temporary solution to get webpack 5 to resolve graphql imports @kettanaito ? I tried adding fullySpecified: false to test: /\.tsx?$/, which fixes the error Error: Can't resolve './graphql', but I'm still getting Error: Can't resolve './version' in '/home/dori/Projects/Work/Project/v3/client/node_modules/graphql'

AdrienLemaire avatar Nov 04 '20 02:11 AdrienLemaire

The way I resolved is to add

           {
                test: /\.m?js/,
                resolve: {
                    fullySpecified: false
                }
            },

to the [rules] section.

flyandi avatar Nov 06 '20 10:11 flyandi

I have the same issue and using the solution from @flyandi did not work for me. Webpack 5.7.0.

badfun avatar Nov 30 '20 17:11 badfun

I have the same issue and using the solution from @flyandi did not work for me. Webpack 5.7.0.

In addition to that rule I think your resolve section also needs to look like this: resolve: { extensions: ['.wasm', '.mjs', '.js', '.jsx', '.json'] },

dtgreene avatar Dec 06 '20 04:12 dtgreene

I have the same issue and using the solution from @flyandi did not work for me. Webpack 5.7.0.

In addition to that rule I think your resolve section also needs to look like this: resolve: { extensions: ['.wasm', '.mjs', '.js', '.jsx', '.json'] },

This didn't work for me either. Only thing that has worked is to add the extensions. That is, in index.mjs, I have to change from './error' to from './error/index.js'

It just bit me again. Quite a drag.

badfun avatar Dec 08 '20 18:12 badfun

I encountered this problem when adding an amplify back-end to my application. The fix described by @flyandi (THANKS!) worked for me but now my build is slowed because webpack must transpile node_modules . Shouldn't this issue be addressed in graphql imports/exports?

changes to my webpack.config.js ...

module.exports = {
  ...
  module: {
    rules: [
      {
        test: /\.m?jsx?$/,
	resolve: {
	  fullySpecified: false
	},
        // ignore transpiling JavaScript from node_modules as they should be ready to go OOTB
        // exclude: /node_modules/,
        ...
      }
    ]
  },
  ...
};

nick-secur avatar Dec 30 '20 17:12 nick-secur

First experience with GraphQL, but it doesn't work with my setup unfortunately. Screenshot 2021-05-09 at 12 07 31

I did try all the recommended options. This is my Webpack setup:

import path from 'path';
import * as webpack from 'webpack';
import * as devServer from 'webpack-dev-server';
import CopyPlugin from 'copy-webpack-plugin';
import webpackMerge from 'webpack-merge';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';

const baseConfig: webpack.Configuration = {
  mode: 'production',
  target: 'browserslist',
  output: {
    filename: 'static/js/[name].[chunkhash].js',
    chunkFilename: 'static/js/[name].[chunkhash].js',
    path: path.resolve('dist'),
    publicPath: '/',
  },
  entry: path.resolve('src'),
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        use: 'babel-loader',
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
      ....
      {
        test: /\.m?js/,
        resolve: {
          fullySpecified: false,
        },
      },
    ],
  },
  ....
  resolve: {
    extensions: ['*', '.mjs', '.js', '.jsx', '.ts', '.tsx'],
    plugins: [
      new TsconfigPathsPlugin(),
    ],
  },
};

export default baseConfig;

export type WebpackConfig = webpack.Configuration & { devServer?: devServer.Configuration };
type WebpackMergeType = (...config: WebpackConfig[]) => WebpackConfig;

export const merge: WebpackMergeType = (...config) => webpackMerge(baseConfig, ...config);

Using Apollo as well as you can see. Version numbers:

"@apollo/client": "^3.3.16",
"graphql": "^15.5.0",
"webpack": "5.36.2",

Anyone any idea? Kinda stuck now on first implementing it 😓

rnnyrk avatar May 09 '21 10:05 rnnyrk

Same MJS problem with Angular and AWS Amplify. @flyandi What is the file we must change please ?

rudyhadoux avatar May 13 '21 18:05 rudyhadoux

I confirm that it is now an issue with Angular 12, which had been upgraded to Webpack 5 and released yesterday. Angular doesn't expose webpack.config.js by default, thus the proposed workaround is not applicable.

DmitryGulin avatar May 13 '21 20:05 DmitryGulin

It is a problem of library. Badly configured for webpack 5.

rudyhadoux avatar May 13 '21 20:05 rudyhadoux

@rudyhadoux I also had this with my ng v12 upgrade and I'm also using amplify. I did a manual install of graphql to get it up to v15.5 and all the errors went away.

npm install --save graphql did the trick for me

So I think the issue lies with either graphql-tag or amplify using old deps, not with graphql itself

dexster avatar May 18 '21 07:05 dexster

@dexster Good information, thanks.

rudyhadoux avatar May 18 '21 08:05 rudyhadoux

I get a similar error but in graphql-ws dependency when trying to run the project as an es module

image

Any workaround apart from using commonjs?

tvvignesh avatar Jun 05 '21 14:06 tvvignesh

Did you try npm i -S graphql ? To have the latest packages.

rudyhadoux avatar Jun 05 '21 14:06 rudyhadoux

I am using yarn but yup, I have the latest versions:

"graphql": "^15.5.0",
 "graphql-helix": "^1.6.1",
"graphql-subscriptions": "^1.2.1",
"graphql-ws": "^4.8.0",

tvvignesh avatar Jun 05 '21 15:06 tvvignesh

Someone told me in an other issue that latest packages work for webpack 5. I don't have time to investigate further.

rudyhadoux avatar Jun 05 '21 15:06 rudyhadoux

Hmm. I don't use webpack/any build tool - just running typescript with node ES modules with the latest version of node.

tvvignesh avatar Jun 05 '21 15:06 tvvignesh

Yes but I think that is the same problem. https://webpack.js.org/blog/2020-10-10-webpack-5-release/#commonjs-tree-shaking

rudyhadoux avatar Jun 05 '21 15:06 rudyhadoux

It is a *.mjs files problem. https://github.com/graphql/graphql-js/issues/2721#issuecomment-723008284

rudyhadoux avatar Jun 05 '21 15:06 rudyhadoux

With main.js config it works like this:

module.exports = {
  core: {
    builder: 'webpack5',
  },
  stories: [],
  addons: ['@storybook/addon-essentials'],
  // Use the property below if you want to apply some webpack config globally
  webpackFinal: async (config, { configType }) => {
    // Make whatever fine-grained changes you need that should apply to all storybook configs
    config.module.rules.push(
      {
        test: /\.m?js/,
        resolve: {
          fullySpecified: false,
        },
      },
    );
    // Return the altered config
    return config;
  },
};

Frotty avatar Aug 19 '21 19:08 Frotty

Hi, I'm using @apollo/client:4.7.0, which again uses graphql. I added the suggested workaround to my webpack config, but it had no effect. Is this because I'm not importing graphql explicitly from my code, but rather from apollo client?

This happened when upgrading webpack from 5.54.0 -> 5.43.0.

Relevant section in webpack.dev.config:

rules: [
  {
    test: /\.m?js/,
    resolve: {
      fullySpecified: false,
    },
  },
  {
    test: /\.[jt]sx?$/,
    use: [
      {
        loader: 'babel-loader',
        options: {
          presets: [
            '@babel/preset-typescript',
            '@babel/preset-react',
            '@babel/preset-env',
          ],
        },
      },
    ],
    exclude: /node_modules/
  },

I'm getting the following error in console

WARNING in ./node_modules/@apollo/client/utilities/globals/graphql.js 4:4-10
export 'isType' (imported as 'isType') was not found in 'graphql' (possible exports: removeTemporaryGlobals)
 @ ./node_modules/@apollo/client/utilities/globals/index.js 7:0-54 8:0-22
 @ ./node_modules/@apollo/client/react/index.js 1:0-39
 @ ./node_modules/@apollo/client/index.js 2:0-33 2:0-33
 @ ./src/index.tsx 9:0-48 12:36-50

I tried to manually change node_modules/@apollo/client/utilities/globals/index.js from import { isType } from 'graphql; to import { isType } from 'graphql/index.mjs';. This made the error go away, but is not a fix of course..

How can I fix this locally in my project? Do I have something wrong in my webpack config?

thomastvedt avatar Sep 27 '21 08:09 thomastvedt

Ahh.. this worked:

rules: [
  {
    test: /\.m?js/,
    resolve: {
      fullySpecified: false,
    },
  },
  {
    test: /\.[jt]sx?$/,
    use: [
      {
        loader: 'babel-loader',
        options: {
          presets: [
            '@babel/preset-typescript',
            '@babel/preset-react',
            '@babel/preset-env',
          ],
        },
      },
    ],
    exclude: /node_modules/,
resolve: {
      fullySpecified: false,
    },
  },
```

thomastvedt avatar Sep 27 '21 08:09 thomastvedt

Ahh.. this worked:

nope.. After a clean install it doesn't work anymore ... rm -rf node_modules + npm install 😢

thomastvedt avatar Sep 28 '21 13:09 thomastvedt

See https://github.com/apollographql/apollo-client/issues/8861. In my case I had the preferRelative flag set to true in my webpack config. This made webpack load graphql from a local module in apollo client, in stead of loading from node_modules.

In addition to :

rules: [
  {
    test: /\.m?js/,
    resolve: {
      fullySpecified: false,
    },
  },

I had to set preferRelative to false in my resolve section:

resolve: {
    extensions: ['.mjs', '.wasm', '.tsx', '.ts', '.js','.jsx','.json', '...'],
    preferRelative: false,
    modules: [path.join(__dirname, 'src'), 'node_modules'],
    plugins: [
      new TsconfigPathsPlugin(),
    ],
  },

thomastvedt avatar Sep 29 '21 08:09 thomastvedt

Upgrading react-scripts to 5.0.0 and webpack to 5.66.0 got me to the same point. Currently getting the following message pretty much everywhere

Did you mean 'graphql.mjs'?
BREAKING CHANGE: The request './graphql' failed to resolve only because it was resolved as fully specified
(probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.

ItzaMi avatar Jan 12 '22 14:01 ItzaMi

Same problem here after upgrading to [email protected] in a non-ejected CRA project

LucaProvencal avatar Jan 20 '22 00:01 LucaProvencal

Anyone got a solution to get graphql/amplify working with CRA5?

silberistgold avatar Feb 09 '22 16:02 silberistgold