Laravel Mix: Configure Babel for IE11 compatibility (transformations and polyfills)
Asked Answered
M

3

6

In a Laravel 6 application with Laravel-Mix 4, and using the Vue preset, I need to compile my JavaScript code to be compatible for IE11. This means adding any polyfills for missing functions, compiling out arrow functions, and so on. Out of the box, this is not done.

My test code in resources/js/app.js:

//require('./bootstrap');
let test = [1, 2, [3, 4]];
console.log(
    test.flat().map((x) => 2*x)
);

With default config, laravel mix does not appear to compile JavaScript code, but only do some formatting. Comments are preserved in the compiled output.

The result of npm run dev is:

       Asset      Size   Chunks             Chunk Names
/css/app.css   0 bytes  /js/app  [emitted]  /js/app
  /js/app.js  4.95 KiB  /js/app  [emitted]  /js/app

How do I get Laravel-Mix to use Babel to create IE11-compatible source code?

Microprint answered 2/11, 2019 at 11:21 Comment(0)
M
9

Enable Babel compilation with Laravel Mix, and use polyfills for internet explorer

Step 1: Install Corejs to get polyfills

Following the Babeljs docs for babel-preset-env 2, we first need to install core-js (which contains the polyfills):

$ npm install core-js@3 --save

Step 2: Configure .babelrc

create a .babelrc file in the project root:

{
    "presets": [
        [
            "@babel/preset-env",
            {
                "useBuiltIns": "usage",
                "corejs": {
                    "version": 3,
                    "proposals": false
                },
                "targets": {
                    "ie": "11"
                }
            }
        ]
    ]
}

Now run npm run dev and you will find polyfills inserted, arrow functions compiled out etc. - your code may just run on IE11!

Laravel-Mix, Babel, IE: Some gotchas

node_modules are not processed through babel

With the default configuration, only source code in the project itself - not its dependencies - runs through the babel compilation step. This means that any let or similar in the dependencies will trip up legacy browsers 3.

using `mix.babel' risks compiling a file twice

The laravel mix docs suggest using the mix.babel function in the Vanilla JS section 1. What this appears to do:

  • if no .babelrc is present, the specified file is run through babel.
  • if a .babelrc is present, the normal mix compilation step already uses babel. Using mix.babel causes the compilation step to be run twice.

Interestingly, the twice-compiled code does not run on IE. One problem is that it will contain require() calls for polyfills that cannot be handled:

SCRIPT5009: 'require' is undefined
Microprint answered 4/11, 2019 at 6:50 Comment(2)
Your solution is not working for me. I cannot notice any difference! But the I did proceed to using mix.babel which you disagreed with and indeed I got the error SCRIPT5009: 'require' is undefined. This is just a proof that I followed your instructions correctly and without any doubt, your solution does NOT work. I should down-vote your answer so you don't waste others time but I will await 1 or 2 confirmation of what I have noticed.Narvik
Note: even if your solution is correct it never works with Laravel Mix in my experience; even if it's processed it just do otherwise. The best way to make it work as intended is to use this Laravel Mix extension laravel-mix.com/extensions/polyfill instead of the standard babelrcMadaih
I
1

This is how I managed to get our webpage to work on IE11. I'm listing all of the packages related to Babel, though some of them are only needed to make Jest work.

package.json

"devDependencies": {
  "@babel/core": "^7.10.5",
  "@babel/plugin-transform-runtime": "^7.10.5",
  "@babel/preset-env": "^7.10.4",
  "@babel/runtime-corejs3": "^7.10.5",
  "babel-core": "^7.0.0-bridge.0",
  "babel-jest": "^24.9.0",
},

.babelrc

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "entry",
        "bugfixes": true,
        "targets": ">0.25%",
        "corejs": {
          "version": 3,
          "proposals": false
        }
      }
    ]
  ],
  "plugins": [
    ["@babel/plugin-transform-runtime", { "corejs": 3 }]
  ]
}

And finally

app.js

import './bootstrap';
import "core-js";
import Vue from 'vue';
// ...

I must say that I'm confused about the useBuiltIns property because different articles point toward different directions. It looks like if you use "useBuiltIns": "usage" you don't need to import core-js in app.js, anyway I have tried different combinations and this one is working fine.

According to the readme of core-js you need to import it, but I'm not 100% sure. Other resources that pointed me to the right directions were those two articles: https://www.valentinog.com/blog/preset-env/ and https://web.dev/serve-modern-code-to-modern-browsers/.

After this setup we only needed to update some CSS and the app was running fine. The only downside is that the vendor.js file is very heavy. I'd like to create a different bundle for browsers that support modules, but that's a different story...

Incline answered 21/8, 2020 at 15:15 Comment(0)
N
0

Seems some use mix.babel(), but I believe that is better compatible with react. I had similar issue and I use babel-loader, @babel/preset-env and @babel/polyfill. Had to resort to polyfill cos I couldn't get core-js 3 to work following their docs. So if anyone is able to figure out how to make it work with core-js 3. I'd be glad to learn. And only install only what I seem to need for my project

Install:

npm install babel-loader @babel/preset-env @babel/polyfill --save

Webpack.mix.js

module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /(bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }

Finally, import at the begining of main/js or app/js

import '@babel/polyfill';

This has been tested on Laravel 7.x | vue 2.6

Dependencies:

"@babel/polyfill": "^7.10.4",
"@babel/preset-env": "^7.10.4",
"babel-loader": "^8.1.0",

Note: I decided to remove .babelrc from the root app completely, may seem like no effect but incase I need it, I prefer adding it to config.js

Narvik answered 14/7, 2020 at 16:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.