React-apollo: webpack 4 compatibility issue

Created on 28 Feb 2018  Â·  14Comments  Â·  Source: apollographql/react-apollo

Intended outcome:

I'm migrate a project that uses [email protected] from webpack 3 to webpack 4. Once the configuration updated, the build must succeed.

Actual outcome:

The build fails in webpack 4:

ERROR in ./node_modules/react-apollo/query-hoc.mjs
81:27-46 Can't import the named export 'createElement' from non EcmaScript module (only default export is available)
 @ ./node_modules/react-apollo/query-hoc.mjs
 @ ./node_modules/react-apollo/react-apollo.browser.umd.js
 @ ./src/client.js
 @ multi ./src/client.js

ERROR in ./node_modules/react-apollo/ApolloConsumer.mjs
8:12-28 Can't import the named export 'object' from non EcmaScript module (only default export is available)
 @ ./node_modules/react-apollo/ApolloConsumer.mjs
 @ ./node_modules/react-apollo/react-apollo.browser.umd.js
 @ ./src/client.js
 @ multi ./src/client.js

…

webpack 4 favors .mjs over .js files and applies stricter rules when dealing with Harmony modules. Within a Harmony module, you can only import CJS modules as default. The following imports would raise an error since react is not a Harmony module:

import {Component} from "react";
import * as React from "react";

In react-apollo, react-apollo.browser.umd.js is evaluated by webpack as javascript/auto (webpack 3 default mode). It is a loose mode to preserve compatibility that support both CJS and ESM within the same file. When webpack parses require("./ApolloProvider") it will look at ./ApolloProvider.mjs first. Files ending with .mjs are parsed as javascript/esm, a stricter mode. This mode does not allow to import CJS modules like ESM ones.

While this issue looks like a webpack one, it is not: react-apollo should correctly import non-ESM dependencies, in this case react.

How to reproduce the issue:

Install dependencies:

yarn add apollo-client react [email protected]
yarn add --dev webpack webpack-cli

Create src/index.js:

import {ApolloProvider} from "react-apollo"
console.log(ApolloProvider)

Build:

yarn webpack --mode production

Version

Most helpful comment

Adding this to the webpack config rules section worked for me:

{
  type: 'javascript/auto',
  test: /\.mjs$/,
  use: []
}

All 14 comments

Seems to be the same/similar issue as #1734

@rubenpa Not the same. #1734 is because CRAP uses an old version of uglify-js that does not support ES2015.

Does anyone know of a workaround?

This is a webpack issue. Named exports of CJS modules are still being ironed out in Node so the lack of support by webpack or the lack of enabling folks to support them seems premature.

Update:

It looks like the solution is to not use .mjs just yet (since it's still being ironed out) and instead use .js with module.rules[].type of "javascript/auto".

Update:

If you use ESM with .js then no type config is needed. It with automatically use javascript/auto and also give you named exports of CJS modules in ESM 🙌

Adding this to the webpack config rules section worked for me:

{
  type: 'javascript/auto',
  test: /\.mjs$/,
  use: []
}

@eldh I used a similar approach:

{
  test: /\.mjs$/,
  include: /node_modules/,
  type: "javascript/auto",
},

@eldh @ooflorent Nice! Just remember Webpack's defaults are the way they are for a reason. .mjs is limited because it's not fully baked and it's support story isn't finished yet. If you need javascript/auto you should really be using .js.

Yeah for sure, definitely not meant as a long-term solution!

Is there a specific reason react-apollo uses .mjs? Should that perhaps be changed to .js for now? (Seems like a tiny change to the build script to do so.)

@eldh (I'm not a maintainer) but it looks like it was done as part of a PR to provide esm and cjs variants and they just used .mjs as the distinguisher, likely unaware of the limitations .mjs imposes since they also had require calls in their .mjs which isn't allowed either.

Yeah, I know. :) Maybe @rosskevin @jaydenseric @jbaxleyiii wants to chime in?

FWIW Inferno.js just switched from .mjs to .esm.js to avoid similar complications in their project.

@eldh I have been pushing for a proper adoption of native ESM hard here for a while now as I have had great success using it in production for my GraphQL API servers and would love to be able to use it everywhere else too. Propper .mjs for react-apollo would particularly benefit people who want to SSR in a native ESM server environment.

The best issue to track regarding support for native ESM via .mjs in Apollo is https://github.com/apollographql/apollo-link/issues/537.

@jdalton I've explained basics in the contributor Slack before, during and after every Apollo .mjs attempt yet issues like still https://github.com/apollographql/react-apollo/issues/1589 come up.

react-apollo should only use .mjs if it is properly implemented and tested to work, otherwise you send an incorrect signal to a myriad of tools and stuff breaks and there is zero benefit to using the extension. The gold standard to testing it out is to console.log the named imports in a test.mjs file and run node --experimental-modules test.mjs. Other tools may or may not try to workaround a dodgy implementation.

I'm less invested in bringing native ESM to client side Apollo packages now that graphql-react is on the scene with full support:

screen shot 2018-03-15 at 11 16 04 am

Confirmed reverted/working in 2.1.1 as cjs with webpack 4.

Was this page helpful?
0 / 5 - 0 ratings