gatsby: Gatsby Build Fails when using export { default } syntax

Description

When I have a page that looks like:

// in pages/my-page.js
export { default } from '../../components/hello-world';

gatsby build fails, even if that default export is a component. However, this works, even though it’s functionality identical:

// in pages/my-page.js
import HelloWorld from '../../components/hello-world';

export default HelloWorld;

Steps to reproduce

  1. Add a new page to the boilerplate with just an export { default } from '',
  2. Run yarn gatsby build
  3. You should see a build error

Minimal repro repo: https://github.com/liamfd/gatsby-boilerplate/tree/export-default-minimal-repro/src. Make sure you’re in the export-default-minimal-repro branch. Then run yarn gatsby build. develop seems to work fine.

Expected result

It should build!

Actual result

The build throws “error [/Users/liam/fabric/test-gatsby-site/src/pages/page-4.js] The page component must export a React component for it to be valid”.

Environment

(gatsby info --clipboard is pretty cool!)

  System:
    OS: macOS High Sierra 10.13.6
    CPU: (4) x64 Intel(R) Core(TM) i5-7267U CPU @ 3.10GHz
    Shell: 5.3 - /bin/zsh
  Binaries:
    Node: 8.10.0 - ~/.nvm/versions/node/v8.10.0/bin/node
    Yarn: 1.12.1 - /usr/local/bin/yarn
    npm: 5.6.0 - ~/.nvm/versions/node/v8.10.0/bin/npm
  Languages:
    Python: 2.7.10 - /usr/bin/python
  Browsers:
    Chrome: 72.0.3626.119
    Firefox: 65.0.1
    Safari: 12.0.3
  npmPackages:
    gatsby: ^2.1.23 => 2.1.23 
    gatsby-image: ^2.0.31 => 2.0.31 
    gatsby-plugin-manifest: ^2.0.22 => 2.0.22 
    gatsby-plugin-offline: ^2.0.24 => 2.0.24 
    gatsby-plugin-react-helmet: ^3.0.8 => 3.0.8 
    gatsby-plugin-sharp: ^2.0.25 => 2.0.25 
    gatsby-source-filesystem: ^2.0.23 => 2.0.23 
    gatsby-transformer-sharp: ^2.1.15 => 2.1.15 

Theory/Suggestion

I’m guessing that this check is the problem:

    if (
      !fileContent.includes(`export default`) &&
      !fileContent.includes(`module.exports`) &&
      !fileContent.includes(`exports.default`) &&
      // this check only applies to js and ts, not mdx
      /\.(jsx?|tsx?)/.test(path.extname(fileName))
    ) {
      includesDefaultExport = false
    }

It seems like the es6 default export check should be expanded to support at least the es6 export from syntax options:

export { name1 as default, … };
export { default } from …;

It might also be worth considering support for the export-default-from proposal. It’s stage-1, but I think a fair amount of people use it or its predecessor:

export default from "mod";

I’m happy to try my hand at a PR, assuming this behavior is not intentional. It does seem a little tricky to check this stuff robustly without using an AST.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 15
  • Comments: 21 (6 by maintainers)

Most upvoted comments

Now the validation check is:

    if (
      !fileContent.includes(`export default`) &&
      !fileContent.includes(`module.exports`) &&
      !fileContent.includes(`exports.default`) &&
      !fileContent.includes(`exports["default"]`) &&
      !fileContent.match(/export \{.* as default.*\}/s) &&
      // this check only applies to js and ts, not mdx
      /\.(jsx?|tsx?)/.test(path.extname(fileName))
    ) {

But it still fails to match export { default } from './whatever'.

As a temporary fix, I just use // export default.


Also, before finding out about this issue, I was really confused when it was not working only on production builds (since I was messing with import aliases just before) and that while debugging with commented code, I realized that it was now working!?

Now, I’m wondering why this check even exists at all?

  • It fails to accomplish its goal right now by making valid code fail to build with a cryptic message.
  • It’s really not future proof since it will fail again as new syntax or use-cases are created.

If it’s that important for newcomers to have this message, I feel like a warning should be enough. 🤔

How’s the state of this? Stage 1 export something from 'something-else' form is not the problem here, but the fact that the official export { default } from 'something' form isn’t supported, as @liamfd correctly pointed out.

Not stale

@emileber 100% agree, this is a dumb restriction and very confusing because dev and prod builds don’t work the same way

@JamesDelfini just add // export default (in the meantime) in the file and then it won’t trip the check and gatsby should treat it as valid.

not stale

@samageloff hi!

I provided the example, were you able to check it out? I actually used the onCreateBabelConfig hook in gatsby-node.js -> https://www.gatsbyjs.org/docs/node-apis/#onCreateBabelConfig, specifically used here. This allows us to more cleanly extend the default babel-config, rather than re-creating it in a local .babelrc.js.

@DSchau sure, happy to, might be a bit before I can do so.