Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
javascriptlabs opened this issue Jul 25, 2020 · 40 comments
Open

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

javascriptlabs opened this issue Jul 25, 2020 · 40 comments

Comments

@javascriptlabs
Copy link

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
+ graphql@15.3.0

$ 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)
@kettanaito
Copy link
Contributor

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.

@GiancarlosIO
Copy link

GiancarlosIO commented Oct 20, 2020

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.

@KEMBL
Copy link

KEMBL commented Oct 27, 2020

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"

@AdrienLemaire
Copy link

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'

@flyandi
Copy link

flyandi commented Nov 6, 2020

The way I resolved is to add

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

to the [rules] section.

@badfun
Copy link

badfun commented Nov 30, 2020

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

@dtgreene
Copy link

dtgreene commented Dec 6, 2020

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'] },

@badfun
Copy link

badfun commented Dec 8, 2020

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.

@dr-nick-nagel
Copy link

dr-nick-nagel commented Dec 30, 2020

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/,
        ...
      }
    ]
  },
  ...
};

@rnnyrk
Copy link

rnnyrk commented May 9, 2021

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 😓

@rudyhadoux
Copy link

rudyhadoux commented May 13, 2021

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

@DmitryGulin
Copy link

DmitryGulin commented May 13, 2021

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.

@rudyhadoux
Copy link

rudyhadoux commented May 13, 2021

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

@dexster
Copy link

dexster commented May 18, 2021

@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

@rudyhadoux
Copy link

@dexster Good information, thanks.

@tvvignesh
Copy link

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?

@rudyhadoux
Copy link

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

@tvvignesh
Copy link

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",

@rudyhadoux
Copy link

rudyhadoux commented Jun 5, 2021

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

@tvvignesh
Copy link

tvvignesh commented Jun 5, 2021

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

@ItzaMi
Copy link

ItzaMi commented Jan 12, 2022

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.

@LucaProvencal
Copy link

LucaProvencal commented Jan 20, 2022

Same problem here after upgrading to react-scripts@5.0.0 in a non-ejected CRA project

@silberistgold
Copy link

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

@eric-burel
Copy link

eric-burel commented Mar 11, 2022

I am desperate about this issue, I can reproduce with packages built with Tsup (so Esbuild) loaded in Next, I cannot import gql from @apollo/client

See https://stackoverflow.com/questions/70615613/apollo-client-named-export-remove-not-found and https://stackoverflow.com/questions/71370990/apollo-client-using-svelte-named-export-remove-not-found as well

This is blocking the adoption of ESM for us.

I am putting a bounty on this Stack Overflow ticket

@eatsjobs
Copy link

eatsjobs commented Mar 31, 2022

If in the package.json's graphql I put manually "browser": "index" will work. just saying it

@graphql graphql deleted a comment from github-actions bot Apr 4, 2022
@kamranesmaeili
Copy link

Thanks, @flyandi - your solution fixed the problem. For anyone interested in resolving the issue without manually modifying the config file, especially if you don't have the option available before publishing the app, I would recommend using the rewiring option which allows you to add the rules to the config file automatically when executing react-script. See below for more details:
https://www.npmjs.com/package/react-app-rewired

@luiznp3000
Copy link

@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

Thanks, this was driving me nuts and it was THAT simple. Being a beginner sucks.

@stuthib
Copy link

stuthib commented Jul 14, 2022

I upgraded my CRA to 5.0.1 and ran into a bunch of errors. To configure while not ejecting, I used react-app-rewired. I set up the override file as below -

const webpack = require('webpack'); 
module.exports = function override(config) { 
  const fallback = config.resolve.fallback || {}; 
  Object.assign(fallback, { 
    "stream": require.resolve("stream-browserify"), 
    "path": require.resolve("path-browserify")
  }) 
  config.resolve.fallback = fallback; 
  config.resolve.extensions = ['*', '.mjs', '.js', '.json', '.gql', '.graphql']
  config.plugins = (config.plugins || []).concat([ 
    new webpack.ProvidePlugin({ 
      process: 'process/browser', 
      Buffer: ['buffer', 'Buffer'] 
    }) 
  ]) 
  return config; 
}

This fixed the error coming from the node_modules, but in the src file I can't import ts/tsx files. It asks for the extension on each import. I tried adding it to extension ['*', '.mjs', '.js', '.ts', '.tsx', '.json', '.gql', '.graphql'], but that did not fix the issue. Any help is much appreciated, sort of hitting a dead-end here.

Example :

ERROR in ./src/index.tsx 16:0-37
Module not found: Error: Can't resolve './Routes/Routes' in '/project/src'

Routes.tsx is present, but it throws the above error.

@g3tr1ght
Copy link

@stuthib I think config.resolve.extensions must look like this: ['.ts', '.tsx', '.mjs', '.js', '.jsx', 'json', '.gql', '.graphql']. I'm not sure what '*' means in your array. If you wanted to have an array like [...webpack defaults, ...my additional extensions], you would do: ['...', '.ts', '.tsx', '.mjs', '.js', '.jsx', 'json', '.gql', '.graphql']. But normally your overrides come first and defaults come after, so: ['.ts', '.tsx', '.mjs', '.js', '.jsx', 'json', '.gql', '.graphql', '...'] https://webpack.js.org/configuration/resolve/#resolveextensions.

@Neha-2
Copy link

Neha-2 commented Nov 21, 2022

Where is the [rules] section? What do you mean by that? Please elaborate!

@qaisjp
Copy link

qaisjp commented Jan 1, 2023

If using create-react-app, set up CRACO, and set your craco.config.js to:

module.exports = {
  webpack: {
    configure: (config, { env, paths }) => {
      config.module.rules.unshift({
        test: /\.m?jsx?$/,
        resolve: {
          fullySpecified: false,
        },
      });
      return config;
  },
};

@4tal
Copy link

4tal commented Jan 2, 2023

Verify that this is the first rule if you have multiple (It took me some time)

{
    test: /\.m?js/,
    resolve: {
        fullySpecified: false
    }
    
}
//... rest of the rules

@chrisrobbins
Copy link

chrisrobbins commented Jul 6, 2023

I was able to solve this with the following:

      {
        test: /\.m?js$/,
        resolve: {
          fullySpecified: false,
        },
        include: [
          'graphql',
        ].map((name) => new RegExp(`node_modules/${name}`)),
      }

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

No branches or pull requests