gatsby: Gatsby'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"

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 9
  • Comments: 45 (34 by maintainers)

Most upvoted comments

https://github.com/gatsbyjs/gatsby/pull/14111 should fix polyfills for all dependencies so you don’t need gatsby-plugin-compile-es6-packages anymore. I appreciate if you could test this and let me know of any bugs.

@dustinhorton and others that come across this thread:

I have created a gist where I share my experiences when getting Gatsby to work with IE. https://gist.github.com/arnars/2bb1d81fc0955d57fe88a8348695f594

If you have any solutions that are not mentioned already, please feel free to share them.

@jackhair I haven’t deployed yet—I’ll report back when I can.

@dustinhorton and others that come across this thread:

I have created a gist where I share my experiences when getting Gatsby to work with IE. https://gist.github.com/arnars/2bb1d81fc0955d57fe88a8348695f594

If you have any solutions that are not mentioned already, please feel free to share them.

@arnars You’re my hero. I needed to do this https://gist.github.com/arnars/2bb1d81fc0955d57fe88a8348695f594#include-babelpolyfill-in-your-webpackconfig but I thought it wasn’t possible anymore. Thanks a lot.

I originally fixed this issue with https://github.com/gatsbyjs/gatsby/issues/12399#issuecomment-473231797 but the ‘Missing resources’ errors popped back up after pulling in react-spring. Ultimately what worked for me was not needing to setup my own local plugin, but just adding a dependency to gatsby-plugin-compile-es6-packages and listing the modules needing transpiling there:

    {
      resolve: `gatsby-plugin-compile-es6-packages`,
      options: {
        modules: [
          `react-spring`, 
          `react-hot-loader`
        ]
      }
    }

@jackhair that would work, but you’d be including every polyfill provided by core-js in your build. With this approach you’re only including the ones for your supported browsers which can be a big saving.

@Undistraction Does this solution not work just importing core-js as a whole?

For anyone needing a quick fix, I found that the only solution that worked in all cases was to create a local plugin that adds all polyfills manually in its gatsby-browser.js. I then added that plugin as the very first plugin in gatsby-config.js.

This is pretty ugly, but it works in multiple cases where this error occurs and other solutions fail.

Note that it is not enough to put this in your project’s gatsby-browser.js as that is loaded after any of your plugin’s gatsby-browser.js files. There are some very confusing cases where loading polyfills after the import of a library that needs them can be problematic (react and react-dom I’m looking at you).

Also note that your local plugins are not transpiled by Gatsby so using entry as a way of autopopulating your polyfills won’t work (unless you set up your own build step).

Here is mygatsby-browser.js for the default settings, obviously yours will need to be specific to your browser matrix. You can toggle babel-preset-env into debug mode and set it to entry, and it will output all the polyfills it is adding to the console.

