profile
viewpoint

Ask questionsGatsby's Use Of Polyfills and the 'Missing Resources for x' error

Description

I've just been through the incredibly painful process of getting a Gatsby site working in IE 11 and thought it was worth writing up the problems I faced due to Gatsby's current architecture.

We were receiving an error for every page in IE:

Can't find resource for ...

There was no other error. The pages loaded fine in all the other browsers we tested, so my hunch was that Gatsby was swallowing some kind of IE-specific error.

After a lot of digging I eventually tracked the point of failure to Gatsby's loader, specifically, this line.

.catch(() => {
   failed = true
})

Inspecting the value passed to the catch I could see that the error was related to something that needed to be polyfilled. The problem here being that Gatsby was swallowing this useful error and giving me nothing to help me pinpoint the issue. The resource wasn't missing - it was just erroring when the Loader tried to fetch it. It would make a lot of sense to error here with a more useful message, passing on the specific error that the loader had encountered.

This leads me on to the second issue. Gatsby uses babel-preset-env to handle polyfills, and by default useBuiltIns is set to usage. This sounds great on the surface, but masks what I would consider to be a big problem. If any third-party modules need polyfilling, it seems that Gatsby will not add the Polyfills they need. It will add polyfill imports to project-based code, but will not add imports to non-project-based code. This means if a third-part module was published with useBuiltIns set to entry, it appears that Gatsby will not include the expected babel-polyfill import and replace with the necessary polyfill imports. This means that if a third-party library needs a polyfill that hasn't been supplied due usage within the gatsby project, then this polyfill will not be included. In my case it was a dependency of another dependency.

Combined with the first issue, this was nightmarishly hard to debug.

I'd also suggest adding a section to the browser support docs that makes it clear that Gatsby's declared browser support is only for production builds. I spent a good deal of time trying to debug IE locally before realising that Gatsby doesn't support IE11 when running in development. I eventually found the docs for Gatsby's default babel preset which explained this, but I think these need to be much more prominent. To anyone encountering a similar issue, the only fix I've found is to manually include the entire babel-polyfill using:

// gatsby-browser.js

require('babel-polyfill')

exports.onClientEntry = () => {
  // Without this function body the import will not be picked up.
}

This is far from ideal as this includes a tonne of extra polyfills we don't need, but it at least fixes the problem in the short term.

I guess another option would be to switch Gatsby from using usage to entry so that the import will be replaced by only required polyfills. That appears to be possible by overriding Gatsby's default babel config.

The above is true as of "gatsby": "2.1.22"

gatsbyjs/gatsby

Answer questions Undistraction

This is what I ended up doing:

I opted not to use gatsby-plugin-compile-es6-packages as I don't think this approach scales. It might if the only modules that were causing problems were top level dependencies, but given that it could be a module deep in the dependency tree that needs polyfilling, I feel this is an ineffective solution. I was also concerned with potential side-effects by transpiling third-party libraries.

I chose to go with using 'entry' instead because I can be sure that they correct polyfills will be present for my chosen browser range, regardless of whether those polyfills are needed within my gatsby project. The other option is to include the whole polyfill, but that will add ~100kb to your project.

  1. Create a .babelrc at the root of your gatsby project. This is based on gatsby's babel-preset-gatsby, however I couldn't get gatsby to recognise either babel.config.js or babelrc.js so I had to use a JSON format. Note that I've set debug to true for babel-preset-env which will output a lot of useful information including a list of which transforms are being applied and which polyfills have been used to replace your import '@babel/polyfill' :
{
  "env": {
    "test": {
      "presets": [
        "@babel/preset-env",
        {
          "loose": true,
          "modules": "commonjs",
          "useBuiltIns": "entry",
          "targets": { "browsers": [">0.25%", "not dead"] }
        }
      ]
    }
  },
  "presets": [
    "babel-preset-gatsby",
    [
      "@babel/preset-env",
      {
        "debug": true,
        "loose": true,
        "modules": false,
        "useBuiltIns": "entry",
        "targets": { "browsers": [">0.25%", "not dead"] }
      }
    ]
  ],
  "plugins": [
    [
      "@babel/plugin-proposal-class-properties",
      {
        "loose": true
      }
    ],
    "babel-plugin-macros",
    "@babel/plugin-syntax-dynamic-import",
    [
      "@babel/plugin-transform-runtime",
      {
        "helpers": true,
        "regenerator": true
      }
    ]
  ]
}

  1. Add the following to gatsby-browser.js in the root of your gatsby project. Note that you must use ES6 imports otherwise the polyfill will not be picked up.
import '@babel/polyfill'

// eslint-disable-next-line import/prefer-default-export
export const onClientEntry = () => {
  // Without this function body the import will not be picked up.
}

That should get things working. I'm not going to close this as I believe Gatsby's current approach is not the right one. It makes it very easy to end up with a broken site in some browsers just to make a relatively small size gain through using 'usage' instead of 'entry'. Personally I see this as a poor tradeoff, and most importantly an unexpected issue and one that is hard to debug.

useful!

Related questions

Error: Cannot create as TypeComposer the following value: Date. hot 3
Importing Link from gatsby breaks Storybook hot 2
Loading chunks while a new release is deployed hot 2
Webpack error #98123 when running "gatsby develop" hot 2
gatsby build error #11328 A page component must export a React component for it to be valid. Please make sure this file exports a React component: /Users/tiagosanchez/Documents/Projects/personalBlog/node_modules/gatsby-plugin-offline/app-shell.js hot 2
[gatsby-telemetry] error: src/postinstall.js not found in Linux environments hot 2
IE11: Object not valid as React Child hot 2
CircleCI build Error: spawn ENOMEM hot 2
[Help] I somehow managed to butcher my site's performance hot 2
Build gets stuck at Generating image thumbnails / Update schema on large sites hot 2
[gatsby-source-graphql] Shopify GraphQL Schema Error hot 2
UNHANDLED REJECTION Source and destination must not be the same. hot 2
gatsby-source-shopify unable to complete build hot 2
Autoprefixer "browsers" option is deprecated in v9, produces warnings hot 2
'gatsby' is not recognized as an internal or external command hot 2
Github User Rank List