Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This course is archived!
While the concepts of this course are still largely applicable, it's built using an older version of Symfony (4) and React (16).

Polyfills: fetch & Promise

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

The fetch() function is built into all modern browsers... which is cool because we didn't need to install any outside libraries to make AJAX requests. Yay! Except... what about older browsers? I'm looking at you IE! Google for "caniuse fetch".

The good news is that fetch() is almost universal... ahem, IE 11. So... you might be ok to do nothing! But, for the rest of us that do have a few users on IE, yea, using fetch() will be a problem. But, a problem we can fix!

When we use new JavaScript syntaxes - like the arrow function - behind the scenes, Babel transpiles - basically rewrites - that code into old, boring syntax that all browsers support. So, that's already handled. But, when there is a totally new feature, like fetch(), Babel doesn't handle that. Instead, you need a polyfill: a fancy word for a library that adds a feature if it's missing.

The fetch Polyfill

Google for "fetch polyfill" to find a library from GitHub. Scroll down to find the library name: whatwg-fetch. Copy that, find your open terminal and:

yarn add whatwg-fetch --dev

To use a JavaScript polyfill, all we need to do is import the file. Internally, it will figure out whether or not the current browser has the feature, like the global fetch() function. If it does not, it will add it.

Super easy! To make sure fetch() is available everywhere, we can import it from our entry file: rep_log_react.js. Then, it will definitely be available in rep_log_api.js. But... I like to get even crazier! Open layout.js. Then look inside webpack.config.js. layout is configured as my "shared" entry... which is a fancy way of saying that layout.js is included on every page and so its code will always run. Inside that file, import 'whatwg-fetch'.

... lines 1 - 7
import 'whatwg-fetch';
... lines 9 - 13

Every part of my app can now safely rely on the fact that the global fetch() function will be available.

Oh, and because I love digging in to see how things work, let's go check out the polyfill code! Open node_modules, search for whatwg, expand its directory and open fetch.js. This is the file we just imported.

Look all the way at the bottom: it's a self-executing function. It passes this into the function, which in a browser environment, is the global window object. Then, on top, that window object is passed as a self. And because all global variables & functions are actually properties on the window object, it's able to ask:

Hey! Does the window variable have the global fetch() function on it?

If it does, it just returns. If it does not, the rest of this code works to define and add it. There it is: self.fetch =. This is a polyfill in action - kinda cool.

The Promise Polyfill

Go back to the fetch polyfill docs. Ah, it says that we also need to use a Promise polyfill for older browsers. We can literally see this inside of the fetch polyfill: it assumes that a Promise class is available.

Let's polyfill it to be safe: click into the library they recommend. Cool: copy the name, move over, and:

yarn add promise-polyfill --dev

When it finishes, head back to the docs. Interesting: this shows two different import options. You can use the second one to import a Promise object, but without adding a new global variable. Because we do want to guarantee that a global Promise variable exists, copy the first one. In layout.js, paste!

... lines 1 - 8
import 'promise-polyfill/src/polyfill';
... lines 10 - 14

To make sure we didn't break anything, go back to the tab that's running encore and restart it:

yarn run encore dev-server

Perfect! We now support older browsers... ahem, IE.

Leave a comment!

4
Login or Register to join the conversation
Daniel B. Avatar
Daniel B. Avatar Daniel B. | posted 3 years ago

Why not axios?

Reply

Hey @danielb

Probably because Ryan wanted to show how things work in a deeper level and to avoid including another dependency into the project, it may overwhelm people :)

Cheers!

Reply
Graymath technology Avatar
Graymath technology Avatar Graymath technology | posted 4 years ago

Shouldn't the promise pollyfill be imported before the fetch pollyfill ?

Reply

Hey Graymath technology

That's a good question. I believe it doesn't matter because no code (app code) is being executed at "import" time, but anyways if you can confirm it, would be great.

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

While the concepts of this course are still largely applicable, it's built using an older version of Symfony (4) and React (16).

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.2.0",
        "ext-iconv": "*",
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "doctrine/doctrine-bundle": "^1.6", // 1.9.1
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.3
        "doctrine/doctrine-fixtures-bundle": "~3.0", // 3.0.2
        "doctrine/doctrine-migrations-bundle": "^1.2", // v1.3.1
        "doctrine/orm": "^2.5", // v2.7.2
        "friendsofsymfony/jsrouting-bundle": "^2.2", // 2.2.0
        "friendsofsymfony/user-bundle": "dev-master#4125505ba6eba82ddf944378a3d636081c06da0c", // dev-master
        "sensio/framework-extra-bundle": "^5.1", // v5.2.0
        "symfony/asset": "^4.0", // v4.1.4
        "symfony/console": "^4.0", // v4.1.4
        "symfony/flex": "^1.0", // v1.17.6
        "symfony/form": "^4.0", // v4.1.4
        "symfony/framework-bundle": "^4.0", // v4.1.4
        "symfony/lts": "^4@dev", // dev-master
        "symfony/monolog-bundle": "^3.1", // v3.3.0
        "symfony/polyfill-apcu": "^1.0", // v1.9.0
        "symfony/serializer-pack": "^1.0", // v1.0.1
        "symfony/swiftmailer-bundle": "^3.1", // v3.2.3
        "symfony/twig-bundle": "^4.0", // v4.1.4
        "symfony/validator": "^4.0", // v4.1.4
        "symfony/yaml": "^4.0", // v4.1.4
        "twig/twig": "2.10.*" // v2.10.0
    },
    "require-dev": {
        "symfony/debug-pack": "^1.0", // v1.0.6
        "symfony/dotenv": "^4.0", // v4.1.4
        "symfony/maker-bundle": "^1.5", // v1.5.0
        "symfony/phpunit-bridge": "^4.0", // v4.1.4
        "symfony/web-server-bundle": "^4.0" // v4.1.4
    }
}

What JavaScript libraries does this tutorial use?

// package.json
{
    "dependencies": {
        "@babel/plugin-proposal-object-rest-spread": "^7.12.1" // 7.12.1
    },
    "devDependencies": {
        "@babel/preset-react": "^7.0.0", // 7.12.5
        "@symfony/webpack-encore": "^0.26.0", // 0.26.0
        "babel-plugin-transform-object-rest-spread": "^6.26.0", // 6.26.0
        "babel-plugin-transform-react-remove-prop-types": "^0.4.13", // 0.4.13
        "bootstrap": "3", // 3.3.7
        "copy-webpack-plugin": "^4.4.1", // 4.5.1
        "core-js": "2", // 1.2.7
        "eslint": "^4.19.1", // 4.19.1
        "eslint-plugin-react": "^7.8.2", // 7.8.2
        "font-awesome": "4", // 4.7.0
        "jquery": "^3.3.1", // 3.3.1
        "promise-polyfill": "^8.0.0", // 8.0.0
        "prop-types": "^15.6.1", // 15.6.1
        "react": "^16.3.2", // 16.4.0
        "react-dom": "^16.3.2", // 16.4.0
        "sass": "^1.29.0", // 1.29.0
        "sass-loader": "^7.0.0", // 7.3.1
        "sweetalert2": "^7.11.0", // 7.22.0
        "uuid": "^3.2.1", // 3.4.0
        "webpack-notifier": "^1.5.1", // 1.6.0
        "whatwg-fetch": "^2.0.4" // 2.0.4
    }
}
userVoice