How to inline Rollup/Babel polyfills for IE11 - javascript

I've been working on a PHP project for a while and the client has asked for IE11 support at the last possible minute. HTML/CSS problems I can deal with but my javascript was written modern syntax.
So I install node, take my javascript, run it through Rollup & Babel the first time it's needed and cache the result for future requests.
Now the output lacks the arrow functions that were giving me a headache before but I've got a bigger problem: the polyfills are import statements and IE11 doesn't support import statements.
I feel like I need to emphasise that I'm not running a node server - it's a PHP server, I'm just using node on the backend for rollup & babel. If there's something that node does to make this work I'm not familiar with it.
Here's my rollup.config.js:
import commonjs from 'rollup-plugin-commonjs';
import resolve from 'rollup-plugin-node-resolve';
import babel from 'rollup-plugin-babel';
import minify from 'rollup-plugin-babel-minify';
export default {
input: '_dud_input.js', // These are set in the exec() call
output: {
file: '_dud_output.js', // These are set in the exec() call
format: 'iife',
strict : false
},
plugins: [
resolve({
browser: true
}),
commonjs({
sourceMap: false
}),
babel({
exclude: 'node_modules/**' // only transpile our source code
}),
minify({
"comments": false
})
]
};
And here's babel.config.js:
module.exports = {
"presets" : [
[
"#babel/preset-env",
{
"targets": {
"browsers": "> 0.5%, ie >= 11"
},
"modules": false,
"spec": true,
"useBuiltIns": "usage",
"forceAllTransforms": true,
"corejs": {
"version": 3,
"proposals": false
}
}
]
]
}
For giggles, here's the shell script I call to run the process:
#!/bin/bash
set -e
# Expected argument values:
# $1 - Path of the root directory
# $2 - Path of the node binary
# $3 - Path of the rollup binary
# $4 - Source file path
# $5 - Destination file path
if [ $# -ne 5 ]
then
exit 99
fi
ROOT_DIR=$1
NODE_BIN=$2
ROLLUP_BIN=$3
SRC_PATH=$4
DEST_PATH=$5
cd ${ROOT_DIR}
${NODE_BIN} ${ROLLUP_BIN} -c ${ROOT_DIR}/rollup.config.js -i ${SRC_PATH} -o ${DEST_PATH}
And it's linked like this:
<script defer="" type="text/javascript" src="http://example.com/site-asset/flatfile.js"></script>
With these settings, my flatfile.js outputs with the following at the top:
import"core-js/modules/es.symbol";
import"core-js/modules/es.symbol.description";
import"core-js/modules/es.symbol.iterator";
import"core-js/modules/es.array.concat";
import"core-js/modules/es.array.filter";
import"core-js/modules/es.array.find";
import"core-js/modules/es.array.for-each";
// ...etc...
Under this setup IE11's console says there's a Syntax error at the first line of every file with the import statements.
Changing useBuiltIns from usage to entry (which I understand means I'm expected to have an entry file elsewhere that adds the polyfills) and including https://polyfill.io/v3/ doesn't do anything (I get errors on Number.parseFloat() calls).
Out of desperation I even added a "core-js" route to my application, which tries to serve up the appropriate core-js file - but there's no indication that IE11 is even trying to follow the require statements.
Looking around the internet it seems like this isn't a problem for anybody else - IE11 apparently works for everybody else?
Maybe it's because I'm not using a node server, but a PHP/Apache one?
I just want the Babel to include the core-js polyfills in my files, not as require statements that IE11 doesn't know how to parse.

I had to disable the babel-minify plugin, but aside from that, copying your configuration seems to work just fine and I get a single bundled JavaScript file with no import statements.
The files are reproduced below, but the full test repo is available at https://github.com/akx/so58712204 – yarn; yarn build and look in dist/...
babel.config.js
module.exports = {
presets: [
[
"#babel/preset-env",
{
targets: {
browsers: "> 0.5%, ie >= 11"
},
modules: false,
spec: true,
useBuiltIns: "usage",
forceAllTransforms: true,
corejs: {
version: 3,
proposals: false
}
}
]
]
};
package.json
{
"scripts": {
"build": "rollup -c ./rollup.config.js -i ./src/entry.js -o ./dist/output.js"
},
"dependencies": {
"#babel/core": "^7.7.0",
"#babel/preset-env": "^7.7.0",
"core-js": "^3.3.6",
"rollup": "^1.26.3",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-babel-minify": "^9.1.0",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0"
}
}
rollup.config.js
import commonjs from "rollup-plugin-commonjs";
import resolve from "rollup-plugin-node-resolve";
import babel from "rollup-plugin-babel";
export default {
input: "_dud_input.js", // These are set in the exec() call
output: {
file: "_dud_output.js", // These are set in the exec() call
format: "iife",
strict: false
},
plugins: [
resolve({
browser: true
}),
commonjs({
sourceMap: false
}),
babel({
exclude: "node_modules/**" // only transpile our source code
})
]
};
src/entry.js
import { magicNumber } from "./magic";
console.log(new Set([Number.parseFloat(magicNumber)]));
src/magic.js
const magicNumber = "8.82";
export { magicNumber };

Related

ReferenceError: regeneratorRuntime is not defined working on vanilla js [duplicate]

I'm trying to use async/await from scratch on Babel 6, but I'm getting regeneratorRuntime is not defined.
.babelrc file
{
"presets": [ "es2015", "stage-0" ]
}
package.json file
"devDependencies": {
"babel-core": "^6.0.20",
"babel-preset-es2015": "^6.0.15",
"babel-preset-stage-0": "^6.0.15"
}
.js file
"use strict";
async function foo() {
await bar();
}
function bar() { }
exports.default = foo;
Using it normally without the async/await works just fine. Any ideas what I'm doing wrong?
babel-polyfill (deprecated as of Babel 7.4) is required. You must also install it in order to get async/await working.
npm i -D babel-core babel-polyfill babel-preset-es2015 babel-preset-stage-0 babel-loader
package.json
"devDependencies": {
"babel-core": "^6.0.20",
"babel-polyfill": "^6.0.16",
"babel-preset-es2015": "^6.0.15",
"babel-preset-stage-0": "^6.0.15"
}
.babelrc
{
"presets": [ "es2015", "stage-0" ]
}
.js with async/await (sample code)
"use strict";
export default async function foo() {
var s = await bar();
console.log(s);
}
function bar() {
return "bar";
}
In the startup file
require("babel-core/register");
require("babel-polyfill");
If you are using webpack you need to put it as the first value of your entry array in your webpack configuration file (usually webpack.config.js), as per #Cemen comment:
module.exports = {
entry: ['babel-polyfill', './test.js'],
output: {
filename: 'bundle.js'
},
module: {
loaders: [
{ test: /\.jsx?$/, loader: 'babel', }
]
}
};
If you want to run tests with babel then use:
mocha --compilers js:babel-core/register --require babel-polyfill
Note
If you're using babel 7, the package has been renamed to #babel/plugin-transform-runtime.
Besides polyfill, I use babel-plugin-transform-runtime. The plugin is described as:
Externalize references to helpers and builtins, automatically polyfilling your code without polluting globals. What does this actually mean though? Basically, you can use built-ins such as Promise, Set, Symbol etc as well use all the Babel features that require a polyfill seamlessly, without global pollution, making it extremely suitable for libraries.
It also includes support for async/await along with other built-ins of ES 6.
$ npm install --save-dev babel-plugin-transform-runtime
In .babelrc, add the runtime plugin
{
"plugins": [
["transform-runtime", {
"regenerator": true
}]
]
}
Babel 7 Users
I had some trouble getting around this since most information was for prior babel versions. For Babel 7, install these two dependencies:
npm install --save #babel/runtime
npm install --save-dev #babel/plugin-transform-runtime
And, in .babelrc, add:
{
"presets": ["#babel/preset-env"],
"plugins": [
["#babel/transform-runtime"]
]
}
Update
It works if you set the target to Chrome. But it might not work for other targets, please refer to: https://github.com/babel/babel-preset-env/issues/112
So this answer is NOT quite proper for the original question. I will keep it here as a reference to babel-preset-env.
A simple solution is to add import 'babel-polyfill' at the beginning of your code.
If you use webpack, a quick solution is to add babel-polyfill as shown below:
entry: {
index: ['babel-polyfill', './index.js']
}
I believe I've found the latest best practice.
Check this project: https://github.com/babel/babel-preset-env
yarn add --dev babel-preset-env
Use the following as your babel configuration:
{
"presets": [
["env", {
"targets": {
"browsers": ["last 2 Chrome versions"]
}
}]
]
}
Then your app should be good to go in the last 2 versions of Chrome browser.
You can also set Node as the targets or fine-tune the browsers list according to https://github.com/ai/browserslist
Tell me what, don't tell me how.
I really like babel-preset-env's philosophy: tell me which environment you want to support, do NOT tell me how to support them. It's the beauty of declarative programming.
I've tested async await and they DO work. I don't know how they work and I really don't want to know. I want to spend my time on my own code and my business logic instead. Thanks to babel-preset-env, it liberates me from the Babel configuration hell.
Update: The Babel 7 post also has a more in-depth answer.
Babel 7.4.0 or later (core-js 2 / 3)
As of Babel 7.4.0, #babel/polyfill is deprecated.
In general, there are two ways to install polyfills/regenerator: via global namespace (Option 1) or as ponyfill (Option 2, without global pollution).
Option 1: #babel/preset-env
presets: [
["#babel/preset-env", {
"useBuiltIns": "usage",
"corejs": 3, // or 2,
"targets": {
"firefox": "64", // or whatever target to choose .
},
}]
]
will automatically use regenerator-runtime and core-js according to your target. No need to import anything manually. Don't forget to install runtime dependencies:
npm i --save regenerator-runtime core-js
Alternatively, set useBuiltIns: "entry" and import it manually:
import "regenerator-runtime/runtime";
import "core-js/stable"; // if polyfills are also needed
Option 2: #babel/transform-runtime with #babel/runtime
This alternative has no global scope pollution and is suitable for libraries.
{
"plugins": [
[
"#babel/plugin-transform-runtime",
{
"regenerator": true,
"corejs": 3 // or 2; if polyfills needed
...
}
]
]
}
Install it:
npm i -D #babel/plugin-transform-runtime
npm i #babel/runtime
If corejs polyfill is used, you replace #babel/runtime with #babel/runtime-corejs2 (for "corejs": 2) or #babel/runtime-corejs3 (for "corejs": 3).
Alternatively, if you don't need all the modules babel-polyfill provides, you can just specify babel-regenerator-runtime in your webpack config:
module.exports = {
entry: ['babel-regenerator-runtime', './test.js'],
// ...
};
When using webpack-dev-server with HMR, doing this reduced the number of files it has to compile on every build by quite a lot. This module is installed as part of babel-polyfill so if you already have that you're fine, otherwise you can install it separately with npm i -D babel-regenerator-runtime.
My simple solution:
npm install --save-dev babel-plugin-transform-runtime
npm install --save-dev babel-plugin-transform-async-to-generator
.babelrc
{
"presets": [
["latest", {
"es2015": {
"loose": true
}
}],
"react",
"stage-0"
],
"plugins": [
"transform-runtime",
"transform-async-to-generator"
]
}
This error is caused when async/await functions are used without the proper Babel plugins. As of March 2020, the following should be all you need to do. (#babel/polyfill and a lot of the accepted solutions have been deprecated in Babel. Read more in the Babel docs.)
In the command line, type:
npm install --save-dev #babel/plugin-transform-runtime
In your babel.config.js file, add this plugin #babel/plugin-transform-runtime. Note: The below example includes the other presets and plugins I have for a small React/Node/Express project I worked on recently:
module.exports = {
presets: ['#babel/preset-react', '#babel/preset-env'],
plugins: ['#babel/plugin-proposal-class-properties',
'#babel/plugin-transform-runtime'],
};
babel-regenerator-runtime is now deprecated, instead one should use regenerator-runtime.
To use the runtime generator with webpack and babel v7:
install regenerator-runtime:
npm i -D regenerator-runtime
And then add within webpack configuration :
entry: [
'regenerator-runtime/runtime',
YOUR_APP_ENTRY
]
Update your .babelrc file according to the following examples, it will work.
If you are using #babel/preset-env package
{
"presets": [
[
"#babel/preset-env", {
"targets": {
"node": "current"
}
}
]
]
}
or if you are using babel-preset-env package
{
"presets": [
[
"env", {
"targets": {
"node": "current"
}
}
]
]
}
As of Oct 2019 this worked for me:
Add this to the preset.
"presets": [
"#babel/preset-env"
]
Then install regenerator-runtime using npm.
npm i regenerator-runtime
And then in your main file use: (this import is used only once)
import "regenerator-runtime/runtime";
This is will enable you to use async awaits in your file and remove the regenerator error
Be careful of hoisted functions
I had both my 'polyfill import' and my 'async function' in the same file, however I was using the function syntax that hoists it above the polyfill which would give me the ReferenceError: regeneratorRuntime is not defined error.
Change this code
import "babel-polyfill"
async function myFunc(){ }
to this
import "babel-polyfill"
var myFunc = async function(){}
to prevent it being hoisted above the polyfill import.
If using babel-preset-stage-2 then just have to start the script with --require babel-polyfill.
In my case this error was thrown by Mocha tests.
Following fixed the issue
mocha \"server/tests/**/*.test.js\" --compilers js:babel-register --require babel-polyfill
I had this problem in Chrome. Similar to RienNeVaPlu͢s’s answer, this solved it for me:
npm install --save-dev regenerator-runtime
Then in my code:
import 'regenerator-runtime/runtime';
Happy to avoid the extra 200 kB from babel-polyfill.
I used tip from https://github.com/babel/babel/issues/9849#issuecomment-592668815 and added targets: { esmodules: true,} to my babel.config.js.
module.exports = {
presets: [
[
'#babel/preset-env',
{
targets: {
esmodules: true,
},
},
],
],
}
You're getting an error because async/await use generators, which are an ES2016 feature, not ES2015. One way to fix this is to install the babel preset for ES2016 (npm install --save babel-preset-es2016) and compile to ES2016 instead of ES2015:
"presets": [
"es2016",
// etc...
]
As the other answers mention, you can also use polyfills (though make sure you load the polyfill first before any other code runs). Alternatively, if you don't want to include all of the polyfill dependencies, you can use the babel-regenerator-runtime or the babel-plugin-transform-runtime.
I started getting this error after converting my project into a typescript project. From what I understand, the problem stems from async/await not being recognized.
For me the error was fixed by adding two things to my setup:
As mentioned above many times, I needed to add babel-polyfill into my webpack entry array:
...
entry: ['babel-polyfill', './index.js'],
...
I needed to update my .babelrc to allow the complilation of async/await into generators:
{
"presets": ["es2015"],
"plugins": ["transform-async-to-generator"]
}
DevDependencies:
I had to install a few things into my devDependencies in my package.json file as well. Namely, I was missing the babel-plugin-transform-async-to-generator, babel-polyfill and the babel-preset-es2015:
"devDependencies": {
"babel-loader": "^6.2.2",
"babel-plugin-transform-async-to-generator": "^6.5.0",
"babel-polyfill": "^6.5.0",
"babel-preset-es2015": "^6.5.0",
"webpack": "^1.12.13"
}
Full Code Gist:
I got the code from a really helpful and concise GitHub gist you can find here.
I fixed this error by installing babel-polyfill
npm install babel-polyfill --save
then I imported it in my app entry point
import http from 'http';
import config from 'dotenv';
import 'babel-polyfill';
import { register } from 'babel-core';
import app from '../app';
for testing I included --require babel-polyfill in my test script
"test": "export NODE_ENV=test|| SET NODE_ENV=test&& mocha --compilers
js:babel-core/register --require babel-polyfill server/test/**.js --exit"
There are so many answers up there, I will post my answer for my reference.
I use webpack and react, here is my solution without the .babelrc file
I am working on this in Aug 2020
Install react and babel
npm i #babel/core babel-loader #babel/preset-env #babel/preset-react react react-dom #babel/plugin-transform-runtime --save-dev
Then in my webpack.config.js
// other stuff
module.exports = {
// other stuff
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env',"#babel/preset-react"],
plugins: ['#babel/plugin-proposal-class-properties', '#babel/plugin-transform-runtime'],
//npm install --save-dev #babel/plugin-transform-runtime
}
}
},
],
},
};
I just don't know why I dont need to install the async package for the moment
New Answer Why you follow my answer ?
Ans: Because I am going to give you a answer with latest Update version npm project .
04/14/2017
"name": "es6",
"version": "1.0.0",
"babel-core": "^6.24.1",
"babel-loader": "^6.4.1",
"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.24.1",
"webpack": "^2.3.3",
"webpack-dev-server": "^2.4.2"
If your Use this version or more UP version of Npm and all other ...
SO just need to change :
webpack.config.js
module.exports = {
entry: ["babel-polyfill", "./app/js"]
};
After change webpack.config.js files Just add this line to top of your code .
import "babel-polyfill";
Now check everything is ok. Reference LINK
Also Thanks #BrunoLM for his nice Answer.
The targeted browsers I need to support already support async/await, but when writing mocha tests, without the proper setting I still got this error.
Most of the articles I googled are outdated, including the accepted answer and high voted answers here, i.e. you don't need polyfill, babel-regenerator-runtime, babel-plugin-transform-runtime. etc. if your target browser(s) already supports async/await (of course if not you need polyfill)
I don't want to use webpack either.
Tyler Long's answer is actually on the right track since he suggested babel-preset-env (but I omitted it first as he mentioned polifill at the beginning). I still got the ReferenceError: regeneratorRuntime is not defined at the first then I realized it was because I didn't set the target. After setting the target for node I fix the regeneratorRuntime error:
"scripts": {
//"test": "mocha --compilers js:babel-core/register"
//https://github.com/mochajs/mocha/wiki/compilers-deprecation
"test": "mocha --require babel-core/register"
},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-preset-env": "^1.7.0",
"mocha": "^5.2.0"
},
//better to set it .bablerc, I list it here for brevity and it works too.
"babel": {
"presets": [
["env",{
"targets": {
"node": "current"
"chrome": 66,
"firefox": 60,
},
"debug":true
}]
]
}
My working babel 7 boilerplate for react with regenerator runtime:
.babelrc
{
"presets": [
[
"#babel/preset-env",
{
"targets": {
"node": true,
},
},
],
"#babel/preset-react",
],
"plugins": [
"#babel/plugin-syntax-class-properties",
"#babel/plugin-proposal-class-properties"
]
}
package.json
...
"devDependencies": {
"#babel/core": "^7.0.0-0",
"#babel/plugin-proposal-class-properties": "^7.4.4",
"#babel/plugin-syntax-class-properties": "^7.2.0",
"#babel/polyfill": "^7.4.4",
"#babel/preset-env": "^7.4.5",
"#babel/preset-react": "^7.0.0",
"babel-eslint": "^10.0.1",
...
main.js
import "#babel/polyfill";
....
Easiest way to fix this 'regeneratorRuntime not defined issue' in your console:
You don't have to install any unnecessary plugins. Just add:
<script src="https://unpkg.com/regenerator-runtime#0.13.1/runtime.js"></script>
inside of the body in your index.html.
Now regeneratorRuntime should be defined once you run babel and now your async/await functions should be compiled successfully into ES2015
Just install regenerator-runtime
with below command
npm i regenerator-runtime
add below line in startup file before you require server file
require("regenerator-runtime/runtime");
So far this has been working for me
I get this error using gulp with rollup when I tried to use ES6 generators:
gulp.task('scripts', () => {
return rollup({
entry: './app/scripts/main.js',
format: "iife",
sourceMap: true,
plugins: [babel({
exclude: 'node_modules/**',
"presets": [
[
"es2015-rollup"
]
],
"plugins": [
"external-helpers"
]
}),
includePaths({
include: {},
paths: ['./app/scripts'],
external: [],
extensions: ['.js']
})]
})
.pipe(source('app.js'))
.pipe(buffer())
.pipe(sourcemaps.init({
loadMaps: true
}))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('.tmp/scripts'))
.pipe(reload({ stream: true }));
});
I may case the solution was to include babel-polyfill as bower component:
bower install babel-polyfill --save
and add it as dependency in index.html:
<script src="/bower_components/babel-polyfill/browser-polyfill.js"></script>
1 - Install babel-plugin-transform-async-to-module-method,
babel-polyfil, bluebird , babel-preset-es2015, babel-core :
npm install babel-plugin-transform-async-to-module-method babel-polyfill bluebird babel-preset-es2015 babel-core
2 - Add in your js babel polyfill:
import 'babel-polyfill';
3 - Add plugin in your .babelrc:
{
"presets": ["es2015"],
"plugins": [
["transform-async-to-module-method", {
"module": "bluebird",
"method": "coroutine"
}]
]
}
Source : http://babeljs.io/docs/plugins/transform-async-to-module-method/
For people looking to use the babel-polyfill version 7^ do this with webpack ver3^.
Npm install the module npm i -D #babel/polyfill
Then in your webpack file in your entry point do this
entry: ['#babel/polyfill', path.resolve(APP_DIR, 'App.js')],
To babel7 users and ParcelJS >= 1.10.0 users
npm i #babel/runtime-corejs2
npm i --save-dev #babel/plugin-transform-runtime #babel/core
.babelrc
{
"plugins": [
["#babel/plugin-transform-runtime", {
"corejs": 2
}]
]
}
taken from https://github.com/parcel-bundler/parcel/issues/1762
I had a setup
with webpack using presets: ['es2015', 'stage-0']
and mocha that was running tests compiled by webpack.
To make my async/await in tests work all I had to do is use mocha with the --require babel-polyfill option:
mocha --require babel-polyfill
I am using a React and Django project and got it to work by using regenerator-runtime. You should do this because #babel/polyfill will increase your app's size more and is also deprecated. I also followed this tutorial's episode 1 & 2 to create my project's structure.
*package.json*
...
"devDependencies": {
"regenerator-runtime": "^0.13.3",
...
}
.babelrc
{
"presets": ["#babel/preset-env", "#babel/preset-react"],
"plugins": ["transform-class-properties"]
}
index.js
...
import regeneratorRuntime from "regenerator-runtime";
import "regenerator-runtime/runtime";
ReactDOM.render(<App />, document.getElementById('app'));
...

Bundle JS with rollup and Babel for use in IE11

I try to bundle two JavaScript modules, so that the resulting code works in IE11. For this I have setup a yarn/npm project which uses rollup.js for bundling and Babel for transpiling. Everything works fine until I add the (non-dev) dependency core-js.
Here the details:
1 Setup before adding core-js
JS files
src/main.js
src/utils.js
Config files
package.json
{
"name": "rollup_for_ie",
"devDependencies": {
"#babel/core": "^7.11.1",
"#babel/preset-env": "^7.11.0",
"#rollup/plugin-babel": "^5.2.0",
"#rollup/plugin-node-resolve": "^9.0.0",
"rollup": "^2.24.0"
},
}
rollup.config.js
import resolve from '#rollup/plugin-node-resolve';
import babel from '#rollup/plugin-babel';
export default {
input: 'src/main.js',
output: {
file: 'dist/main.js',
format: 'iife'
},
plugins: [
resolve({
browser: true
}),
babel({
exclude: "node_modules/**", // only transpile our source code
babelHelpers: 'bundled'
})
]
};
babel.config.js
module.exports = {
presets: [
[
"#babel/preset-env",
{
targets: {
browsers: "> 0.5%, ie >= 11"
},
modules: false,
spec: true,
useBuiltIns: "usage",
forceAllTransforms: true,
corejs: 3
}
]
],
};
When I run rollup -c I get warnings about unresolved dependencies, but a bundled file dist/main.js with the (used) stuff from the src directory is generated. The resulting file works even in modern browsers like Chrome. So far so good.
Problems after adding core-js
However the bundled file is not yet IE11 ready: In IE I get errors like Object doesn't support property or method 'getOwnPropertySymbols'. So the polyfills from core-js need to be added.
For this I install core-js as a prod dependency. Now rollup -c doesn't give me warnings - but the resulting dist/main.js begins like
(function (exports) {
'use strict';
var $ = require('../internals/export');
.
.
.
which as a script can not neither Chrome nor IE execute! It looks like that somehow the presence of the core-js library throws the rollup bundler off.
How can I fix my setup so that the resulting dist/main.js works as non-module script in Chrome and IE11?
I think as you enabled the option useBuiltIns: "usage" which means it will append code from corejs into your module files which is written with cjs style. So you have to add this plugin #rollup/plugin-commonjs to convert back to esm, then it will work:
import commonjs from '#rollup/plugin-commonjs';
export default {
// ...
plugins: [
// ...
commonjs(),
]
};

Material-UI have different style result in production mode?

I am writing a React app that uses server-side rendering. I am following the instruction here to set up a file.
Here is my .babelrc configuration file
{
"presets": [
[
"#babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": { "version": 3, "proposals": true },
"targets": {
"browsers": "> 1%, not ie 11, not op_mini all",
"node": 13
}
}
],
"#babel/preset-react"
],
"plugins": [
"#babel/plugin-proposal-class-properties",
"#babel/plugin-transform-runtime",
[
"import",
{
"libraryName": "#material-ui/icons",
"libraryDirectory": "utils", // default: lib
"camel2DashComponentName": false // default: true
},
"#material-ui/icons"
]
]
}
And this is webpack.config.js file
const path = require("path");
const nodeExternals = require("webpack-node-externals");
const commonConfig = {
devtool: "source-map",
module: {
rules: [{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }]
},
resolve: {
alias: {
"#material-ui/core": "#material-ui/core/es"
}
}
};
module.exports = [
{
...commonConfig,
entry: "./src/client",
output: {
path: path.resolve(__dirname, "public")
}
},
{
...commonConfig,
target: "node",
entry: "./src/server",
output: {
path: path.resolve(__dirname, "server")
},
externals: [nodeExternals()]
}
];
(Here is the full code in CodeSandBox and here is in Github if you want to try out)
The problem appear is when I bundle up the file, in development mode, everything work just fine. But when I try production mode, the CSS part starts to behave weirdly. When the file is first loaded from localhost, it is styled correctly (this happens in a very short time), then the style goes wrong as some styling is missing.
When I try to investigate, I find that all the style that is missing is the part I wrote with makeStyles(). All the built-in styles work just fine.
I tried to remove all the resolve property in webpack.config.js following this post, but it doesn't work. No matter what I try to change that property, nothing happens.
So now the only way I found that can make the app work in production build is to remove the code that removes the styling file (you can find that part at the end of client.js file), but I'm not sure what is the result of doing so.
So my questions are:
What can you suggest the fix for the app?
Why there is such a difference between two modes, development and production? I get that the production mode will include some minification, tree shaking, etc., and the development has most of that except for minification. So why there is a difference?
Edit: I found two possible and workable fixes for this bug: one is to stop removing those CSS files (code that I wrote in client.js file); the other one is to remove the nodeExternal() plugin in webpack.config.js and bundle everything for the server file. What do you think ?
I had a similar issue, although without server-side rendering. It was caused by a different order of stylesheets in dev and prod environments, causing unwanted overwrites. In dev env all stylesheets created by makeStyles() were injected after ALL MUI stylesheets, but in production they were mixed.
Solution:
Add an option: { index: 1 } to all makeStyles() invocations, in order to place those sheets after the MUI sheets which have an index of 0 (by default). This optional argument is passed directly to underlying JSS's jss.createStyleSheet() and dictates the injection order:
const useStyles = makeStyles(
(...), // styles
{ index: 1 }, // optional argument for JSS, to set position after MUI stylesheets
)
(after: https://stackoverflow.com/a/62646041/624597)

Get rid of "regeneratorRuntime is not defined" without importing the polyfill

I wrote a library of elements, and want to make sure designers can just add the right source file to their HTML pages to start using it.
I am creating a bundle using rollup (to roll it up to one file) and babel (to make sure any browser can use it).
My rollup.conf is pretty simple:
import resolve from 'rollup-plugin-node-resolve'
import babel from 'rollup-plugin-babel'
import minify from 'rollup-plugin-babel-minify'
module.exports = [
// IIFE
{
input: './tpe.js',
output: {
file: 'distr/tpe.js', // IIFE ONE FILE
format: 'iife'
},
plugins: [resolve({}), babel({})]
},
{
input: './themes/material/material.js',
output: {
file: 'distr/material.js', // IIFE ONE FILE
format: 'iife'
},
plugins: [resolve({}), minify({})]
}
]
Note that ./tpe.js contains a long list of imports:
import './ee-autocomplete-input-spans.js'
import './ee-autocomplete-item-country.js'
import './ee-autocomplete-item-email.js'
import './ee-autocomplete-item-li.js'
import './ee-autocomplete.js'
import './ee-drawer.js'
import './ee-fab.js'
import './ee-header.js'
import './ee-nav-bar.js'
import './ee-network.js'
import './ee-snack-bar.js'
import './ee-tabs.js'
...
My babel.conf.js is even simpler:
module.exports = function (api) {
api.cache(true)
const presets = [
[
'#babel/env', {
modules: false,
exclude: [],
targets: {
ie: "9"
}
}
]
]
const plugins = []
return {
presets,
plugins
}
This is all fine, except that I have to ask my users to do this:
<script src="https://unpkg.com/#babel/polyfill/dist/polyfill.min.js"></script>
<script src="./distr/material.js"></script>
<script src="./distr/tpe.js"></script>
<nn-input-text id="input" name="aName"></nn-input-text>
Without that polyfill.min.js, I get the dreaded regeneratorRuntime is not defined.
I spent hours, and hours, and hours trying to make sure that I don't need to ask users to have that polyfill.min.js.
To "fix" the problem, I added this to my ./tpe.js:
import 'regenerator-runtime/runtime'
import './ee-autocomplete-input-spans.js'
import './ee-autocomplete-item-country.js'
import './ee-autocomplete-item-email.js'
import './ee-autocomplete-item-li.js'
This actually allows me to have just this:
<script src="./distr/material.js"></script>
<script src="./distr/tpe.js"></script>
<nn-input-text id="input" name="aName"></nn-input-text>
QUESTIONS:
Babel is compiling things in node_modules, which in my case is exactly lit-html and lit-element (both ES6 source). I had problems at the beginning where lit-element (in node_modules) didn't compile. However, the problem disappeared and I don't know how/why.
Is regenerator-runtime/runtime the ONLY thing I will ever need to polyfill? I am targeting IE9 after all...
Is there a better way to add regenerator-runtime/runtime without having it in the includes in tpe.js?
I read about "corejs" being important is it provides more polyfills. However, adding this
useBuiltIns: "usage",
corejs: 3
Results in a lot of warnings. And then if I add an exclude in rollup.conf.js like this:
plugins: [resolve({}), babel({exclude: [/\/core-js\//]}), minify({})]
Things compile, but the result doesn't work (Uncaught SyntaxError: Cannot use import statement outside a module).
If I instead do:
useBuiltIns: "entry",
corejs: 3
I don't need the "exclude", but it doesn't seem to do anything.
Do I actually need the corejs polyfills?
I saw the Github issue you opened and linked to this post.
I have also been trying to diagnose this setup and the problems I've run into trying to configure it.
Checkout this recommended config on the rollup-plugin-babel repo.
I was running into the same issue with regeneratorRuntime is not defined and couldn't figure out why the polyfills weren't being loaded as I hoped/expected.
The key seems to be that 3 plugins are required for this use-case.
// We need all 3 of these to end up with the 'usage'-based babel polyfills
import babel from "rollup-plugin-babel";
import commonjs from "rollup-plugin-commonjs";
import resolve from "rollup-plugin-node-resolve";
export default [
{
input: "src/index.js",
output: {
file: "dist/index.js",
format: "iife"
},
plugins: [
resolve(),
babel({
exclude: "node_modules/**",
presets: [
[
"#babel/preset-env",
{
corejs: 3,
modules: false,
useBuiltIns: "usage",
targets: {
ie: "11"
}
}
]
]
}),
commonjs()
]
}
];
Here's my dependenices from package.json:
"scripts": {
"start": "rollup -c --compact --watch"
}
"dependencies": {
"core-js": "^3.3.4",
"regenerator-runtime": "^0.13.3"
},
"devDependencies": {
"#babel/core": "^7.6.4",
"#babel/preset-env": "^7.6.3",
"rollup": "^1.26.0",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
}
My output dist/index.js ends up including this assignment for regeneratorRuntime, which wasn't there before I had all 3 of the above rollup plugins:
try {
regeneratorRuntime = runtime;
} catch (accidentalStrictMode) {
// This module should not be running in strict mode, so the above
// assignment should always work unless something is misconfigured. Just
// in case runtime.js accidentally runs in strict mode, we can escape
// strict mode using a global Function call. This could conceivably fail
// if a Content Security Policy forbids using Function, but in that case
// the proper solution is to fix the accidental strict mode problem. If
// you've misconfigured your bundler to force strict mode and applied a
// CSP to forbid Function, and you're not willing to fix either of those
// problems, please detail your unique predicament in a GitHub issue.
Function("r", "regeneratorRuntime = r")(runtime);
}

Babel [karma-babel-preprocessor] Not Converting ES6->ES5 for Karma Tests

We have installed karma, which is using mocha and chai for tests. We are trying to integrate babel straight into karma using karma-babel-preprocessor, to do the converting of our ES6 files into ES5 to be run. Using mocha individually works with babel, i.e. a mocha test command, but we try to use karma instead it doesn't work.
karma.conf.js snippet:
frameworks: ['mocha', 'chai'],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'src/**/*.js': ['babel'],
'test/**/*_spec.js': ['babel']
},
"babelPreprocessor": {
options: {
presets: ['es2015'],
sourceMap: 'inline'
},
filename: function(file) {
return file.originalPath.replace(/\.js$/, '.es5.js');
},
sourceFileName: function(file) {
return file.originalPath;
}
},
// list of files / patterns to load in the browser
files: [
'src/**/*.js',
'test/**/*_spec.js'
],
package.json snippets:
"scripts": {
"test": "./node_modules/karma/bin/karma start karma.conf.js"
},
"babel": {
"presets": ["es2015"]
},
"devDependencies": {
"babel-preset-es2015": "^6.1.18",
"chai": "^3.4.1",
"karma": "^0.13.15",
"karma-babel-preprocessor": "^6.0.1",
"karma-chai": "^0.1.0",
"karma-mocha": "^0.2.1",
"karma-phantomjs-launcher": "^0.2.1",
"phantomjs": "^1.9.18",
"redux": "^3.0.4"
}
We get the following error:
PhantomJS 1.9.8 (Mac OS X 0.0.0) ERROR
ReferenceError: Can't find variable: exports
at Users/alexgurr/BT/FutureVoice/trunk/Portal/server/src/login.es5.js:3
When we evaluate the JS files being loaded, they haven't been converted to ES5, hence the syntax 'export' is still present.
We don't want to use any other frameworks for conversion, ie. webpack, browserify etc.
Thanks!
I've been struggling for the past few hours with the same issue. I'm not sure if your use case is the same as mine, but I finally figured it out.
Code under test src/foo.js:
var foo = "foo value";
export default foo;
Test code tests/foo.spec.js:
import foo from "../src/foo.js";
describe('Foo', function() {
it('should be "foo value"', function() {
expect(foo).toBe('foo value');
});
});
karma.conf.js file before:
{
// other configs
files: [
'src/**/*.js',
'tests/**/*.spec.js',
],
preprocessors: {
'src/**/*.js': ['babel'],
'tests/**/*.spec.js': ['babel'],
},
babelPreprocessor: {
options: {
"presets": ["es2015"]
}
}
}
This yielded the ReferenceError: Can't find variable: exports error you saw.
The fix:
npm install --save-dev babel-plugin-transform-es2015-modules-umd
Add following to karma.conf.js
babelPreprocessor: {
options: {
"presets": ["es2015"],
"plugins": ["transform-es2015-modules-umd"]
}
}
Then the error went away.
Also, note that the following export declarations (which I believe should be correct) do not work.
// exports an object
export default var foo = "something";
// exports undefined
export var bar = "something else";
The problem is that you still didn't bundle/wrap your files to be able to execute CommonJS modules in the browser (because Babel transpile es2015 modules into CommonJS and CJS is default module system for node, not for browsers where Karma run its tests). So your options are:
Use karma-commonjs wrapper (if you want to add all your dependencies manualy)
Use browserify bundler with babelify plugin
Use webpack bundler
I think you still need babel, not just the preset.
npm i babel --save-dev
I have almost the same configuration on one of my project, meaning letting karma pre-process my file on the fly, and the only difference for me is that I have installed babeljs also.
Hope this helps.
Cheers

Categories

Resources