import 'core-js/modules/es6.array.copy-within' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.array.fill' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.array.find' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.array.find-index' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.array.from' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es7.array.includes' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.array.iterator' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.array.of' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.array.sort' // { "android":"4.4.3", "chrome":"49", "ios":"8" }
import 'core-js/modules/es6.array.species' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.date.to-json' // { "ios":"8" }
import 'core-js/modules/es6.date.to-primitive' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.function.has-instance' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.function.name' // { "ie":"11" }
import 'core-js/modules/es6.map' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.math.acosh' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.math.asinh' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.math.atanh' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.math.cbrt' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.math.clz32' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.math.cosh' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.math.expm1' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.math.fround' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.math.hypot' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.math.imul' // { "ie":"11" }
import 'core-js/modules/es6.math.log1p' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.math.log10' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.math.log2' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.math.sign' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.math.sinh' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.math.tanh' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.math.trunc' // { "android":"4.4.3", "ie":"11" }
import 'core-js/modules/es6.number.constructor' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.number.epsilon' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.number.is-finite' // { "ie":"11", "ios":"8", "opera":"57" }
import 'core-js/modules/es6.number.is-integer' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.number.is-nan' // { "ie":"11", "ios":"8", "opera":"57" }
import 'core-js/modules/es6.number.is-safe-integer' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.number.max-safe-integer' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.number.min-safe-integer' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.number.parse-float' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.number.parse-int' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.object.assign' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es7.object.define-getter' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es7.object.define-setter' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es7.object.entries' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.object.freeze' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.object.get-own-property-descriptor' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es7.object.get-own-property-descriptors' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.object.get-own-property-names' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.object.get-prototype-of' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es7.object.lookup-getter' // { "android":"4.4.3", "chrome":"49", "edge":"17", "ie":"11", "ios":"8" }
import 'core-js/modules/es7.object.lookup-setter' // { "android":"4.4.3", "chrome":"49", "edge":"17", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.object.prevent-extensions' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.object.is' // { "ie":"11", "ios":"8", "opera":"57" }
import 'core-js/modules/es6.object.is-frozen' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.object.is-sealed' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.object.is-extensible' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.object.keys' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.object.seal' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.object.set-prototype-of' // { "android":"4.4.3", "ios":"8" }
import 'core-js/modules/es7.object.values' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.promise' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es7.promise.finally' // { "android":"4.4.3", "chrome":"49", "edge":"17", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.reflect.apply' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.reflect.construct' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.reflect.define-property' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.reflect.delete-property' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.reflect.get' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.reflect.get-own-property-descriptor' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.reflect.get-prototype-of' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.reflect.has' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.reflect.is-extensible' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.reflect.own-keys' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.reflect.prevent-extensions' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.reflect.set' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.reflect.set-prototype-of' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.regexp.constructor' // { "android":"4.4.3", "chrome":"49", "edge":"17", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.regexp.flags' // { "android":"4.4.3", "edge":"17", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.regexp.match' // { "android":"4.4.3", "chrome":"49", "edge":"17", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.regexp.replace' // { "android":"4.4.3", "chrome":"49", "edge":"17", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.regexp.split' // { "android":"4.4.3", "chrome":"49", "edge":"17", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.regexp.search' // { "android":"4.4.3", "chrome":"49", "edge":"17", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.regexp.to-string' // { "android":"4.4.3", "chrome":"49", "edge":"17", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.set' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.symbol' // { "android":"4.4.3", "chrome":"49", "edge":"17", "ie":"11", "ios":"8" }
import 'core-js/modules/es7.symbol.async-iterator' // { "android":"4.4.3", "chrome":"49", "edge":"17", "ie":"11", "ios":"8", "safari":"11.1" }
import 'core-js/modules/es6.string.anchor' // { "ie":"11", "opera":"57" }
import 'core-js/modules/es6.string.big' // { "ie":"11", "opera":"57" }
import 'core-js/modules/es6.string.blink' // { "ie":"11", "opera":"57" }
import 'core-js/modules/es6.string.bold' // { "ie":"11", "opera":"57" }
import 'core-js/modules/es6.string.code-point-at' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.string.ends-with' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.string.fixed' // { "ie":"11", "opera":"57" }
import 'core-js/modules/es6.string.fontcolor' // { "ie":"11", "opera":"57" }
import 'core-js/modules/es6.string.fontsize' // { "ie":"11", "opera":"57" }
import 'core-js/modules/es6.string.from-code-point' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.string.includes' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.string.italics' // { "ie":"11", "opera":"57" }
import 'core-js/modules/es6.string.iterator' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.string.link' // { "ie":"11", "opera":"57" }
import 'core-js/modules/es7.string.pad-start' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es7.string.pad-end' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.string.raw' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.string.repeat' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.string.small' // { "ie":"11", "opera":"57" }
import 'core-js/modules/es6.string.starts-with' // { "android":"4.4.3", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.string.strike' // { "ie":"11", "opera":"57" }
import 'core-js/modules/es6.string.sub' // { "ie":"11", "opera":"57" }
import 'core-js/modules/es6.string.sup' // { "ie":"11", "opera":"57" }
import 'core-js/modules/es6.typed.array-buffer' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.typed.int8-array' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.typed.uint8-array' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.typed.uint8-clamped-array' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.typed.int16-array' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.typed.uint16-array' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.typed.int32-array' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.typed.uint32-array' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.typed.float32-array' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.typed.float64-array' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.weak-map' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/es6.weak-set' // { "android":"4.4.3", "chrome":"49", "ie":"11", "ios":"8" }
import 'core-js/modules/web.timers' // { "android":"4.4.3", "chrome":"49", "edge":"17", "firefox":"64", "ie":"11", "ios":"8", "opera":"57", "safari":"11.1" }
import 'core-js/modules/web.immediate' // { "android":"4.4.3", "chrome":"49", "edge":"17", "firefox":"64", "ie":"11", "ios":"8", "opera":"57", "safari":"11.1" }
import 'core-js/modules/web.dom.iterable' // { "android":"4.4.3", "chrome":"49", "edge":"17", "firefox":"64", "ie":"11", "ios":"8", "opera":"57", "safari":"11.1" }

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